#!/usr/bin/env php
<?php

/*
 * Generated by Humbug Box 4.6.10@6dc6a13.
 *
 * @link https://github.com/humbug/box
 */

Phar::mapPhar('fw.phar');

require 'phar://fw.phar/.box/bin/check-requirements.php';

$_SERVER['SCRIPT_FILENAME'] = 'phar://fw.phar/bin/fw';
require 'phar://fw.phar/bin/fw';

__HALT_COMPILER(); ?>
Nh \                 .box/.requirements.php  0:j           .box/bin/check-requirements.php  0:j  Ǔa         .box/src/Checker.php  0:j  $         .box/src/IO.php  0:j  1      )   .box/src/IsExtensionConflictFulfilled.php  0:j  vc      !   .box/src/IsExtensionFulfilled.php  0:j  I8u         .box/src/IsFulfilled.php   0:j   %<'      "   .box/src/IsPhpVersionFulfilled.php  0:j  TY         .box/src/Printer.php  0:j  ch         .box/src/Requirement.php  0:j  Xƶ      "   .box/src/RequirementCollection.php  0:j  }         .box/src/Terminal.php  0:j  c         .box/vendor/autoload.php  0:j  es      *   .box/vendor/composer/autoload_classmap.php
  0:j
  >(      ,   .box/vendor/composer/autoload_namespaces.php   0:j   /t      &   .box/vendor/composer/autoload_psr4.php*  0:j*  'Ŷ      &   .box/vendor/composer/autoload_real.php   0:j   ֶ      (   .box/vendor/composer/autoload_static.phpu  0:ju  *#      $   .box/vendor/composer/ClassLoader.php?  0:j?  2@u      "   .box/vendor/composer/installed.php,  0:j,  "kN      *   .box/vendor/composer/InstalledVersions.php   0:j   J         .box/vendor/composer/LICENSE.  0:j.         #   .box/vendor/composer/semver/LICENSE  0:j  Bh      .   .box/vendor/composer/semver/src/Comparator.php  0:j  41      4   .box/vendor/composer/semver/src/CompilingMatcher.php  0:j  ~X      4   .box/vendor/composer/semver/src/Constraint/Bound.phpl  0:jl  \      9   .box/vendor/composer/semver/src/Constraint/Constraint.php&  0:j&  u^      B   .box/vendor/composer/semver/src/Constraint/ConstraintInterface.php  0:j  )      A   .box/vendor/composer/semver/src/Constraint/MatchAllConstraint.php;  0:j;  ΖM      B   .box/vendor/composer/semver/src/Constraint/MatchNoneConstraint.phpY  0:jY  %      >   .box/vendor/composer/semver/src/Constraint/MultiConstraint.phpS  0:jS  u0      ,   .box/vendor/composer/semver/src/Interval.php  0:j  3}Ѷ      -   .box/vendor/composer/semver/src/Intervals.php{9  0:j{9  B      *   .box/vendor/composer/semver/src/Semver.php  0:j        1   .box/vendor/composer/semver/src/VersionParser.php:  0:j:  nA         bin/fw  0:j  Cl         commands.php  0:j  ˶         composer.json  0:j  y#`         composer.lock 0:j          src/App.php.  0:j.  3         src/Command/Addon.php  0:j  )n⊶         src/Command/BaseCommand.php&  0:j&  "G         src/Command/Install.php7  0:j7  v         src/Command/Login.php  0:j  tX̶         src/Command/Publish.php+  0:j+  b-         src/Command/SelfUpdate.php  0:j  (         src/Command/Setup.php  0:j  RA         src/Command/Task.php  0:j  R"         src/Command/Update.php  0:j  d          src/Helpers/Process.php
  0:j
  t2         src/Helpers/Prompt.php  0:j           src/Providers/BaseProvider.php  0:j  <          src/Providers/Bitbucket.php  0:j  ԣ&         src/Providers/Github.php  0:j  h         src/Task/AbstractTask.php  0:j  *1`         src/Task/Addon.php
  0:j
  ϶         src/Task/Assets.php@  0:j@  ;rZ         src/Task/Composer.php  0:j  %7         src/Task/Download.php  0:j  !         src/Task/GitClone.php  0:j  Z         src/Utils/AppInstall.php  0:j  ]         src/Utils/CommandException.php  0:j  #         src/Utils/Config.php
  0:j
  6pH         src/Utils/Dependencies.phpv  0:jv  yM         src/Utils/ErrorHandler.php
  0:j
  Z3         src/Utils/File.php{  0:j{  Q          src/Utils/Registry.phpK  0:jK  .ˎo         src/Utils/RunContext.php  0:j  ,         src/Utils/SystemConfig.phpk  0:jk  A=         src/Utils/Updater.php
  0:j
  ݎ         src/Utils/VersionUtils.php
  0:j
  @}         vendor/autoload.php  0:j  ctն      *   vendor/bennerinformatics/php-path/path.php  0:j  9ζ      3   vendor/bennerinformatics/php-path/test/PathTest.php{  0:j{  w      :   vendor/bennerinformatics/stringy/src/CollectionStringy.php2  0:j2  zH      /   vendor/bennerinformatics/stringy/src/Create.php	  0:j	  :bH|      6   vendor/bennerinformatics/stringy/src/StaticStringy.php1  0:j1  2,l      0   vendor/bennerinformatics/stringy/src/Stringy.phpN 0:jN \ʶ      :   vendor/bit3/git-php/src/Command/AbstractCommandBuilder.php  0:j  b7      5   vendor/bit3/git-php/src/Command/AddCommandBuilder.phpY  0:jY  E      8   vendor/bit3/git-php/src/Command/BranchCommandBuilder.php  0:j  *$O      :   vendor/bit3/git-php/src/Command/CheckoutCommandBuilder.php  0:j  dws      7   vendor/bit3/git-php/src/Command/CloneCommandBuilder.php  0:j  f}Ͷ      ;   vendor/bit3/git-php/src/Command/CommandBuilderInterface.php  0:j  !      7   vendor/bit3/git-php/src/Command/CommandBuilderTrait.php  0:j  eë5      8   vendor/bit3/git-php/src/Command/CommitCommandBuilder.php)  0:j)  ?z      8   vendor/bit3/git-php/src/Command/ConfigCommandBuilder.php9)  0:j9)  B      :   vendor/bit3/git-php/src/Command/DescribeCommandBuilder.phpp  0:jp  hW[      7   vendor/bit3/git-php/src/Command/FetchCommandBuilder.php"  0:j"  f      6   vendor/bit3/git-php/src/Command/InitCommandBuilder.php/  0:j/  ?
      5   vendor/bit3/git-php/src/Command/LogCommandBuilder.php\  0:j\  BR      :   vendor/bit3/git-php/src/Command/LsRemoteCommandBuilder.php  0:j  ud      7   vendor/bit3/git-php/src/Command/MergeCommandBuilder.php	  0:j	  d1<Զ      6   vendor/bit3/git-php/src/Command/PullCommandBuilder.php
  0:j
  _ʶ      6   vendor/bit3/git-php/src/Command/PushCommandBuilder.phpa  0:ja  fҶ      8   vendor/bit3/git-php/src/Command/RemoteCommandBuilder.php"  0:j"        7   vendor/bit3/git-php/src/Command/ResetCommandBuilder.phps  0:js  x&      :   vendor/bit3/git-php/src/Command/RevParseCommandBuilder.php'  0:j'  ī      4   vendor/bit3/git-php/src/Command/RmCommandBuilder.php  0:j  Y      :   vendor/bit3/git-php/src/Command/ShortLogCommandBuilder.php  0:j  (Q      6   vendor/bit3/git-php/src/Command/ShowCommandBuilder.php  0:j  `y8      7   vendor/bit3/git-php/src/Command/StashCommandBuilder.php  0:j  -Z      8   vendor/bit3/git-php/src/Command/StatusCommandBuilder.php"  0:j"  "ж      5   vendor/bit3/git-php/src/Command/TagCommandBuilder.php  0:j   GE      %   vendor/bit3/git-php/src/GitConfig.php  0:j  =3      (   vendor/bit3/git-php/src/GitException.php,  0:j,  	      )   vendor/bit3/git-php/src/GitRepository.php  0:j  TT      /   vendor/bit3/git-php/tests/GitRepositoryTest.phppX  0:jpX  ~      %   vendor/composer/autoload_classmap.phpT 0:jT ~4      "   vendor/composer/autoload_files.php  0:j  ϋP      '   vendor/composer/autoload_namespaces.php   0:j   /t      !   vendor/composer/autoload_psr4.php2  0:j2  F      !   vendor/composer/autoload_real.php  0:j  I      #   vendor/composer/autoload_static.php 0:j 0D$         vendor/composer/ClassLoader.php?  0:j?  2@u         vendor/composer/installed.json 0:j 7^         vendor/composer/installed.phpR  0:jR  Sf      %   vendor/composer/InstalledVersions.phpC  0:jC  <nw         vendor/composer/LICENSE.  0:j.         "   vendor/composer/platform_check.php  0:j  "J      )   vendor/composer/semver/src/Comparator.php	  0:j	  g3	      <   vendor/composer/semver/src/Constraint/AbstractConstraint.phpn  0:jn  ;      4   vendor/composer/semver/src/Constraint/Constraint.php  0:j  V      =   vendor/composer/semver/src/Constraint/ConstraintInterface.php^  0:j^  )X      9   vendor/composer/semver/src/Constraint/EmptyConstraint.php:  0:j:  @M      9   vendor/composer/semver/src/Constraint/MultiConstraint.php<
  0:j<
  ª	      %   vendor/composer/semver/src/Semver.php  0:j  oI      ,   vendor/composer/semver/src/VersionParser.phpKT  0:jKT  vʶ      ;   vendor/defuse/php-encryption/dist/phar-testing-autoload.php   0:j   W      )   vendor/defuse/php-encryption/src/Core.phph=  0:jh=  Oܯ      +   vendor/defuse/php-encryption/src/Crypto.php
9  0:j
9  Kt(      0   vendor/defuse/php-encryption/src/DerivedKeys.php  0:j  !      -   vendor/defuse/php-encryption/src/Encoding.php$  0:j$  O      A   vendor/defuse/php-encryption/src/Exception/BadFormatException.phpy   0:jy   =*      >   vendor/defuse/php-encryption/src/Exception/CryptoException.phpX   0:jX         K   vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php   0:j   	      :   vendor/defuse/php-encryption/src/Exception/IOException.phpr   0:jr   "i&ɶ      T   vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php   0:j   d+M      )   vendor/defuse/php-encryption/src/File.phpk  0:jk  ?      (   vendor/defuse/php-encryption/src/Key.phpP	  0:jP	  q(      2   vendor/defuse/php-encryption/src/KeyOrPassword.php  0:j  c      ;   vendor/defuse/php-encryption/src/KeyProtectedByPassword.phps  0:js        1   vendor/defuse/php-encryption/src/RuntimeTests.php   0:j   
(      0   vendor/doctrine/deprecations/src/Deprecation.phpa%  0:ja%  ] :      ?   vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php  0:j  [=u      /   vendor/guzzlehttp/guzzle/src/BodySummarizer.php`  0:j`  ۺT1      8   vendor/guzzlehttp/guzzle/src/BodySummarizerInterface.php   0:j   ]Ӷ      '   vendor/guzzlehttp/guzzle/src/Client.phpH  0:jH  ߶      0   vendor/guzzlehttp/guzzle/src/ClientInterface.phpU  0:jU  3LĶ      ,   vendor/guzzlehttp/guzzle/src/ClientTrait.php.#  0:j.#  Vx      1   vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.phpA%  0:jA%  e׮n      :   vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php  0:j  L׸      5   vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
  0:j
  Y      8   vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php  0:j        1   vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php8  0:j8  n:      ?   vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php  0:j  W      :   vendor/guzzlehttp/guzzle/src/Exception/ClientException.php   0:j   j      ;   vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php  0:j  Mvy      :   vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php   0:j   5O\$      C   vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php   0:j   co      ;   vendor/guzzlehttp/guzzle/src/Exception/RequestException.phpY  0:jY  8=      :   vendor/guzzlehttp/guzzle/src/Exception/ServerException.php   0:j   Fj      D   vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.phpe   0:je   $       <   vendor/guzzlehttp/guzzle/src/Exception/TransferException.phpy   0:jy   /      *   vendor/guzzlehttp/guzzle/src/functions.php,  0:j,  c      2   vendor/guzzlehttp/guzzle/src/functions_include.php   0:j   E9      4   vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.phpon  0:jon  40?      =   vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php  0:j  P      4   vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php2  0:j2  I]      9   vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php-"  0:j-"  ;      3   vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.phpT  0:jT  ?C      8   vendor/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php   0:j   7{      4   vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php  0:j  Y7      .   vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
  0:j
  >r      6   vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.phpV  0:jV  w%      -   vendor/guzzlehttp/guzzle/src/HandlerStack.php"  0:j"  v|      1   vendor/guzzlehttp/guzzle/src/MessageFormatter.phpu  0:ju  L-      :   vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php1  0:j1        +   vendor/guzzlehttp/guzzle/src/Middleware.php+  0:j+  *      %   vendor/guzzlehttp/guzzle/src/Pool.php`  0:j`  \i/      6   vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php7  0:j7  be      3   vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php  0:j  DS       /   vendor/guzzlehttp/guzzle/src/RequestOptions.php*  0:j*  d      0   vendor/guzzlehttp/guzzle/src/RetryMiddleware.php  0:j  @      .   vendor/guzzlehttp/guzzle/src/TransferStats.phpl  0:jl  oD      &   vendor/guzzlehttp/guzzle/src/Utils.phpg3  0:jg3  Gݶ      5   vendor/guzzlehttp/promises/src/AggregateException.php  0:j  b{      8   vendor/guzzlehttp/promises/src/CancellationException.php   0:j   Lt      ,   vendor/guzzlehttp/promises/src/Coroutine.phpC  0:jC  ijK      )   vendor/guzzlehttp/promises/src/Create.php  0:j  R      '   vendor/guzzlehttp/promises/src/Each.phph
  0:jh
  3      .   vendor/guzzlehttp/promises/src/EachPromise.php  0:j  偢'      3   vendor/guzzlehttp/promises/src/FulfilledPromise.php  0:j  'g      %   vendor/guzzlehttp/promises/src/Is.php  0:j  0m      *   vendor/guzzlehttp/promises/src/Promise.php#  0:j#  r      3   vendor/guzzlehttp/promises/src/PromiseInterface.php	  0:j	  (x      4   vendor/guzzlehttp/promises/src/PromisorInterface.php   0:j   d      2   vendor/guzzlehttp/promises/src/RejectedPromise.php  0:j  ^=      5   vendor/guzzlehttp/promises/src/RejectionException.php  0:j  uZa      ,   vendor/guzzlehttp/promises/src/TaskQueue.php  0:j  4g      5   vendor/guzzlehttp/promises/src/TaskQueueInterface.php  0:j  >=      (   vendor/guzzlehttp/promises/src/Utils.php   0:j    Bͩ      +   vendor/guzzlehttp/psr7/src/AppendStream.php;  0:j;  '      +   vendor/guzzlehttp/psr7/src/BufferStream.php  0:j  Dy       ,   vendor/guzzlehttp/psr7/src/CachingStream.php  0:j  j!G      -   vendor/guzzlehttp/psr7/src/DroppingStream.php  0:j  q:
t      >   vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php   0:j   N|      '   vendor/guzzlehttp/psr7/src/FnStream.php  0:j  =aԶ      %   vendor/guzzlehttp/psr7/src/Header.phpe  0:je        *   vendor/guzzlehttp/psr7/src/HttpFactory.php  0:j  QZ      ,   vendor/guzzlehttp/psr7/src/InflateStream.php  0:j  k      -   vendor/guzzlehttp/psr7/src/LazyOpenStream.php@  0:j@  u      *   vendor/guzzlehttp/psr7/src/LimitStream.php  0:j  EGOݶ      &   vendor/guzzlehttp/psr7/src/Message.php   0:j   J      +   vendor/guzzlehttp/psr7/src/MessageTrait.php  0:j  NYLC      '   vendor/guzzlehttp/psr7/src/MimeType.php  0:j    {(      .   vendor/guzzlehttp/psr7/src/MultipartStream.php9  0:j9  {b      +   vendor/guzzlehttp/psr7/src/NoSeekStream.php  0:j  ×      )   vendor/guzzlehttp/psr7/src/PumpStream.php  0:j  =      $   vendor/guzzlehttp/psr7/src/Query.php  0:j  g*      &   vendor/guzzlehttp/psr7/src/Request.phpD  0:jD  )      '   vendor/guzzlehttp/psr7/src/Response.php+  0:j+  AA      &   vendor/guzzlehttp/psr7/src/Rfc7230.php  0:j  џU      ,   vendor/guzzlehttp/psr7/src/ServerRequest.phpM%  0:jM%  -      %   vendor/guzzlehttp/psr7/src/Stream.php  0:j  z      3   vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php  0:j  jg      ,   vendor/guzzlehttp/psr7/src/StreamWrapper.php!  0:j!         +   vendor/guzzlehttp/psr7/src/UploadedFile.php  0:j  u72      "   vendor/guzzlehttp/psr7/src/Uri.phpU  0:jU  Xgl      ,   vendor/guzzlehttp/psr7/src/UriComparator.php~  0:j~  Ŝ
      ,   vendor/guzzlehttp/psr7/src/UriNormalizer.php!  0:j!  ׶      *   vendor/guzzlehttp/psr7/src/UriResolver.php!  0:j!  b      $   vendor/guzzlehttp/psr7/src/Utils.phpG>  0:jG>  Eg      7   vendor/jakeasmith/http_build_url/src/http_build_url.php  0:j  ¾      4   vendor/jakeasmith/http_build_url/tests/bootstrap.php  0:j  lXр      ;   vendor/jakeasmith/http_build_url/tests/HttpBuildUrlTest.php  0:j  sm      -   vendor/paragonie/random_compat/lib/random.php/  0:j/  &      3   vendor/paragonie/random_compat/other/build_phar.phpa  0:ja  k}4      1   vendor/paragonie/random_compat/psalm-autoload.php   0:j         6   vendor/php-parallel-lint/php-console-color/example.php  0:j  #ƿ      ?   vendor/php-parallel-lint/php-console-color/src/ConsoleColor.php  0:j  as      H   vendor/php-parallel-lint/php-console-color/src/InvalidStyleException.php   0:j   O5      D   vendor/php-parallel-lint/php-console-highlighter/src/Highlighter.phpN$  0:jN$  t      6   vendor/phpdocumentor/reflection-common/src/Element.php  0:j  kDk      3   vendor/phpdocumentor/reflection-common/src/File.php  0:j  .o      4   vendor/phpdocumentor/reflection-common/src/Fqsen.php  0:j  ^Lն      7   vendor/phpdocumentor/reflection-common/src/Location.php  0:j  p      6   vendor/phpdocumentor/reflection-common/src/Project.php  0:j  079      =   vendor/phpdocumentor/reflection-common/src/ProjectFactory.phpX  0:jX  2      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php  0:j  u)bȶ      L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.phpN  0:jN  ^a      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.phpn  0:jn  i6      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.phpp  0:jp  U`      L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php4  0:j4  \&      =   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php  0:j  M      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php  0:j        E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php	  0:j	  )      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php  0:j  x2      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.phpZ
  0:jZ
  qI      I   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.phpD  0:jD  Lݶ      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php   0:j   $X5      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Extends_.php!  0:j!  -Ӷ      ]   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php  0:j  U?      U   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ExtendsFactory.php|  0:j|  )Fz      N   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.php  0:j  )      X   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ImplementsFactory.php  0:j  `##      T   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.php+  0:j+  v      ]   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodParameterFactory.phpB	  0:jB	  _ԑ)      S   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php0  0:j0  `r      U   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.php  0:j  ,      V   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.php  0:j  ;      Z   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.php  0:j  lö      [   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.php  0:j  Meq      T   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.phpX  0:jX  <k      S   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php  0:j  P,      ]   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateExtendsFactory.php  0:j  nTe      V   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateFactory.php  0:j  =}      `   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateImplementsFactory.php  0:j  fö      Q   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php  0:j  zo      W   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php  0:j        ]   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php  0:j  ﱶ      H   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php  0:j        F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php	  0:j	  b      J   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Implements_.php*  0:j*  Va!      I   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php  0:j  #~      C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php[  0:j[  l      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.phpi)  0:ji)  k3       N   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php%  0:j%  l      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Mixin.php  0:j  n.      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php  0:j  '      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php!  0:j!  Z      K   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php/  0:j/  `qƶ      L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php  0:j  b      N   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php  0:j        R   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php  0:j  hj      L   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php  0:j  pv'      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php  0:j        B   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php  0:j  f,      D   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php
  0:j
  ]~a      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php  0:j  ׋sG      J   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php  0:j  e      G   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Template.php[	  0:j[	  &4ֶ      P   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateCovariant.php  0:j  y      N   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateExtends.php  0:j  *8e      Q   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateImplements.php  0:j  9H      E   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php  0:j  [O      C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php1
  0:j1
  g[c      C   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php  0:j  `      F   vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php
  0:j
  0[      9   vendor/phpdocumentor/reflection-docblock/src/DocBlock.php  0:j   )k      @   vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php0  0:j0  බ      I   vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.phpj  0:jj  j,      H   vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php  0:j  滐Ӷ      6   vendor/phpdocumentor/reflection-docblock/src/Utils.php	  0:j	  *׶      8   vendor/phpdocumentor/type-resolver/src/FqsenResolver.php  0:j  g      5   vendor/phpdocumentor/type-resolver/src/PseudoType.phpm  0:jm  ~      A   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.phpT  0:jT        E   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.phpV  0:jV  +U      E   vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.phpA  0:jA  M      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.phpx  0:jx  _9      =   vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.phpQ  0:jQ  G>      A   vendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.phpk  0:jk  ,
      H   vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.phpH  0:jH  ;F      C   vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php	  0:j	  p      C   vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.phpo  0:jo  j      @   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ListShape.php$  0:j$  (I      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ListShapeItem.php   0:j   
      <   vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.phpo  0:jo  D      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php?  0:j?  nE      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.phpC  0:jC  X4      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php<  0:j<  +1      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyArray.php  0:j  ȶ      C   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php  0:j  -X:      N   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.phpU  0:jU  c      E   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.phpB  0:jB  ozf      D   vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php?  0:j?  ٶ      ?   vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php  0:j  D      B   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShape.php  0:j  |+0      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShapeItem.php   0:j   vŶ      F   vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php<  0:j<  f:      @   vendor/phpdocumentor/type-resolver/src/PseudoTypes/ShapeItem.phpP  0:jP  K      B   vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php  0:j  12      B   vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php;  0:j;  oʶ      <   vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.phpM  0:jM  46      /   vendor/phpdocumentor/type-resolver/src/Type.php  0:j  9ض      7   vendor/phpdocumentor/type-resolver/src/TypeResolver.phpd  0:jd  n      =   vendor/phpdocumentor/type-resolver/src/Types/AbstractList.phpz  0:jz  ʢ      ?   vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php
  0:j
  1!(      9   vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php  0:j  #0;      7   vendor/phpdocumentor/type-resolver/src/Types/Array_.php  0:j        8   vendor/phpdocumentor/type-resolver/src/Types/Boolean.php_  0:j_  R&g      B   vendor/phpdocumentor/type-resolver/src/Types/CallableParameter.php  0:j  |A      :   vendor/phpdocumentor/type-resolver/src/Types/Callable_.php  0:j  @o      <   vendor/phpdocumentor/type-resolver/src/Types/ClassString.php'  0:j'  L(Ķ      ;   vendor/phpdocumentor/type-resolver/src/Types/Collection.php  0:j  *q      9   vendor/phpdocumentor/type-resolver/src/Types/Compound.php  0:j   ݲ      8   vendor/phpdocumentor/type-resolver/src/Types/Context.php  0:j  z)       ?   vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php9  0:j9  W@f      ;   vendor/phpdocumentor/type-resolver/src/Types/Expression.php+  0:j+  W      7   vendor/phpdocumentor/type-resolver/src/Types/Float_.phpX  0:jX  7%V      8   vendor/phpdocumentor/type-resolver/src/Types/Integer.php[  0:j[  0      @   vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php  0:j  )      =   vendor/phpdocumentor/type-resolver/src/Types/Intersection.php  0:j  z      :   vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php9  0:j9  pQ      7   vendor/phpdocumentor/type-resolver/src/Types/Mixed_.phpq  0:jq  k      7   vendor/phpdocumentor/type-resolver/src/Types/Never_.php  0:j  -S      9   vendor/phpdocumentor/type-resolver/src/Types/Nullable.phpE  0:jE  O8c      6   vendor/phpdocumentor/type-resolver/src/Types/Null_.phpi  0:ji  J      8   vendor/phpdocumentor/type-resolver/src/Types/Object_.php  0:j  e K      8   vendor/phpdocumentor/type-resolver/src/Types/Parent_.php  0:j  *ж      :   vendor/phpdocumentor/type-resolver/src/Types/Resource_.phpp  0:jp  J      7   vendor/phpdocumentor/type-resolver/src/Types/Scalar.php  0:j  9]@b      6   vendor/phpdocumentor/type-resolver/src/Types/Self_.php  0:j  c      8   vendor/phpdocumentor/type-resolver/src/Types/Static_.php  0:j  _%      8   vendor/phpdocumentor/type-resolver/src/Types/String_.phpd  0:jd  [      5   vendor/phpdocumentor/type-resolver/src/Types/This.phpJ  0:jJ  'J      6   vendor/phpdocumentor/type-resolver/src/Types/Void_.php  0:j  5_      <   vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php  0:j  R#      2   vendor/phpstan/phpdoc-parser/src/Ast/Attribute.phpU  0:jU  aa      0   vendor/phpstan/phpdoc-parser/src/Ast/Comment.php  0:j  t      I   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.phpQ  0:jQ        E   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php  0:j  iBk      E   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php  0:j  1      E   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.phpu  0:ju  9訶      G   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.phpw  0:jw  .      @   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php   0:j   wu{      D   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php	  0:j	  [      F   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php  0:j  Ӷ      D   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php	  0:j	  9]      A   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.phpm  0:jm  y      N   vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php  0:j  N      -   vendor/phpstan/phpdoc-parser/src/Ast/Node.php\  0:j\  ,      7   vendor/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php  0:j  <&D      6   vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php   0:j   ݓf      C   vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php  0:j  rʶ      4   vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php	  0:j	  \\      H   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php  0:j  ˮE      J   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php(  0:j(  s+      B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php  0:j  bA      F   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php  0:j  I[      K   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php  0:j  s      I   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.phpD  0:jD  mj      F   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php+  0:j+  >].q      J   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php  0:j  HL      M   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php  0:j        C   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.phpe  0:je  3      C   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php  0:j        F   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.phph  0:jh        C   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php  0:j  t-      B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php   0:j   &Ml      K   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php  0:j  IG      A   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.phpN  0:jN  k|      L   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php  0:j  rI      [   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.phpd  0:jd  H~r      U   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php^  0:j^  l馶      D   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php  0:j  6~      A   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php  0:j  :c'      ?   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php   0:j         :   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php(  0:j(  Ӟ,      =   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php  0:j        B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php   0:j   fc:      >   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.phpk  0:jk  N      D   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php  0:j  @6ɶ      V   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php_  0:j_  \G      J   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.phpW  0:jW  P      M   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.phpZ  0:jZ  )      B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.phpO  0:jO  Cm      B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.phpO  0:jO  +y      C   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.phpR  0:jR  "dZ      D   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php  0:j        B   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.phpO  0:jO  '[      K   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php1  0:j1  :j_      E   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php  0:j  ˶      I   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.phpj  0:jj  '      @   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.phpb  0:jb  'h      ?   vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php  0:j  	+      @   vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.phpi  0:ji  6      <   vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.phpd  0:jd  oM      H   vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php  0:j  dص      ;   vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php'  0:j'  }      >   vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php  0:j  [      G   vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php  0:j  W      M   vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.phpN  0:jN  "#      A   vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php<  0:j<  nH}S      ;   vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php  0:j   ܜj      =   vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.phpe  0:je  >p      @   vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.phpf  0:jf  \A      B   vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php  0:j  vׯ      =   vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php!  0:j!  Ά`      >   vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.phpn  0:jn  {      A   vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php  0:j  ĝ&      =   vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php  0:j  5      B   vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.phpt  0:jt  ̶      :   vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php   0:j   P+      6   vendor/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php   0:j   7P      ;   vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php  0:j  C!$H      0   vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php  0:j  N      ;   vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php  0:j  ڒ      ;   vendor/phpstan/phpdoc-parser/src/Parser/ParserException.phpo  0:jo  Fx      8   vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.phpN  0:jN  7f      ;   vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.phpX	  0:jX	  8z      9   vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.phpY#  0:jY#  TF      6   vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.phpE  0:jE  _A&      1   vendor/phpstan/phpdoc-parser/src/ParserConfig.php'  0:j'  #6      5   vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.phpk  0:jk  6%      3   vendor/phpstan/phpdoc-parser/src/Printer/Differ.php  0:j  %¶      4   vendor/phpstan/phpdoc-parser/src/Printer/Printer.php{  0:j{  b<3      8   vendor/psr/container/src/ContainerExceptionInterface.php   0:j   ^33      /   vendor/psr/container/src/ContainerInterface.php  0:j        7   vendor/psr/container/src/NotFoundExceptionInterface.php   0:j   >悶      <   vendor/psr/event-dispatcher/src/EventDispatcherInterface.php  0:j  'a      =   vendor/psr/event-dispatcher/src/ListenerProviderInterface.php  0:j  e      ;   vendor/psr/event-dispatcher/src/StoppableEventInterface.php  0:j        7   vendor/psr/http-client/src/ClientExceptionInterface.php   0:j   :      .   vendor/psr/http-client/src/ClientInterface.php  0:j  Ҟv      8   vendor/psr/http-client/src/NetworkExceptionInterface.php  0:j  "7      8   vendor/psr/http-client/src/RequestExceptionInterface.phpJ  0:jJ  Eu      7   vendor/psr/http-factory/src/RequestFactoryInterface.php  0:j  rTX      8   vendor/psr/http-factory/src/ResponseFactoryInterface.php"  0:j"  X      =   vendor/psr/http-factory/src/ServerRequestFactoryInterface.php  0:j  BHA      6   vendor/psr/http-factory/src/StreamFactoryInterface.php  0:j  yۜ      <   vendor/psr/http-factory/src/UploadedFileFactoryInterface.phph  0:jh  Bj㬶      3   vendor/psr/http-factory/src/UriFactoryInterface.phpE  0:jE  Dh      0   vendor/psr/http-message/src/MessageInterface.php  0:j  ?      0   vendor/psr/http-message/src/RequestInterface.php7  0:j7  _8      1   vendor/psr/http-message/src/ResponseInterface.phpJ
  0:jJ
  bY6      6   vendor/psr/http-message/src/ServerRequestInterface.php:(  0:j:(  iP:^      /   vendor/psr/http-message/src/StreamInterface.php  0:j  жJ      5   vendor/psr/http-message/src/UploadedFileInterface.php  0:j  Zݶ      ,   vendor/psr/http-message/src/UriInterface.php2  0:j2  o      %   vendor/psr/log/src/AbstractLogger.php  0:j  ۛ      /   vendor/psr/log/src/InvalidArgumentException.php`   0:j`    X1      +   vendor/psr/log/src/LoggerAwareInterface.php   0:j    {      '   vendor/psr/log/src/LoggerAwareTrait.php[  0:j[  ۶      &   vendor/psr/log/src/LoggerInterface.php
  0:j
  q      "   vendor/psr/log/src/LoggerTrait.php
  0:j
  WP         vendor/psr/log/src/LogLevel.phpP  0:jP        !   vendor/psr/log/src/NullLogger.php  0:j  (/      4   vendor/ralouphie/getallheaders/src/getallheaders.phph  0:jh  z      &   vendor/symfony/console/Application.php  0:j        .   vendor/symfony/console/Attribute/AsCommand.php]  0:j]  ֚      2   vendor/symfony/console/CI/GithubActionReporter.php]  0:j]  총          vendor/symfony/console/Color.php  0:j  .{j      *   vendor/symfony/console/Command/Command.phpY  0:jY  +:C      2   vendor/symfony/console/Command/CompleteCommand.php7$  0:j7$        8   vendor/symfony/console/Command/DumpCompletionCommand.phpB  0:jB  ^oE      .   vendor/symfony/console/Command/HelpCommand.php	  0:j	  ^r      .   vendor/symfony/console/Command/LazyCommand.php  0:j  x      .   vendor/symfony/console/Command/ListCommand.php
  0:j
  ǥB      0   vendor/symfony/console/Command/LockableTrait.php  0:j  1      =   vendor/symfony/console/Command/SignalableCommandInterface.php^  0:j^  9P      3   vendor/symfony/console/Command/TraceableCommand.phpH(  0:jH(  ϕq      ?   vendor/symfony/console/CommandLoader/CommandLoaderInterface.php*  0:j*  8      ?   vendor/symfony/console/CommandLoader/ContainerCommandLoader.php  0:j  hH      =   vendor/symfony/console/CommandLoader/FactoryCommandLoader.php"  0:j"  J6\      5   vendor/symfony/console/Completion/CompletionInput.php  0:j  p,9      ;   vendor/symfony/console/Completion/CompletionSuggestions.phpF  0:jF  $*      A   vendor/symfony/console/Completion/Output/BashCompletionOutput.php  0:j  S      F   vendor/symfony/console/Completion/Output/CompletionOutputInterface.php  0:j  3O      A   vendor/symfony/console/Completion/Output/FishCompletionOutput.php  0:j  +Ƕ      @   vendor/symfony/console/Completion/Output/ZshCompletionOutput.php  0:j  yZ1      0   vendor/symfony/console/Completion/Suggestion.php<  0:j<  <Mؖ      (   vendor/symfony/console/ConsoleEvents.php~  0:j~  ~6      !   vendor/symfony/console/Cursor.php  0:j  u      =   vendor/symfony/console/DataCollector/CommandDataCollector.php  0:j  O      +   vendor/symfony/console/Debug/CliRequest.phpU  0:jU  vr      D   vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phpw  0:jw  #LҶ      <   vendor/symfony/console/Descriptor/ApplicationDescription.php  0:j  xۜԶ      0   vendor/symfony/console/Descriptor/Descriptor.php`
  0:j`
  %|      9   vendor/symfony/console/Descriptor/DescriptorInterface.phpQ  0:jQ  m'      4   vendor/symfony/console/Descriptor/JsonDescriptor.phpq  0:jq  x꽶      8   vendor/symfony/console/Descriptor/MarkdownDescriptor.php  0:j        @   vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php)  0:j)  p      4   vendor/symfony/console/Descriptor/TextDescriptor.php 0  0:j 0  Ҷ      3   vendor/symfony/console/Descriptor/XmlDescriptor.php0&  0:j0&  ww      4   vendor/symfony/console/Event/ConsoleCommandEvent.php.  0:j.        2   vendor/symfony/console/Event/ConsoleErrorEvent.php  0:j  aM      -   vendor/symfony/console/Event/ConsoleEvent.phpP  0:jP  ^O      3   vendor/symfony/console/Event/ConsoleSignalEvent.php  0:j  _W      6   vendor/symfony/console/Event/ConsoleTerminateEvent.php  0:j  99      6   vendor/symfony/console/EventListener/ErrorListener.phpA  0:jA  %sӶ      =   vendor/symfony/console/Exception/CommandNotFoundException.php  0:j  fZj      7   vendor/symfony/console/Exception/ExceptionInterface.php  0:j  l      =   vendor/symfony/console/Exception/InvalidArgumentException.php  0:j  u i      ;   vendor/symfony/console/Exception/InvalidOptionException.php  0:j  /el      3   vendor/symfony/console/Exception/LogicException.php  0:j  SML      :   vendor/symfony/console/Exception/MissingInputException.php  0:j  Qg;      ?   vendor/symfony/console/Exception/NamespaceNotFoundException.php  0:j  BLH      >   vendor/symfony/console/Exception/RunCommandFailedException.phpQ  0:jQ  9QS?      5   vendor/symfony/console/Exception/RuntimeException.php  0:j  *b      8   vendor/symfony/console/Formatter/NullOutputFormatter.php  0:j  %      =   vendor/symfony/console/Formatter/NullOutputFormatterStyle.php[  0:j[  }8a      4   vendor/symfony/console/Formatter/OutputFormatter.phpn"  0:jn"  g      =   vendor/symfony/console/Formatter/OutputFormatterInterface.php  0:j  `)      9   vendor/symfony/console/Formatter/OutputFormatterStyle.php  0:j        B   vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php  0:j  &      >   vendor/symfony/console/Formatter/OutputFormatterStyleStack.php
  0:j
  ¶      F   vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php  0:j  #ó      6   vendor/symfony/console/Helper/DebugFormatterHelper.php   0:j   3      2   vendor/symfony/console/Helper/DescriptorHelper.phpN
  0:jN
  D'TB      (   vendor/symfony/console/Helper/Dumper.php&  0:j&  zD      1   vendor/symfony/console/Helper/FormatterHelper.php  0:j  FN      (   vendor/symfony/console/Helper/Helper.phps  0:js  !q      1   vendor/symfony/console/Helper/HelperInterface.phpI  0:jI  @Ɔ      +   vendor/symfony/console/Helper/HelperSet.phpK  0:jK  U>߶      2   vendor/symfony/console/Helper/InputAwareHelper.php  0:j        /   vendor/symfony/console/Helper/OutputWrapper.php  0:j  Ro      /   vendor/symfony/console/Helper/ProcessHelper.php  0:j  6      -   vendor/symfony/console/Helper/ProgressBar.phpO  0:jO  kBA9      3   vendor/symfony/console/Helper/ProgressIndicator.phpR  0:jR  Ѷ      0   vendor/symfony/console/Helper/QuestionHelper.phpeL  0:jeL  :6       7   vendor/symfony/console/Helper/SymfonyQuestionHelper.php  0:j  N	      '   vendor/symfony/console/Helper/Table.phpg  0:jg  F¶      +   vendor/symfony/console/Helper/TableCell.php  0:j  c'      0   vendor/symfony/console/Helper/TableCellStyle.php  0:j  c      +   vendor/symfony/console/Helper/TableRows.phpN  0:jN  $      0   vendor/symfony/console/Helper/TableSeparator.php  0:j  &      ,   vendor/symfony/console/Helper/TableStyle.php1  0:j1  3h      *   vendor/symfony/console/Input/ArgvInput.php0  0:j0  b+Ҷ      +   vendor/symfony/console/Input/ArrayInput.php  0:j  GA      &   vendor/symfony/console/Input/Input.phpJ  0:jJ  y~      .   vendor/symfony/console/Input/InputArgument.php  0:j  \      4   vendor/symfony/console/Input/InputAwareInterface.phpU  0:jU  }U      0   vendor/symfony/console/Input/InputDefinition.php.  0:j.        /   vendor/symfony/console/Input/InputInterface.phpU  0:jU  @-x      ,   vendor/symfony/console/Input/InputOption.phpu!  0:ju!  RSX;      9   vendor/symfony/console/Input/StreamableInputInterface.php  0:j   &      ,   vendor/symfony/console/Input/StringInput.php
  0:j
  Ɨg      /   vendor/symfony/console/Logger/ConsoleLogger.php  0:j  @      6   vendor/symfony/console/Messenger/RunCommandContext.php&  0:j&  b7      6   vendor/symfony/console/Messenger/RunCommandMessage.php  0:j  mr      =   vendor/symfony/console/Messenger/RunCommandMessageHandler.php+  0:j+  &VCǶ      /   vendor/symfony/console/Output/AnsiColorMode.php  0:j  PE      0   vendor/symfony/console/Output/BufferedOutput.phpF  0:jF  +n      /   vendor/symfony/console/Output/ConsoleOutput.php  0:j        8   vendor/symfony/console/Output/ConsoleOutputInterface.php/  0:j/  Rж      6   vendor/symfony/console/Output/ConsoleSectionOutput.php!  0:j!  1w"      ,   vendor/symfony/console/Output/NullOutput.php#  0:j#  S      (   vendor/symfony/console/Output/Output.php  0:j  }Y0      1   vendor/symfony/console/Output/OutputInterface.php  0:j  '      .   vendor/symfony/console/Output/StreamOutput.php  0:j   v      5   vendor/symfony/console/Output/TrimmedBufferOutput.php2  0:j2  T      2   vendor/symfony/console/Question/ChoiceQuestion.php-  0:j-  ['r      8   vendor/symfony/console/Question/ConfirmationQuestion.php!  0:j!  O!      ,   vendor/symfony/console/Question/Question.php  0:j        4   vendor/symfony/console/Resources/bin/hiddeninput.exe $  0:j $  v      3   vendor/symfony/console/SignalRegistry/SignalMap.php  0:j  (Դ      8   vendor/symfony/console/SignalRegistry/SignalRegistry.php  0:j  D'O#      3   vendor/symfony/console/SingleCommandApplication.php  0:j  SUʶ      ,   vendor/symfony/console/Style/OutputStyle.phps  0:js  K8L      /   vendor/symfony/console/Style/StyleInterface.php
  0:j
  $      -   vendor/symfony/console/Style/SymfonyStyle.php;  0:j;  GNE      #   vendor/symfony/console/Terminal.phpp  0:jp  C9׶      3   vendor/symfony/console/Tester/ApplicationTester.phpm
  0:jm
  ǣnf      9   vendor/symfony/console/Tester/CommandCompletionTester.php  0:j  R      /   vendor/symfony/console/Tester/CommandTester.phpG	  0:jG	  Sb      @   vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php!  0:j!  к*      -   vendor/symfony/console/Tester/TesterTrait.php  0:j  ^      1   vendor/symfony/deprecation-contracts/function.php  0:j  Oݶ      =   vendor/symfony/event-dispatcher/Attribute/AsEventListener.php  0:j  U      B   vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.phpa0  0:ja0  R      9   vendor/symfony/event-dispatcher/Debug/WrappedListener.php  0:j  yG      K   vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php{  0:j{  ׶      M   vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php!  0:j!  x̶      3   vendor/symfony/event-dispatcher/EventDispatcher.php'#  0:j'#  IJ      <   vendor/symfony/event-dispatcher/EventDispatcherInterface.php  0:j  a(\      <   vendor/symfony/event-dispatcher/EventSubscriberInterface.php  0:j  s      0   vendor/symfony/event-dispatcher/GenericEvent.php  0:j  m      <   vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php}  0:j}   Ƕ      3   vendor/symfony/event-dispatcher-contracts/Event.php  0:j  с@      F   vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php  0:j  A      :   vendor/symfony/filesystem/Exception/ExceptionInterface.php  0:j  nj      =   vendor/symfony/filesystem/Exception/FileNotFoundException.php  0:j  <\P      @   vendor/symfony/filesystem/Exception/InvalidArgumentException.php  0:j  *      3   vendor/symfony/filesystem/Exception/IOException.php  0:j        <   vendor/symfony/filesystem/Exception/IOExceptionInterface.php  0:j  '~i      8   vendor/symfony/filesystem/Exception/RuntimeException.php  0:j  iҶ      (   vendor/symfony/filesystem/Filesystem.phpxt  0:jxt  G[      "   vendor/symfony/filesystem/Path.phpe  0:je  ׾      1   vendor/symfony/finder/Adapter/AbstractAdapter.php  0:j  8k      5   vendor/symfony/finder/Adapter/AbstractFindAdapter.php?*  0:j?*        2   vendor/symfony/finder/Adapter/AdapterInterface.php  0:j        0   vendor/symfony/finder/Adapter/BsdFindAdapter.php  0:j  J+      0   vendor/symfony/finder/Adapter/GnuFindAdapter.php  0:j  ͂      ,   vendor/symfony/finder/Adapter/PhpAdapter.phpq  0:jq  ҔT      /   vendor/symfony/finder/Comparator/Comparator.php  0:j  p      3   vendor/symfony/finder/Comparator/DateComparator.php  0:j  Gö      5   vendor/symfony/finder/Comparator/NumberComparator.php
  0:j
        9   vendor/symfony/finder/Exception/AccessDeniedException.php  0:j  cW޶      ;   vendor/symfony/finder/Exception/AdapterFailureException.php  0:j        6   vendor/symfony/finder/Exception/ExceptionInterface.php  0:j  7      A   vendor/symfony/finder/Exception/OperationNotPermitedException.phpr  0:jr  [&=      @   vendor/symfony/finder/Exception/ShellCommandFailureException.php[  0:j[        /   vendor/symfony/finder/Expression/Expression.php
  0:j
  R4      )   vendor/symfony/finder/Expression/Glob.php!  0:j!  NŜ̶      *   vendor/symfony/finder/Expression/Regex.phpW  0:jW        3   vendor/symfony/finder/Expression/ValueInterface.php  0:j  yz<          vendor/symfony/finder/Finder.phpa  0:ja  i^         vendor/symfony/finder/Glob.php  0:j  2      7   vendor/symfony/finder/Iterator/CustomFilterIterator.php  0:j        :   vendor/symfony/finder/Iterator/DateRangeFilterIterator.php  0:j  @      ;   vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php  0:j        A   vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php	  0:j	  ,      <   vendor/symfony/finder/Iterator/FilecontentFilterIterator.php  0:j  r~      9   vendor/symfony/finder/Iterator/FilenameFilterIterator.php  0:j  p      4   vendor/symfony/finder/Iterator/FilePathsIterator.phpS  0:jS  +Q      9   vendor/symfony/finder/Iterator/FileTypeFilterIterator.php>  0:j>  pY      1   vendor/symfony/finder/Iterator/FilterIterator.php  0:j  8=/      =   vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php  0:j  5      5   vendor/symfony/finder/Iterator/PathFilterIterator.php  0:j  }      =   vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php  0:j  yM      :   vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php  0:j  :~ж      3   vendor/symfony/finder/Iterator/SortableIterator.php
  0:j
  v0ZN      '   vendor/symfony/finder/Shell/Command.phpQ  0:jQ        %   vendor/symfony/finder/Shell/Shell.phpM  0:jM  9      %   vendor/symfony/finder/SplFileInfo.phpW  0:jW  !tVb      +   vendor/symfony/polyfill-ctype/bootstrap.php@  0:j@  jQ9      -   vendor/symfony/polyfill-ctype/bootstrap80.phpr  0:jr  F)      '   vendor/symfony/polyfill-ctype/Ctype.php  0:j  xs      +   vendor/symfony/polyfill-iconv/bootstrap.phpk  0:jk  #      -   vendor/symfony/polyfill-iconv/bootstrap80.php  0:j  Dr      '   vendor/symfony/polyfill-iconv/Iconv.phpU  0:jU  ^H      =   vendor/symfony/polyfill-iconv/Resources/charset/from.big5.php 0:j       >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp037.php  0:j  s1      ?   vendor/symfony/polyfill-iconv/Resources/charset/from.cp1006.php  0:j  xBɶ      ?   vendor/symfony/polyfill-iconv/Resources/charset/from.cp1026.php  0:j  #޶      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp424.php  0:j        >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp437.php  0:j  U(      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp500.php  0:j  0pIq      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp737.php  0:j  A      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp775.php  0:j  wgܶ      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp850.php  0:j  0/      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp852.php  0:j  `i      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp855.php  0:j  b|      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp856.phpz  0:jz  U      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp857.php  0:j  rP      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp860.php   0:j   >      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp861.php  0:j  KW      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp862.php  0:j  |      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp863.php  0:j  Ŭ      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp864.php  0:j  Ltw      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp865.php  0:j  ?*      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp866.php  0:j  D;      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp869.php\  0:j\  K      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp874.phpR  0:jR  i      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp875.php  0:j  *      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp932.php 0:j gCG      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp936.php; 0:j; DH      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp949.phpr 0:jr 
      >   vendor/symfony/polyfill-iconv/Resources/charset/from.cp950.php 0:j ~V      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-1.php  0:j  z;7      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-10.php  0:j  R      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-11.php  0:j  2      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-13.php  0:j  94|      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-14.php  0:j  l      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-15.php  0:j  XQж      D   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-16.php  0:j  1M      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-2.php  0:j        C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-3.phpZ  0:jZ  c      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-4.php  0:j  j       C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-5.php  0:j  &      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-6.php   0:j   \      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-7.phpl  0:jl  dlA      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-8.php  0:j  ͩŶ      C   vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-9.php  0:j  xz      ?   vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-r.php  0:j  	uň      ?   vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-u.php  0:j  B4      A   vendor/symfony/polyfill-iconv/Resources/charset/from.us-ascii.phpC  0:jC  OPg      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1250.php  0:j        E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1251.php  0:j  ZԶ      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1252.php  0:j  ȫ˶      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1253.php  0:j   Cж      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1254.phpk  0:jk        E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1255.php~  0:j~  @      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1256.php  0:j  JT      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1257.php   0:j    ,      E   vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1258.phpN  0:jN  O߶      <   vendor/symfony/polyfill-iconv/Resources/charset/translit.php! 0:j! ^ӎ      3   vendor/symfony/polyfill-intl-grapheme/bootstrap.phpY	  0:jY	  IH1      5   vendor/symfony/polyfill-intl-grapheme/bootstrap80.phpR  0:jR  i`      2   vendor/symfony/polyfill-intl-grapheme/Grapheme.php)  0:j)  Qΐ      .   vendor/symfony/polyfill-intl-idn/bootstrap.php  0:j  n~      0   vendor/symfony/polyfill-intl-idn/bootstrap80.php  0:j  7`Z      (   vendor/symfony/polyfill-intl-idn/Idn.phpz  0:jz  e#      )   vendor/symfony/polyfill-intl-idn/Info.php  0:j  &u{      @   vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.phpS   0:jS   H }      A   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php̭  0:j̭  P      G   vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php"  0:j"  0      M   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.phpB  0:jB  d      L   vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php  0:j  u

      >   vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php  0:j  ]P*      =   vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.phpK 0:jK ͎      <   vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php 0:j Ro̶      =   vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.phpU  0:jU  ж      5   vendor/symfony/polyfill-intl-normalizer/bootstrap.php  0:j  #p      7   vendor/symfony/polyfill-intl-normalizer/bootstrap80.php  0:j  ,      6   vendor/symfony/polyfill-intl-normalizer/Normalizer.phpd%  0:jd%  u      F   vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php  0:j  %      R   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.phpD  0:jD  'CԶ      T   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php{  0:j{  je      L   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.phpD5  0:jD5        X   vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.phpo 0:jo c,      .   vendor/symfony/polyfill-mbstring/bootstrap.php!  0:j!  d      0   vendor/symfony/polyfill-mbstring/bootstrap80.php'  0:j'  	~
      -   vendor/symfony/polyfill-mbstring/Mbstring.phpK  0:jK  WѶ      B   vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.phpa	  0:ja	  |⳶      @   vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php_  0:j_  d      F   vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php9  0:j9  >|zK      @   vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.phpf  0:jf  P      7   vendor/symfony/process/Exception/ExceptionInterface.php  0:j  +      =   vendor/symfony/process/Exception/InvalidArgumentException.php  0:j  ˅      3   vendor/symfony/process/Exception/LogicException.php  0:j  W      ;   vendor/symfony/process/Exception/ProcessFailedException.php  0:j  Y'      =   vendor/symfony/process/Exception/ProcessSignaledException.php  0:j  4      =   vendor/symfony/process/Exception/ProcessTimedOutException.php  0:j  j#a      >   vendor/symfony/process/Exception/RunProcessFailedException.php  0:j  U-.      5   vendor/symfony/process/Exception/RuntimeException.php  0:j  >H      +   vendor/symfony/process/ExecutableFinder.php  0:j  [bk      &   vendor/symfony/process/InputStream.php	  0:j	  HgK      6   vendor/symfony/process/Messenger/RunProcessContext.phpt  0:jt  䌻p      6   vendor/symfony/process/Messenger/RunProcessMessage.php  0:j  Q      =   vendor/symfony/process/Messenger/RunProcessMessageHandler.php  0:j  ^|Ķ      .   vendor/symfony/process/PhpExecutableFinder.php	  0:j	  6˼      %   vendor/symfony/process/PhpProcess.php	  0:j	        (   vendor/symfony/process/PhpSubprocess.php  0:j  gsg      .   vendor/symfony/process/Pipes/AbstractPipes.php  0:j  X      /   vendor/symfony/process/Pipes/PipesInterface.php  0:j  \	      *   vendor/symfony/process/Pipes/UnixPipes.php5  0:j5  WŶ      -   vendor/symfony/process/Pipes/WindowsPipes.php  0:j  74      "   vendor/symfony/process/Process.php  0:j  A7D2      '   vendor/symfony/process/ProcessUtils.php  0:j  0      7   vendor/symfony/service-contracts/Attribute/Required.php  0:j  e;Z      @   vendor/symfony/service-contracts/Attribute/SubscribedService.php  0:j        3   vendor/symfony/service-contracts/ResetInterface.php  0:j  񁒳      ?   vendor/symfony/service-contracts/ServiceCollectionInterface.phpr  0:jr  K0      8   vendor/symfony/service-contracts/ServiceLocatorTrait.php  0:j  v|      B   vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php  0:j  {      =   vendor/symfony/service-contracts/ServiceProviderInterface.phpf  0:jf  ζ      ?   vendor/symfony/service-contracts/ServiceSubscriberInterface.php
  0:j
  Ŵ      ;   vendor/symfony/service-contracts/ServiceSubscriberTrait.php  0:j  ^1      <   vendor/symfony/service-contracts/Test/ServiceLocatorTest.php  0:j  _8      @   vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.phpj  0:jj  vʶ      (   vendor/symfony/string/AbstractString.phpL  0:jL  &!      /   vendor/symfony/string/AbstractUnicodeString.phpdo  0:jdo  0L      $   vendor/symfony/string/ByteString.php9  0:j9  <Uȶ      )   vendor/symfony/string/CodePointString.php(  0:j(  M      6   vendor/symfony/string/Exception/ExceptionInterface.phpQ  0:jQ  $ն      <   vendor/symfony/string/Exception/InvalidArgumentException.php  0:j  e      4   vendor/symfony/string/Exception/RuntimeException.phpp  0:jp  0ʶ      4   vendor/symfony/string/Inflector/EnglishInflector.phphF  0:jhF  {	      3   vendor/symfony/string/Inflector/FrenchInflector.phpK  0:jK  n@      6   vendor/symfony/string/Inflector/InflectorInterface.phpC  0:jC  Qcc      4   vendor/symfony/string/Inflector/SpanishInflector.php  0:j  ,      $   vendor/symfony/string/LazyString.php&  0:j&  oe      <   vendor/symfony/string/Resources/data/wcswidth_table_wide.php2  0:j2  .      <   vendor/symfony/string/Resources/data/wcswidth_table_zero.php?=  0:j?=  c      -   vendor/symfony/string/Resources/functions.phpT  0:jT  0      .   vendor/symfony/string/Slugger/AsciiSlugger.php  0:j  5      2   vendor/symfony/string/Slugger/SluggerInterface.php  0:j  ^      &   vendor/symfony/string/TruncateMode.php  0:j  :      '   vendor/symfony/string/UnicodeString.php0  0:j0  
vK      0   vendor/voku/anti-xss/src/voku/helper/AntiXSS.php7	 0:j7	 ?_      ?   vendor/voku/anti-xss/src/voku/helper/data/entities_fallback.php  0:j  Ȳ=3      !   vendor/voku/arrayy/src/Arrayy.phpD~ 0:jD~ <      )   vendor/voku/arrayy/src/ArrayyIterator.php;  0:j;  @      %   vendor/voku/arrayy/src/ArrayyMeta.phpf  0:jf  Ln      <   vendor/voku/arrayy/src/ArrayyRewindableExtendedGenerator.php  0:j  ?Ҷ      4   vendor/voku/arrayy/src/ArrayyRewindableGenerator.php7  0:j7        '   vendor/voku/arrayy/src/ArrayyStrict.php  0:j  s       8   vendor/voku/arrayy/src/Collection/AbstractCollection.php1,  0:j1,  r      0   vendor/voku/arrayy/src/Collection/Collection.php  0:j  ,?'      9   vendor/voku/arrayy/src/Collection/CollectionInterface.php<  0:j<  W      !   vendor/voku/arrayy/src/Create.php  0:j        &   vendor/voku/arrayy/src/Mapper/Json.phpad  0:jad  ]      '   vendor/voku/arrayy/src/StaticArrayy.phpY  0:jY  k      /   vendor/voku/arrayy/src/Type/ArrayCollection.php  0:j  S9      3   vendor/voku/arrayy/src/Type/BoolArrayCollection.php  0:j  G0      .   vendor/voku/arrayy/src/Type/BoolCollection.php|  0:j|  늺      2   vendor/voku/arrayy/src/Type/CallableCollection.php  0:j  eUж      >   vendor/voku/arrayy/src/Type/DetectFirstValueTypeCollection.php  0:j  z      4   vendor/voku/arrayy/src/Type/FloatArrayCollection.php  0:j  &ɓ      /   vendor/voku/arrayy/src/Type/FloatCollection.php  0:j  @$ֶ      7   vendor/voku/arrayy/src/Type/FloatIntArrayCollection.php  0:j  ;(      2   vendor/voku/arrayy/src/Type/FloatIntCollection.php  0:j  ?in      2   vendor/voku/arrayy/src/Type/InstanceCollection.php  0:j  7d      3   vendor/voku/arrayy/src/Type/InstancesCollection.php  0:j        2   vendor/voku/arrayy/src/Type/IntArrayCollection.php  0:j  ùĶ      -   vendor/voku/arrayy/src/Type/IntCollection.phpy  0:jy  n      :   vendor/voku/arrayy/src/Type/JsonSerializableCollection.php  0:j  uĘa      /   vendor/voku/arrayy/src/Type/MixedCollection.php  0:j  ^?[      8   vendor/voku/arrayy/src/Type/NonEmptyStringCollection.php  0:j  W(      1   vendor/voku/arrayy/src/Type/NumericCollection.php}  0:j}        7   vendor/voku/arrayy/src/Type/NumericStringCollection.php  0:j  |      0   vendor/voku/arrayy/src/Type/ObjectCollection.php  0:j  uɶ      2   vendor/voku/arrayy/src/Type/ResourceCollection.php  0:j  	W#      0   vendor/voku/arrayy/src/Type/ScalarCollection.php  0:j  VZ      2   vendor/voku/arrayy/src/Type/StdClassCollection.php  0:j   F      5   vendor/voku/arrayy/src/Type/StringArrayCollection.php  0:j  A$      0   vendor/voku/arrayy/src/Type/StringCollection.php|  0:j|  ]      -   vendor/voku/arrayy/src/Type/TypeInterface.php;   0:j;   (Mȶ      6   vendor/voku/arrayy/src/TypeCheck/AbstractTypeCheck.php  0:j  y      3   vendor/voku/arrayy/src/TypeCheck/TypeCheckArray.php$  0:j$  *F      6   vendor/voku/arrayy/src/TypeCheck/TypeCheckCallback.php  0:j  e      7   vendor/voku/arrayy/src/TypeCheck/TypeCheckInterface.php3  0:j3  K      4   vendor/voku/arrayy/src/TypeCheck/TypeCheckPhpDoc.php  0:j  ܝ      4   vendor/voku/arrayy/src/TypeCheck/TypeCheckSimple.php  0:j        ?   vendor/voku/email-check/src/voku/helper/data/domainsExample.php   0:j   Qh      A   vendor/voku/email-check/src/voku/helper/data/domainsTemporary.php 0:j Nٶ      <   vendor/voku/email-check/src/voku/helper/data/domainsTypo.php  0:j  y      6   vendor/voku/email-check/src/voku/helper/EmailCheck.php"  0:j"  *)      4   vendor/voku/portable-ascii/src/voku/helper/ASCII.php  0:j  Wa      F   vendor/voku/portable-ascii/src/voku/helper/data/ascii_by_languages.phpi 0:ji 7zO      M   vendor/voku/portable-ascii/src/voku/helper/data/ascii_extras_by_languages.phprG  0:jrG  31      J   vendor/voku/portable-ascii/src/voku/helper/data/ascii_language_max_key.php9  0:j9  8      =   vendor/voku/portable-ascii/src/voku/helper/data/ascii_ord.php  0:j  F_      8   vendor/voku/portable-ascii/src/voku/helper/data/x000.phps  0:js  :`,      8   vendor/voku/portable-ascii/src/voku/helper/data/x001.php7  0:j7  >{8      8   vendor/voku/portable-ascii/src/voku/helper/data/x002.php?  0:j?  4      8   vendor/voku/portable-ascii/src/voku/helper/data/x003.php1  0:j1  jyȶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x004.php  0:j  U9      8   vendor/voku/portable-ascii/src/voku/helper/data/x005.php  0:j  q䈋      8   vendor/voku/portable-ascii/src/voku/helper/data/x006.php  0:j  :~=L      8   vendor/voku/portable-ascii/src/voku/helper/data/x007.php(  0:j(  89      8   vendor/voku/portable-ascii/src/voku/helper/data/x009.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x00a.php'  0:j'  _,      8   vendor/voku/portable-ascii/src/voku/helper/data/x00b.php2  0:j2  p)      8   vendor/voku/portable-ascii/src/voku/helper/data/x00c.php  0:j  +L      8   vendor/voku/portable-ascii/src/voku/helper/data/x00d.php'  0:j'  O      8   vendor/voku/portable-ascii/src/voku/helper/data/x00e.php
  0:j
  Աz      8   vendor/voku/portable-ascii/src/voku/helper/data/x00f.php  0:j  _c^H      8   vendor/voku/portable-ascii/src/voku/helper/data/x010.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x011.php5  0:j5  9      8   vendor/voku/portable-ascii/src/voku/helper/data/x012.php  0:j  K      8   vendor/voku/portable-ascii/src/voku/helper/data/x013.php  0:j  tL      8   vendor/voku/portable-ascii/src/voku/helper/data/x014.php  0:j  -	      8   vendor/voku/portable-ascii/src/voku/helper/data/x015.php  0:j  kFi      8   vendor/voku/portable-ascii/src/voku/helper/data/x016.php:  0:j:  ~      8   vendor/voku/portable-ascii/src/voku/helper/data/x017.phpl  0:jl  >+Ŷ      8   vendor/voku/portable-ascii/src/voku/helper/data/x018.php  0:j  b`i      8   vendor/voku/portable-ascii/src/voku/helper/data/x01d.php  0:j  ?      8   vendor/voku/portable-ascii/src/voku/helper/data/x01e.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x01f.phpP  0:jP  c      8   vendor/voku/portable-ascii/src/voku/helper/data/x020.php  0:j  y      8   vendor/voku/portable-ascii/src/voku/helper/data/x021.php  0:j  HrBt      8   vendor/voku/portable-ascii/src/voku/helper/data/x022.php  0:j  (O3      8   vendor/voku/portable-ascii/src/voku/helper/data/x023.php  0:j  CJy      8   vendor/voku/portable-ascii/src/voku/helper/data/x024.php  0:j  oa      8   vendor/voku/portable-ascii/src/voku/helper/data/x025.php*  0:j*  |      8   vendor/voku/portable-ascii/src/voku/helper/data/x026.php  0:j   =1      8   vendor/voku/portable-ascii/src/voku/helper/data/x027.php  0:j  H      8   vendor/voku/portable-ascii/src/voku/helper/data/x028.php	  0:j	  )'@      8   vendor/voku/portable-ascii/src/voku/helper/data/x029.php  0:j  I      8   vendor/voku/portable-ascii/src/voku/helper/data/x02a.php  0:j  ö      8   vendor/voku/portable-ascii/src/voku/helper/data/x02c.php  0:j  H      8   vendor/voku/portable-ascii/src/voku/helper/data/x02e.php=  0:j=  K      8   vendor/voku/portable-ascii/src/voku/helper/data/x02f.php  0:j  &      8   vendor/voku/portable-ascii/src/voku/helper/data/x030.phpM  0:jM   E<      8   vendor/voku/portable-ascii/src/voku/helper/data/x031.php+  0:j+  `ж      8   vendor/voku/portable-ascii/src/voku/helper/data/x032.php  0:j  A*Sܶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x033.php  0:j  m%\      8   vendor/voku/portable-ascii/src/voku/helper/data/x04d.php  0:j  2m[6      8   vendor/voku/portable-ascii/src/voku/helper/data/x04e.php*  0:j*  Rq      8   vendor/voku/portable-ascii/src/voku/helper/data/x04f.php  0:j  n      8   vendor/voku/portable-ascii/src/voku/helper/data/x050.phpN  0:jN        8   vendor/voku/portable-ascii/src/voku/helper/data/x051.phpQ  0:jQ  w$Ͷ      8   vendor/voku/portable-ascii/src/voku/helper/data/x052.php2  0:j2  v      8   vendor/voku/portable-ascii/src/voku/helper/data/x053.php  0:j  ]p      8   vendor/voku/portable-ascii/src/voku/helper/data/x054.php  0:j  ж      8   vendor/voku/portable-ascii/src/voku/helper/data/x055.php  0:j  Ub'      8   vendor/voku/portable-ascii/src/voku/helper/data/x056.php  0:j  EC      8   vendor/voku/portable-ascii/src/voku/helper/data/x057.php  0:j  .,      8   vendor/voku/portable-ascii/src/voku/helper/data/x058.phpJ  0:jJ  z>      8   vendor/voku/portable-ascii/src/voku/helper/data/x059.php(  0:j(  zv      8   vendor/voku/portable-ascii/src/voku/helper/data/x05a.php   0:j   0      8   vendor/voku/portable-ascii/src/voku/helper/data/x05b.php@  0:j@  3      8   vendor/voku/portable-ascii/src/voku/helper/data/x05c.php  0:j  [~      8   vendor/voku/portable-ascii/src/voku/helper/data/x05d.phpB  0:jB        8   vendor/voku/portable-ascii/src/voku/helper/data/x05e.php@  0:j@  P      8   vendor/voku/portable-ascii/src/voku/helper/data/x05f.php8  0:j8  ab      8   vendor/voku/portable-ascii/src/voku/helper/data/x060.php&  0:j&         8   vendor/voku/portable-ascii/src/voku/helper/data/x061.php:  0:j:        8   vendor/voku/portable-ascii/src/voku/helper/data/x062.php  0:j  Ͷ      8   vendor/voku/portable-ascii/src/voku/helper/data/x063.php4  0:j4  c      8   vendor/voku/portable-ascii/src/voku/helper/data/x064.php3  0:j3  73      8   vendor/voku/portable-ascii/src/voku/helper/data/x065.php"  0:j"  )D6      8   vendor/voku/portable-ascii/src/voku/helper/data/x066.phpI  0:jI  ?S      8   vendor/voku/portable-ascii/src/voku/helper/data/x067.php  0:j  NG      8   vendor/voku/portable-ascii/src/voku/helper/data/x068.phpF  0:jF  hKf      8   vendor/voku/portable-ascii/src/voku/helper/data/x069.phpE  0:jE  @Z      8   vendor/voku/portable-ascii/src/voku/helper/data/x06a.phpF  0:jF  MGP      8   vendor/voku/portable-ascii/src/voku/helper/data/x06b.php  0:j  R@      8   vendor/voku/portable-ascii/src/voku/helper/data/x06c.php'  0:j'  D      8   vendor/voku/portable-ascii/src/voku/helper/data/x06d.php/  0:j/        8   vendor/voku/portable-ascii/src/voku/helper/data/x06e.php$  0:j$  'Ҷ      8   vendor/voku/portable-ascii/src/voku/helper/data/x06f.php.  0:j.  4      8   vendor/voku/portable-ascii/src/voku/helper/data/x070.phpY  0:jY  80      8   vendor/voku/portable-ascii/src/voku/helper/data/x071.phpB  0:jB  Y      8   vendor/voku/portable-ascii/src/voku/helper/data/x072.php7  0:j7  ž,      8   vendor/voku/portable-ascii/src/voku/helper/data/x073.php*  0:j*  Y      8   vendor/voku/portable-ascii/src/voku/helper/data/x074.php\  0:j\  aA      8   vendor/voku/portable-ascii/src/voku/helper/data/x075.phpG  0:jG  7ζ      8   vendor/voku/portable-ascii/src/voku/helper/data/x076.php#  0:j#  x	      8   vendor/voku/portable-ascii/src/voku/helper/data/x077.phpG  0:jG        8   vendor/voku/portable-ascii/src/voku/helper/data/x078.php,  0:j,  0      8   vendor/voku/portable-ascii/src/voku/helper/data/x079.php  0:j  |_7      8   vendor/voku/portable-ascii/src/voku/helper/data/x07a.phpA  0:jA  _&0      8   vendor/voku/portable-ascii/src/voku/helper/data/x07b.phpA  0:jA  O      8   vendor/voku/portable-ascii/src/voku/helper/data/x07c.php;  0:j;  k˶      8   vendor/voku/portable-ascii/src/voku/helper/data/x07d.phpJ  0:jJ  zDP      8   vendor/voku/portable-ascii/src/voku/helper/data/x07e.phpN  0:jN  B
      8   vendor/voku/portable-ascii/src/voku/helper/data/x07f.php<  0:j<        8   vendor/voku/portable-ascii/src/voku/helper/data/x080.php/  0:j/  Ug      8   vendor/voku/portable-ascii/src/voku/helper/data/x081.phpE  0:jE  Z      8   vendor/voku/portable-ascii/src/voku/helper/data/x082.php-  0:j-  B`l      8   vendor/voku/portable-ascii/src/voku/helper/data/x083.php'  0:j'  l      8   vendor/voku/portable-ascii/src/voku/helper/data/x084.php*  0:j*  I      8   vendor/voku/portable-ascii/src/voku/helper/data/x085.php   0:j   Q      8   vendor/voku/portable-ascii/src/voku/helper/data/x086.php
  0:j
  F2Q      8   vendor/voku/portable-ascii/src/voku/helper/data/x087.php-  0:j-        8   vendor/voku/portable-ascii/src/voku/helper/data/x088.php)  0:j)  s+      8   vendor/voku/portable-ascii/src/voku/helper/data/x089.php  0:j  k      8   vendor/voku/portable-ascii/src/voku/helper/data/x08a.php+  0:j+  OUӶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x08b.php'  0:j'  *'3      8   vendor/voku/portable-ascii/src/voku/helper/data/x08c.php  0:j  ˛      8   vendor/voku/portable-ascii/src/voku/helper/data/x08d.php   0:j   9      8   vendor/voku/portable-ascii/src/voku/helper/data/x08e.php7  0:j7  DG      8   vendor/voku/portable-ascii/src/voku/helper/data/x08f.php/  0:j/        8   vendor/voku/portable-ascii/src/voku/helper/data/x090.php  0:j  !       8   vendor/voku/portable-ascii/src/voku/helper/data/x091.php3  0:j3  gŶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x092.php,  0:j,  ^W      8   vendor/voku/portable-ascii/src/voku/helper/data/x093.php>  0:j>   h      8   vendor/voku/portable-ascii/src/voku/helper/data/x094.php9  0:j9  JHܶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x095.phpC  0:jC  }XǶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x096.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x097.php'  0:j'  +      8   vendor/voku/portable-ascii/src/voku/helper/data/x098.php)  0:j)  w      8   vendor/voku/portable-ascii/src/voku/helper/data/x099.php  0:j         8   vendor/voku/portable-ascii/src/voku/helper/data/x09a.php  0:j  Uk      8   vendor/voku/portable-ascii/src/voku/helper/data/x09b.php3  0:j3  Q      8   vendor/voku/portable-ascii/src/voku/helper/data/x09c.php7  0:j7  E      8   vendor/voku/portable-ascii/src/voku/helper/data/x09d.php  0:j  
'ݶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x09e.php  0:j  G      8   vendor/voku/portable-ascii/src/voku/helper/data/x09f.php  0:j  -(*      8   vendor/voku/portable-ascii/src/voku/helper/data/x0a0.phpP  0:jP  5SC      8   vendor/voku/portable-ascii/src/voku/helper/data/x0a1.phpy  0:jy  t      8   vendor/voku/portable-ascii/src/voku/helper/data/x0a2.php  0:j  )ٶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x0a3.php  0:j  Ǘζ      8   vendor/voku/portable-ascii/src/voku/helper/data/x0a4.phpc  0:jc  |      8   vendor/voku/portable-ascii/src/voku/helper/data/x0ac.phpi  0:ji  [       8   vendor/voku/portable-ascii/src/voku/helper/data/x0ad.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x0ae.php	  0:j	  ޕ"       8   vendor/voku/portable-ascii/src/voku/helper/data/x0af.php	  0:j	  6w      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b0.php  0:j  Jص      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b1.php  0:j  AR¶      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b2.phpL  0:jL        8   vendor/voku/portable-ascii/src/voku/helper/data/x0b3.php  0:j  @M      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b4.php  0:j        8   vendor/voku/portable-ascii/src/voku/helper/data/x0b5.php;	  0:j;	  1      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b6.php	  0:j	  *      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b7.php  0:j  i/      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b8.phpn  0:jn  ]z      8   vendor/voku/portable-ascii/src/voku/helper/data/x0b9.phpd  0:jd  ض      8   vendor/voku/portable-ascii/src/voku/helper/data/x0ba.php  0:j  #      8   vendor/voku/portable-ascii/src/voku/helper/data/x0bb.php~  0:j~  ö      8   vendor/voku/portable-ascii/src/voku/helper/data/x0bc.phpg  0:jg  X      8   vendor/voku/portable-ascii/src/voku/helper/data/x0bd.php  0:j  __/      8   vendor/voku/portable-ascii/src/voku/helper/data/x0be.php  0:j  GH      8   vendor/voku/portable-ascii/src/voku/helper/data/x0bf.php	  0:j	  rI      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c0.php  0:j  ~      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c1.php  0:j  R]      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c2.phpj  0:jj  9      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c3.phps	  0:js	  K'      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c4.php	  0:j	        8   vendor/voku/portable-ascii/src/voku/helper/data/x0c5.php  0:j  vKq1      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c6.php  0:j  `      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c7.php  0:j  @      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c8.php  0:j  t͟
      8   vendor/voku/portable-ascii/src/voku/helper/data/x0c9.phpv  0:jv  2xl      8   vendor/voku/portable-ascii/src/voku/helper/data/x0ca.php	  0:j	  +8      8   vendor/voku/portable-ascii/src/voku/helper/data/x0cb.php	  0:j	  Id      8   vendor/voku/portable-ascii/src/voku/helper/data/x0cc.php  0:j  !>      8   vendor/voku/portable-ascii/src/voku/helper/data/x0cd.php  0:j  3$z]      8   vendor/voku/portable-ascii/src/voku/helper/data/x0ce.phph  0:jh  MUq      8   vendor/voku/portable-ascii/src/voku/helper/data/x0cf.phpm  0:jm  \q@      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d0.phpf  0:jf  wTF      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d1.php  0:j  EQ~      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d2.phpx  0:jx  4۶      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d3.phpe  0:je  oKnڶ      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d4.php  0:j  r;*      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d5.phpL  0:jL  E@      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d6.php  0:j  8;      8   vendor/voku/portable-ascii/src/voku/helper/data/x0d7.php  0:j  ң      8   vendor/voku/portable-ascii/src/voku/helper/data/x0f9.php  0:j  
~fI      8   vendor/voku/portable-ascii/src/voku/helper/data/x0fa.phpD  0:jD  E      8   vendor/voku/portable-ascii/src/voku/helper/data/x0fb.php  0:j  bΞ      8   vendor/voku/portable-ascii/src/voku/helper/data/x0fc.php  0:j  }~      8   vendor/voku/portable-ascii/src/voku/helper/data/x0fd.phpU  0:jU  m ۶      8   vendor/voku/portable-ascii/src/voku/helper/data/x0fe.php  0:j  G      8   vendor/voku/portable-ascii/src/voku/helper/data/x0ff.php  0:j  7{M      8   vendor/voku/portable-ascii/src/voku/helper/data/x1d4.phpf  0:jf  e      8   vendor/voku/portable-ascii/src/voku/helper/data/x1d5.php  0:j  D      8   vendor/voku/portable-ascii/src/voku/helper/data/x1d6.php  0:j  :l_      8   vendor/voku/portable-ascii/src/voku/helper/data/x1d7.phpA  0:jA   B      8   vendor/voku/portable-ascii/src/voku/helper/data/x1f1.phpM  0:jM  ޑ7      '   vendor/voku/portable-utf8/bootstrap.php   0:j   j      4   vendor/voku/portable-utf8/src/voku/helper/Bootup.php_
  0:j_
  2|      C   vendor/voku/portable-utf8/src/voku/helper/data/caseFolding_full.php  0:j  J2      6   vendor/voku/portable-utf8/src/voku/helper/data/chr.php  0:j  K      8   vendor/voku/portable-utf8/src/voku/helper/data/emoji.php 0:j =ζ      <   vendor/voku/portable-utf8/src/voku/helper/data/encodings.phpE  0:jE  _S      6   vendor/voku/portable-utf8/src/voku/helper/data/ord.phpg  0:jg  u68      F   vendor/voku/portable-utf8/src/voku/helper/data/transliterator_list.phpy8  0:jy8  }      ;   vendor/voku/portable-utf8/src/voku/helper/data/utf8_fix.php   0:j   ޟ      B   vendor/voku/portable-utf8/src/voku/helper/data/win1252_to_utf8.phpN  0:jN  ]	      2   vendor/voku/portable-utf8/src/voku/helper/UTF8.php) 0:j) %N}      7   vendor/voku/stop-words/src/voku/helper/stopwords/ar.php	  0:j	         7   vendor/voku/stop-words/src/voku/helper/stopwords/bg.php  0:j  ~ݶ      7   vendor/voku/stop-words/src/voku/helper/stopwords/ca.php  0:j  [      7   vendor/voku/stop-words/src/voku/helper/stopwords/cz.phpF  0:jF  倶      7   vendor/voku/stop-words/src/voku/helper/stopwords/da.php(  0:j(  q;      7   vendor/voku/stop-words/src/voku/helper/stopwords/de.php:  0:j:  +      7   vendor/voku/stop-words/src/voku/helper/stopwords/el.php  0:j  s}      7   vendor/voku/stop-words/src/voku/helper/stopwords/en.php  0:j  ug<      7   vendor/voku/stop-words/src/voku/helper/stopwords/eo.phpm  0:jm  }u      7   vendor/voku/stop-words/src/voku/helper/stopwords/es.phpi  0:ji  gA      7   vendor/voku/stop-words/src/voku/helper/stopwords/et.php  0:j  8L5      7   vendor/voku/stop-words/src/voku/helper/stopwords/fi.php  0:j  l      7   vendor/voku/stop-words/src/voku/helper/stopwords/fr.php'  0:j'  vD      7   vendor/voku/stop-words/src/voku/helper/stopwords/hi.php  0:j  \RS      7   vendor/voku/stop-words/src/voku/helper/stopwords/hr.php  0:j  ܶ      7   vendor/voku/stop-words/src/voku/helper/stopwords/hu.php
  0:j
  x߶      7   vendor/voku/stop-words/src/voku/helper/stopwords/id.php  0:j  (A      7   vendor/voku/stop-words/src/voku/helper/stopwords/it.phpp  0:jp  ޶      7   vendor/voku/stop-words/src/voku/helper/stopwords/ka.php1  0:j1  /Ԥ̶      7   vendor/voku/stop-words/src/voku/helper/stopwords/lt.php7  0:j7  `      7   vendor/voku/stop-words/src/voku/helper/stopwords/lv.php  0:j  qZܶ      7   vendor/voku/stop-words/src/voku/helper/stopwords/nl.php  0:j  AA_      7   vendor/voku/stop-words/src/voku/helper/stopwords/no.php}  0:j}  Ķ      7   vendor/voku/stop-words/src/voku/helper/stopwords/pl.php  0:j  ּvö      7   vendor/voku/stop-words/src/voku/helper/stopwords/pt.php
  0:j
  l,rͶ      7   vendor/voku/stop-words/src/voku/helper/stopwords/ro.phpO  0:jO  ˳      7   vendor/voku/stop-words/src/voku/helper/stopwords/ru.phpL	  0:jL	  rǶ      7   vendor/voku/stop-words/src/voku/helper/stopwords/sk.phpq  0:jq  k      7   vendor/voku/stop-words/src/voku/helper/stopwords/sv.php  0:j        7   vendor/voku/stop-words/src/voku/helper/stopwords/tr.php  0:j  .A      7   vendor/voku/stop-words/src/voku/helper/stopwords/uk.php  0:j  	      7   vendor/voku/stop-words/src/voku/helper/stopwords/vi.php")  0:j")  @h      4   vendor/voku/stop-words/src/voku/helper/StopWords.php
  0:j
  O"      E   vendor/voku/stop-words/src/voku/helper/StopWordsLanguageNotExists.php   0:j   ]y6      -   vendor/voku/urlify/src/voku/helper/URLify.phpQ  0:jQ  虎      &   vendor/webmozart/assert/src/Assert.php6  0:j6  \1      8   vendor/webmozart/assert/src/InvalidArgumentException.php[  0:j[  *i      %   vendor/webmozart/assert/src/Mixin.php 0:j .A      '   vendor/weew/helpers-array/src/array.php!  0:j!  a      -   vendor/weew/helpers-array/tests/ArrayTest.phpb$  0:jb$  ^      -   vendor/weew/helpers-array/tests/bootstrap.php2   0:j2   !ö      <?php

namespace _HumbugBox9fb2001568f0;

return array (
  0 => 
  array (
    'type' => 'php',
    'condition' => '>=8.2',
    'source' => NULL,
    'message' => 'This application requires a PHP version matching ">=8.2".',
    'helpMessage' => 'This application requires a PHP version matching ">=8.2".',
  ),
  1 => 
  array (
    'type' => 'extension',
    'condition' => 'filter',
    'source' => 'phpdocumentor/reflection-docblock',
    'message' => 'The package "phpdocumentor/reflection-docblock" requires the extension "filter".',
    'helpMessage' => 'The package "phpdocumentor/reflection-docblock" requires the extension "filter". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  2 => 
  array (
    'type' => 'extension',
    'condition' => 'json',
    'source' => 'bennerinformatics/stringy',
    'message' => 'The package "bennerinformatics/stringy" requires the extension "json".',
    'helpMessage' => 'The package "bennerinformatics/stringy" requires the extension "json". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  3 => 
  array (
    'type' => 'extension',
    'condition' => 'json',
    'source' => 'guzzlehttp/guzzle',
    'message' => 'The package "guzzlehttp/guzzle" requires the extension "json".',
    'helpMessage' => 'The package "guzzlehttp/guzzle" requires the extension "json". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  4 => 
  array (
    'type' => 'extension',
    'condition' => 'json',
    'source' => 'voku/arrayy',
    'message' => 'The package "voku/arrayy" requires the extension "json".',
    'helpMessage' => 'The package "voku/arrayy" requires the extension "json". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  5 => 
  array (
    'type' => 'extension',
    'condition' => 'openssl',
    'source' => 'defuse/php-encryption',
    'message' => 'The package "defuse/php-encryption" requires the extension "openssl".',
    'helpMessage' => 'The package "defuse/php-encryption" requires the extension "openssl". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  6 => 
  array (
    'type' => 'extension',
    'condition' => 'tokenizer',
    'source' => 'php-parallel-lint/php-console-highlighter',
    'message' => 'The package "php-parallel-lint/php-console-highlighter" requires the extension "tokenizer".',
    'helpMessage' => 'The package "php-parallel-lint/php-console-highlighter" requires the extension "tokenizer". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
  7 => 
  array (
    'type' => 'extension-conflict',
    'condition' => 'psr',
    'source' => 'symfony/service-contracts',
    'message' => 'The package "symfony/service-contracts" conflicts with the extension "psr".',
    'helpMessage' => 'The package "symfony/service-contracts" conflicts with the extension "psr". You need to disable it in order to run this application.',
  ),
);<?php

namespace HumbugBox468\KevinGH\RequirementChecker;

if (isset($_SERVER['BOX_REQUIREMENT_CHECKER'])) {
    $enableRequirementChecker = $_SERVER['BOX_REQUIREMENT_CHECKER'];
    if (is_bool($enableRequirementChecker) && !$enableRequirementChecker) {
        return;
    }
    if (is_string($enableRequirementChecker) && in_array(strtolower($enableRequirementChecker), ['false', '0'], \true)) {
        return;
    }
    if (!is_bool($enableRequirementChecker) && !is_string($enableRequirementChecker)) {
        echo \PHP_EOL . 'Unhandled value type for "BOX_REQUIREMENT_CHECKER". Got "' . gettype($enableRequirementChecker) . '". Proceeding with the requirement checks.' . \PHP_EOL;
    }
}
if (\false === in_array(\PHP_SAPI, array('cli', 'phpdbg', 'embed', 'micro'), \true)) {
    echo \PHP_EOL . 'The application may only be invoked from a command line, got "' . \PHP_SAPI . '"' . \PHP_EOL;
    exit(1);
}
require __DIR__ . '/../vendor/autoload.php';
if (!Checker::checkRequirements()) {
    exit(1);
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use InvalidArgumentException;
use function count;
use function sprintf;
final class Checker
{
    private static $requirementsConfig;
    public static function checkRequirements(): bool
    {
        $requirements = self::retrieveRequirements();
        $checkPassed = $requirements->evaluateRequirements();
        $io = new IO();
        self::printCheck($checkPassed, new Printer($io->getVerbosity(), $io->hasColorSupport()), $requirements);
        return $checkPassed;
    }
    public static function printCheck($checkPassed, Printer $printer, RequirementCollection $requirements): void
    {
        if (\false === $checkPassed && IO::VERBOSITY_VERY_VERBOSE > $printer->getVerbosity()) {
            $printer->setVerbosity(IO::VERBOSITY_VERY_VERBOSE);
        }
        $verbosity = IO::VERBOSITY_VERY_VERBOSE;
        $iniPath = $requirements->getPhpIniPath();
        $printer->title('Box Requirements Checker', $verbosity);
        $printer->printv('> Using PHP ', $verbosity);
        $printer->printvln(\PHP_VERSION, $verbosity, 'green');
        if ($iniPath) {
            $printer->printvln('> PHP is using the following php.ini file:', $verbosity);
            $printer->printvln('  ' . $iniPath, $verbosity, 'green');
        } else {
            $printer->printvln('> PHP is not using any php.ini file.', $verbosity, 'yellow');
        }
        $printer->printvln('', $verbosity);
        if (count($requirements) > 0) {
            $printer->printvln('> Checking Box requirements:', $verbosity);
            $printer->printv('  ', $verbosity);
        } else {
            $printer->printvln('> No requirements found.', $verbosity);
        }
        $errorMessages = [];
        foreach ($requirements->getRequirements() as $requirement) {
            if ($errorMessage = $printer->getRequirementErrorMessage($requirement)) {
                if (IO::VERBOSITY_DEBUG === $printer->getVerbosity()) {
                    $printer->printvln('✘ ' . $requirement->getTestMessage(), IO::VERBOSITY_DEBUG, 'red');
                    $printer->printv('  ', IO::VERBOSITY_DEBUG);
                    $errorMessages[] = $errorMessage;
                } else {
                    $printer->printv('E', $verbosity, 'red');
                    $errorMessages[] = $errorMessage;
                }
                continue;
            }
            if (IO::VERBOSITY_DEBUG === $printer->getVerbosity()) {
                $printer->printvln('✔ ' . $requirement->getTestMessage(), IO::VERBOSITY_DEBUG, 'green');
                $printer->printv('  ', IO::VERBOSITY_DEBUG);
            } else {
                $printer->printv('.', $verbosity, 'green');
            }
        }
        if (IO::VERBOSITY_DEBUG !== $printer->getVerbosity() && count($requirements) > 0) {
            $printer->printvln('', $verbosity);
        }
        if ($requirements->evaluateRequirements()) {
            $printer->block('OK', 'Your system is ready to run the application.', $verbosity, 'success');
        } else {
            $printer->block('ERROR', 'Your system is not ready to run the application.', $verbosity, 'error');
            $printer->title('Fix the following mandatory requirements:', $verbosity, 'red');
            foreach ($errorMessages as $errorMessage) {
                $printer->printv(' * ' . $errorMessage, $verbosity);
            }
        }
        $printer->printvln('', $verbosity);
    }
    private static function retrieveRequirements(): RequirementCollection
    {
        if (null === self::$requirementsConfig) {
            self::$requirementsConfig = __DIR__ . '/../.requirements.php';
        }
        $config = require self::$requirementsConfig;
        $requirements = new RequirementCollection();
        foreach ($config as $constraint) {
            $requirements->addRequirement(self::createCondition($constraint['type'], $constraint['condition']), $constraint['message'], $constraint['helpMessage']);
        }
        return $requirements;
    }
    private static function createCondition($type, $condition): IsFulfilled
    {
        switch ($type) {
            case 'php':
                return new IsPhpVersionFulfilled($condition);
            case 'extension':
                return new IsExtensionFulfilled($condition);
            case 'extension-conflict':
                return new IsExtensionConflictFulfilled($condition);
            default:
                throw new InvalidArgumentException(sprintf('Unknown requirement type "%s".', $type));
        }
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use function fstat;
use function function_exists;
use function getenv;
use function implode;
use function posix_isatty;
use function preg_match;
use function preg_quote;
use function sapi_windows_vt100_support;
use function sprintf;
use function str_replace;
use function stream_isatty;
use const DIRECTORY_SEPARATOR;
use const STDOUT;
final class IO
{
    public const VERBOSITY_QUIET = 16;
    public const VERBOSITY_NORMAL = 32;
    public const VERBOSITY_VERBOSE = 64;
    public const VERBOSITY_VERY_VERBOSE = 128;
    public const VERBOSITY_DEBUG = 256;
    private $interactive;
    private $verbosity = self::VERBOSITY_NORMAL;
    private $colorSupport;
    private $options;
    public function __construct()
    {
        $this->options = implode(' ', $_SERVER['argv']);
        $shellVerbosity = $this->configureVerbosity();
        $this->interactive = $this->checkInteractivity($shellVerbosity);
        $this->colorSupport = $this->checkColorSupport();
    }
    public function isInteractive(): bool
    {
        return $this->interactive;
    }
    public function getVerbosity(): int
    {
        return $this->verbosity;
    }
    public function hasColorSupport(): bool
    {
        return $this->colorSupport;
    }
    public function hasParameter($values): bool
    {
        $values = (array) $values;
        foreach ($values as $value) {
            $regexp = sprintf('/\s%s\b/', str_replace(' ', '\s+', preg_quote($value, '/')));
            if (1 === preg_match($regexp, $this->options)) {
                return \true;
            }
        }
        return \false;
    }
    private function checkInteractivity(int $shellVerbosity): bool
    {
        if (-1 === $shellVerbosity) {
            return \false;
        }
        if (\true === $this->hasParameter(['--no-interaction', '-n'])) {
            return \false;
        }
        if (function_exists('posix_isatty') && !@posix_isatty(STDOUT) && \false === getenv('SHELL_INTERACTIVE')) {
            return \false;
        }
        return \true;
    }
    private function configureVerbosity(): int
    {
        switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
            case -1:
                $this->verbosity = self::VERBOSITY_QUIET;
                break;
            case 1:
                $this->verbosity = self::VERBOSITY_VERBOSE;
                break;
            case 2:
                $this->verbosity = self::VERBOSITY_VERY_VERBOSE;
                break;
            case 3:
                $this->verbosity = self::VERBOSITY_DEBUG;
                break;
            default:
                $shellVerbosity = 0;
                break;
        }
        if ($this->hasParameter(['--quiet', '-q'])) {
            $this->verbosity = self::VERBOSITY_QUIET;
            $shellVerbosity = -1;
        } elseif ($this->hasParameter(['-vvv', '--verbose=3', '--verbose 3'])) {
            $this->verbosity = self::VERBOSITY_DEBUG;
            $shellVerbosity = 3;
        } elseif ($this->hasParameter(['-vv', '--verbose=2', '--verbose 2'])) {
            $this->verbosity = self::VERBOSITY_VERY_VERBOSE;
            $shellVerbosity = 2;
        } elseif ($this->hasParameter(['-v', '--verbose=1', '--verbose 1', '--verbose'])) {
            $this->verbosity = self::VERBOSITY_VERBOSE;
            $shellVerbosity = 1;
        }
        return $shellVerbosity;
    }
    private function checkColorSupport(): bool
    {
        if ($this->hasParameter(['--ansi'])) {
            return \true;
        }
        if ($this->hasParameter(['--no-ansi'])) {
            return \false;
        }
        if (DIRECTORY_SEPARATOR === '\\') {
            return function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(STDOUT) || \false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
        }
        if (function_exists('stream_isatty')) {
            return stream_isatty(STDOUT);
        }
        if (function_exists('posix_isatty')) {
            return posix_isatty(STDOUT);
        }
        $stat = fstat(STDOUT);
        return $stat ? 020000 === ($stat['mode'] & 0170000) : \false;
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use function extension_loaded;
final class IsExtensionConflictFulfilled implements IsFulfilled
{
    private $conflictingExtension;
    public function __construct(string $requiredExtension)
    {
        $this->conflictingExtension = $requiredExtension;
    }
    public function __invoke(): bool
    {
        return !extension_loaded($this->conflictingExtension);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use function extension_loaded;
final class IsExtensionFulfilled implements IsFulfilled
{
    private $requiredExtension;
    public function __construct(string $requiredExtension)
    {
        $this->requiredExtension = $requiredExtension;
    }
    public function __invoke(): bool
    {
        return extension_loaded($this->requiredExtension);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

interface IsFulfilled
{
    public function __invoke(): bool;
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use HumbugBox468\Composer\Semver\Semver;
use function sprintf;
use const PHP_MAJOR_VERSION;
use const PHP_MINOR_VERSION;
use const PHP_RELEASE_VERSION;
final class IsPhpVersionFulfilled implements IsFulfilled
{
    private $requiredPhpVersion;
    public function __construct(string $requiredPhpVersion)
    {
        $this->requiredPhpVersion = $requiredPhpVersion;
    }
    public function __invoke(): bool
    {
        return Semver::satisfies(sprintf('%d.%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION), $this->requiredPhpVersion);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use function array_shift;
use function count;
use function explode;
use function ltrim;
use function min;
use function sprintf;
use function str_pad;
use function str_repeat;
use function strlen;
use function trim;
use function wordwrap;
use const PHP_EOL;
final class Printer
{
    private $styles = ['reset' => "\x1b[0m", 'red' => "\x1b[31m", 'green' => "\x1b[32m", 'yellow' => "\x1b[33m", 'title' => "\x1b[33m", 'error' => "\x1b[37;41m", 'success' => "\x1b[30;42m"];
    private $verbosity;
    private $supportColors;
    private $width;
    public function __construct(int $verbosity, bool $supportColors, ?int $width = null)
    {
        if (null === $width) {
            $terminal = new Terminal();
            $width = $terminal->getWidth();
        }
        $this->verbosity = $verbosity;
        $this->supportColors = $supportColors;
        $this->width = $width ?: 80;
    }
    public function getVerbosity(): int
    {
        return $this->verbosity;
    }
    public function setVerbosity($verbosity): void
    {
        $this->verbosity = $verbosity;
    }
    public function title(string $title, int $verbosity, ?string $style = null): void
    {
        if (null === $style) {
            $style = 'title';
        }
        $this->printvln('', $verbosity, $style);
        $this->printvln($title, $verbosity, $style);
        $this->printvln(str_repeat('=', min(strlen($title), $this->width)), $verbosity, $style);
        $this->printvln('', $verbosity, $style);
    }
    public function getRequirementErrorMessage(Requirement $requirement): ?string
    {
        if ($requirement->isFulfilled()) {
            return null;
        }
        return wordwrap($requirement->getHelpText(), $this->width - 3, PHP_EOL . '   ') . PHP_EOL;
    }
    public function block(string $title, string $message, int $verbosity, ?string $style = null): void
    {
        $prefix = ' [' . $title . '] ';
        $lineLength = $this->width - strlen($prefix) - 1;
        if ($lineLength < 0) {
            $lineLength = 0;
        }
        $message = $prefix . trim($message);
        $lines = [];
        $remainingMessage = $message;
        $wrapped = wordwrap($remainingMessage, $lineLength, '¬');
        $wrapped = explode('¬', $wrapped);
        do {
            $line = array_shift($wrapped);
            if ($lines && $lineLength > 0) {
                $line = str_repeat(' ', strlen($prefix)) . ltrim($line);
            }
            $lines[] = str_pad($line, $this->width, ' ', \STR_PAD_RIGHT);
        } while (count($wrapped));
        $this->printvln('', $verbosity);
        $this->printvln(str_repeat(' ', $this->width), $verbosity, $style);
        foreach ($lines as $line) {
            $this->printvln($line, $verbosity, $style);
        }
        $this->printv(str_repeat(' ', $this->width), $verbosity, $style);
        $this->printvln('', $verbosity);
    }
    public function printvln(string $message, int $verbosity, ?string $style = null): void
    {
        $this->printv($message, $verbosity, $style);
        $this->printv(PHP_EOL, $verbosity, null);
    }
    public function printv(string $message, int $verbosity, ?string $style = null): void
    {
        if ($verbosity > $this->verbosity) {
            return;
        }
        $message = wordwrap($message, $this->width);
        $message = sprintf('%s%s%s', $this->supportColors && isset($this->styles[$style]) ? $this->styles[$style] : '', $message, $this->supportColors ? $this->styles['reset'] : '');
        if ('1' === getenv('BOX_REQUIREMENTS_CHECKER_LOG_TO_STDOUT')) {
            echo $message;
        } else {
            fwrite(\STDERR, $message);
        }
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

final class Requirement
{
    private $checkIsFulfilled;
    private $fulfilled;
    private $testMessage;
    private $helpText;
    public function __construct(IsFulfilled $checkIsFulfilled, string $testMessage, string $helpText)
    {
        $this->checkIsFulfilled = $checkIsFulfilled;
        $this->testMessage = $testMessage;
        $this->helpText = $helpText;
    }
    public function isFulfilled(): bool
    {
        if (!isset($this->fulfilled)) {
            $this->fulfilled = $this->checkIsFulfilled->__invoke();
        }
        return $this->fulfilled;
    }
    public function getIsFullfilledChecker(): IsFulfilled
    {
        return $this->checkIsFulfilled;
    }
    public function getTestMessage(): string
    {
        return $this->testMessage;
    }
    public function getHelpText(): string
    {
        return $this->helpText;
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use ArrayIterator;
use Countable;
use IteratorAggregate;
use Traversable;
use function count;
use function get_cfg_var;
final class RequirementCollection implements IteratorAggregate, Countable
{
    private $requirements = [];
    private $phpIniPath;
    public function __construct($phpIniPath = null)
    {
        $this->phpIniPath = $phpIniPath ?? get_cfg_var('cfg_file_path');
    }
    public function getIterator(): Traversable
    {
        return new ArrayIterator($this->requirements);
    }
    public function count(): int
    {
        return count($this->requirements);
    }
    public function add(Requirement $requirement): void
    {
        $this->requirements[] = $requirement;
    }
    public function addRequirement(IsFulfilled $checkIsFulfilled, string $testMessage, string $helpText): void
    {
        $this->add(new Requirement($checkIsFulfilled, $testMessage, $helpText));
    }
    public function getRequirements(): array
    {
        return $this->requirements;
    }
    public function getPhpIniPath()
    {
        return $this->phpIniPath;
    }
    public function evaluateRequirements()
    {
        return array_reduce($this->requirements, static function (bool $checkPassed, Requirement $requirement): bool {
            return $checkPassed && $requirement->isFulfilled();
        }, \true);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox468\KevinGH\RequirementChecker;

use function exec;
use function fclose;
use function fopen;
use function function_exists;
use function getenv;
use function preg_match;
use function proc_close;
use function proc_open;
use function sapi_windows_cp_get;
use function sapi_windows_cp_set;
use function sapi_windows_vt100_support;
use function stream_get_contents;
use function trim;
use const DIRECTORY_SEPARATOR;
class Terminal
{
    private static $width;
    private static $height;
    private static $stty;
    public function getWidth(): int
    {
        $width = getenv('COLUMNS');
        if (\false !== $width) {
            return (int) trim($width);
        }
        if (!isset(self::$width)) {
            self::initDimensions();
        }
        return self::$width ?: 80;
    }
    public function getHeight(): int
    {
        $height = getenv('LINES');
        if (\false !== $height) {
            return (int) trim($height);
        }
        if (!isset(self::$height)) {
            self::initDimensions();
        }
        return self::$height ?: 50;
    }
    public static function hasSttyAvailable(): bool
    {
        if (isset(self::$stty)) {
            return self::$stty;
        }
        if (!function_exists('exec')) {
            return \false;
        }
        exec('stty 2>&1', $output, $exitcode);
        return self::$stty = 0 === $exitcode;
    }
    private static function initDimensions(): void
    {
        if ('\\' === DIRECTORY_SEPARATOR) {
            if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON') ?: ''), $matches)) {
                self::$width = (int) $matches[1];
                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
            } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
                self::initDimensionsUsingStty();
            } elseif (null !== $dimensions = self::getConsoleMode()) {
                self::$width = (int) $dimensions[0];
                self::$height = (int) $dimensions[1];
            }
        } else {
            self::initDimensionsUsingStty();
        }
    }
    private static function hasVt100Support(): bool
    {
        return function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'wb'));
    }
    private static function initDimensionsUsingStty(): void
    {
        if ($sttyString = self::getSttyColumns()) {
            if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            }
        }
    }
    private static function getConsoleMode(): ?array
    {
        $info = self::readFromProcess('mode CON');
        if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
            return null;
        }
        return [(int) $matches[2], (int) $matches[1]];
    }
    private static function getSttyColumns(): ?string
    {
        return self::readFromProcess('stty -a | grep columns');
    }
    private static function readFromProcess(string $command): ?string
    {
        if (!function_exists('proc_open')) {
            return null;
        }
        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
        $cp = function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;
        if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true])) {
            return null;
        }
        $info = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($process);
        if ($cp) {
            sapi_windows_cp_set($cp);
        }
        return $info;
    }
}
<?php

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, $err);
        } elseif (!headers_sent()) {
            echo $err;
        }
    }
    throw new RuntimeException($err);
}

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitHumbugBox468::getLoader();
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'HumbugBox468\\Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
    'HumbugBox468\\Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
    'HumbugBox468\\Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
    'HumbugBox468\\Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php',
    'HumbugBox468\\Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php',
    'HumbugBox468\\Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
    'HumbugBox468\\Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\Checker' => $baseDir . '/src/Checker.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\IO' => $baseDir . '/src/IO.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\IsExtensionConflictFulfilled' => $baseDir . '/src/IsExtensionConflictFulfilled.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => $baseDir . '/src/IsExtensionFulfilled.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\IsFulfilled' => $baseDir . '/src/IsFulfilled.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => $baseDir . '/src/IsPhpVersionFulfilled.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\Printer' => $baseDir . '/src/Printer.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\Requirement' => $baseDir . '/src/Requirement.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\RequirementCollection' => $baseDir . '/src/RequirementCollection.php',
    'HumbugBox468\\KevinGH\\RequirementChecker\\Terminal' => $baseDir . '/src/Terminal.php',
);
<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
);
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'HumbugBox468\\KevinGH\\RequirementChecker\\' => array($baseDir . '/src'),
    'HumbugBox468\\Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
);
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInitHumbugBox468
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInitHumbugBox468', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInitHumbugBox468', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInitHumbugBox468::getInitializer($loader));

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        return $loader;
    }
}
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInitHumbugBox468
{
    public static $prefixLengthsPsr4 = array (
        'H' => 
        array (
            'HumbugBox468\\KevinGH\\RequirementChecker\\' => 40,
            'HumbugBox468\\Composer\\Semver\\' => 29,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'HumbugBox468\\KevinGH\\RequirementChecker\\' => 
        array (
            0 => __DIR__ . '/../..' . '/src',
        ),
        'HumbugBox468\\Composer\\Semver\\' => 
        array (
            0 => __DIR__ . '/..' . '/composer/semver/src',
        ),
    );

    public static $classMap = array (
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
        'HumbugBox468\\Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php',
        'HumbugBox468\\Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
        'HumbugBox468\\Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php',
        'HumbugBox468\\Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php',
        'HumbugBox468\\Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php',
        'HumbugBox468\\Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php',
        'HumbugBox468\\Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\Checker' => __DIR__ . '/../..' . '/src/Checker.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\IO' => __DIR__ . '/../..' . '/src/IO.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\IsExtensionConflictFulfilled' => __DIR__ . '/../..' . '/src/IsExtensionConflictFulfilled.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => __DIR__ . '/../..' . '/src/IsExtensionFulfilled.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\IsFulfilled' => __DIR__ . '/../..' . '/src/IsFulfilled.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => __DIR__ . '/../..' . '/src/IsPhpVersionFulfilled.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\Printer' => __DIR__ . '/../..' . '/src/Printer.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\Requirement' => __DIR__ . '/../..' . '/src/Requirement.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\RequirementCollection' => __DIR__ . '/../..' . '/src/RequirementCollection.php',
        'HumbugBox468\\KevinGH\\RequirementChecker\\Terminal' => __DIR__ . '/../..' . '/src/Terminal.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInitHumbugBox468::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInitHumbugBox468::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInitHumbugBox468::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var string|null */
    private $vendorDir;

    // PSR-4
    /**
     * @var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array<string, list<string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var array<string, bool>
     */
    private $missingClasses = array();

    /** @var string|null */
    private $apcuPrefix;

    /**
     * @var array<string, self>
     */
    private static $registeredLoaders = array();

    /**
     * @param string|null $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
        self::initializeIncludeClosure();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return array<string, string> Array of classname => path
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array<string, string> $classMap Class to filename map
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string              $prefix  The prefix
     * @param list<string>|string $paths   The PSR-0 root directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string              $prefix  The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths   The PSR-4 base directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string              $prefix The prefix
     * @param list<string>|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string              $prefix The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            $includeFile = self::$includeFile;
            $includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders keyed by their corresponding vendor directories.
     *
     * @return array<string, self>
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }

    /**
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) {
            return;
        }

        /**
         * Scope isolated include.
         *
         * Prevents access to $this/self from included files.
         *
         * @param  string $file
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) {
            include $file;
        }, null, null);
    }
}
<?php

namespace HumbugBox468;

return array('root' => array('name' => 'humbug/requirement-checker', 'pretty_version' => '4.x.x-dev', 'version' => '4.9999999.9999999.9999999-dev', 'reference' => null, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \true), 'versions' => array('composer/semver' => array('pretty_version' => '3.4.0', 'version' => '3.4.0.0', 'reference' => '35e8d0af4486141bc745f23a29cc2091eb624a32', 'type' => 'library', 'install_path' => __DIR__ . '/./semver', 'aliases' => array(), 'dev_requirement' => \false), 'ergebnis/composer-normalize' => array('pretty_version' => '2.43.0', 'version' => '2.43.0.0', 'reference' => '4b46330c84bb8f43fac79f5c5a05162fc7c80d75', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../ergebnis/composer-normalize', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json' => array('pretty_version' => '1.2.0', 'version' => '1.2.0.0', 'reference' => 'a457f25a5ba7ea11fc94f84d53678c5211abfce0', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-normalizer' => array('pretty_version' => '4.5.0', 'version' => '4.5.0.0', 'reference' => 'f0ee9e70739f121b27fac8b743e4a52b23de2152', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-normalizer', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-pointer' => array('pretty_version' => '3.4.0', 'version' => '3.4.0.0', 'reference' => 'b654757d873050622c2166f55ab25d04685261c5', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-pointer', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-printer' => array('pretty_version' => '3.5.0', 'version' => '3.5.0.0', 'reference' => '549e16fe6de34b8c3aee7b421be12caa552f3ced', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-printer', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-schema-validator' => array('pretty_version' => '4.2.0', 'version' => '4.2.0.0', 'reference' => '10ed514fdc3f9b71f8a92c567afea21a2f6fa1ef', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-schema-validator', 'aliases' => array(), 'dev_requirement' => \true), 'fidry/makefile' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'reference' => 'be5a048dcc5648d04e924facce0f85b406d731e4', 'type' => 'library', 'install_path' => __DIR__ . '/../fidry/makefile', 'aliases' => array(), 'dev_requirement' => \true), 'humbug/requirement-checker' => array('pretty_version' => '4.x.x-dev', 'version' => '4.9999999.9999999.9999999-dev', 'reference' => null, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'justinrainbow/json-schema' => array('pretty_version' => 'v5.2.13', 'version' => '5.2.13.0', 'reference' => 'fbbe7e5d79f618997bc3332a6f49246036c45793', 'type' => 'library', 'install_path' => __DIR__ . '/../justinrainbow/json-schema', 'aliases' => array(), 'dev_requirement' => \true), 'localheinz/diff' => array('pretty_version' => '1.1.1', 'version' => '1.1.1.0', 'reference' => '851bb20ea8358c86f677f5f111c4ab031b1c764c', 'type' => 'library', 'install_path' => __DIR__ . '/../localheinz/diff', 'aliases' => array(), 'dev_requirement' => \true), 'myclabs/deep-copy' => array('pretty_version' => '1.12.0', 'version' => '1.12.0.0', 'reference' => '3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'dev_requirement' => \true), 'nikic/php-parser' => array('pretty_version' => 'v5.1.0', 'version' => '5.1.0.0', 'reference' => '683130c2ff8c2739f4822ff7ac5c873ec529abd1', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), 'dev_requirement' => \true), 'phar-io/manifest' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => '54750ef60c58e43759730615a392c31c80e23176', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/manifest', 'aliases' => array(), 'dev_requirement' => \true), 'phar-io/version' => array('pretty_version' => '3.2.1', 'version' => '3.2.1.0', 'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/version', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-code-coverage' => array('pretty_version' => '10.1.15', 'version' => '10.1.15.0', 'reference' => '5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-file-iterator' => array('pretty_version' => '4.1.0', 'version' => '4.1.0.0', 'reference' => 'a95037b6d9e608ba092da1b23931e537cadc3c3c', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-file-iterator', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-invoker' => array('pretty_version' => '4.0.0', 'version' => '4.0.0.0', 'reference' => 'f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-invoker', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-text-template' => array('pretty_version' => '3.0.1', 'version' => '3.0.1.0', 'reference' => '0c7b06ff49e3d5072f057eb1fa59258bf287a748', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-text-template', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-timer' => array('pretty_version' => '6.0.0', 'version' => '6.0.0.0', 'reference' => 'e2a2d67966e740530f4a3343fe2e030ffdc1161d', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-timer', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/phpunit' => array('pretty_version' => '10.5.26', 'version' => '10.5.26.0', 'reference' => '42e2f13ceaa2e34461bc89bea75407550b40b2aa', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/cli-parser' => array('pretty_version' => '2.0.1', 'version' => '2.0.1.0', 'reference' => 'c34583b87e7b7a8055bf6c450c2c77ce32a24084', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/cli-parser', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit' => array('pretty_version' => '2.0.0', 'version' => '2.0.0.0', 'reference' => 'a81fee9eef0b7a76af11d121767abc44c104e503', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit-reverse-lookup' => array('pretty_version' => '3.0.0', 'version' => '3.0.0.0', 'reference' => '5e3a687f7d8ae33fb362c5c0743794bbb2420a1d', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/comparator' => array('pretty_version' => '5.0.1', 'version' => '5.0.1.0', 'reference' => '2db5010a484d53ebf536087a70b4a5423c102372', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/comparator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/complexity' => array('pretty_version' => '3.2.0', 'version' => '3.2.0.0', 'reference' => '68ff824baeae169ec9f2137158ee529584553799', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/complexity', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/diff' => array('pretty_version' => '5.1.1', 'version' => '5.1.1.0', 'reference' => 'c41e007b4b62af48218231d6c2275e4c9b975b2e', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/environment' => array('pretty_version' => '6.1.0', 'version' => '6.1.0.0', 'reference' => '8074dbcd93529b357029f5cc5058fd3e43666984', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/environment', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/exporter' => array('pretty_version' => '5.1.2', 'version' => '5.1.2.0', 'reference' => '955288482d97c19a372d3f31006ab3f37da47adf', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/exporter', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/global-state' => array('pretty_version' => '6.0.2', 'version' => '6.0.2.0', 'reference' => '987bafff24ecc4c9ac418cab1145b96dd6e9cbd9', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/global-state', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/lines-of-code' => array('pretty_version' => '2.0.2', 'version' => '2.0.2.0', 'reference' => '856e7f6a75a84e339195d48c556f23be2ebf75d0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/lines-of-code', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-enumerator' => array('pretty_version' => '5.0.0', 'version' => '5.0.0.0', 'reference' => '202d0e344a580d7f7d04b3fafce6933e59dae906', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-enumerator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-reflector' => array('pretty_version' => '3.0.0', 'version' => '3.0.0.0', 'reference' => '24ed13d98130f0e7122df55d06c5c4942a577957', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-reflector', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/recursion-context' => array('pretty_version' => '5.0.0', 'version' => '5.0.0.0', 'reference' => '05909fb5bc7df4c52992396d0116aed689f93712', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/recursion-context', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/type' => array('pretty_version' => '4.0.0', 'version' => '4.0.0.0', 'reference' => '462699a16464c3944eefc02ebdd77882bd3925bf', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/type', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/version' => array('pretty_version' => '4.0.1', 'version' => '4.0.1.0', 'reference' => 'c51fa83a5d8f43f1402e3f32a005e6262244ef17', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/version', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/deprecation-contracts' => array('pretty_version' => 'v3.5.0', 'version' => '3.5.0.0', 'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/polyfill-ctype' => array('pretty_version' => 'v1.30.0', 'version' => '1.30.0.0', 'reference' => '0424dff1c58f028c451efff2045f5d92410bd540', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/yaml' => array('pretty_version' => 'v6.4.8', 'version' => '6.4.8.0', 'reference' => '52903de178d542850f6f341ba92995d3d63e60c9', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/yaml', 'aliases' => array(), 'dev_requirement' => \true), 'thecodingmachine/safe' => array('pretty_version' => 'v2.5.0', 'version' => '2.5.0.0', 'reference' => '3115ecd6b4391662b4931daac4eba6b07a2ac1f0', 'type' => 'library', 'install_path' => __DIR__ . '/../thecodingmachine/safe', 'aliases' => array(), 'dev_requirement' => \true), 'theseer/tokenizer' => array('pretty_version' => '1.2.3', 'version' => '1.2.3.0', 'reference' => '737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2', 'type' => 'library', 'install_path' => __DIR__ . '/../theseer/tokenizer', 'aliases' => array(), 'dev_requirement' => \true)));
<?php

namespace HumbugBox468\Composer;

use HumbugBox468\Composer\Autoload\ClassLoader;
use HumbugBox468\Composer\Semver\VersionParser;
class InstalledVersions
{
    private static $selfDir = null;
    /**
    @psalm-var
    */
    private static $installed;
    private static $installedIsLocalDir;
    private static $canGetVendors;
    /**
    @psalm-var
    */
    private static $installedByVendor = array();
    /**
    @psalm-return
    */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = array_keys($installed['versions']);
        }
        if (1 === \count($packages)) {
            return $packages[0];
        }
        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
    }
    /**
    @psalm-return
    */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();
        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }
        return $packagesByType;
    }
    public static function isInstalled($packageName, $includeDevRequirements = \true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === \false;
            }
        }
        return \false;
    }
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints((string) $constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
        return $provided->matches($constraint);
    }
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }
            return implode(' || ', $ranges);
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['pretty_version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }
            return $installed['versions'][$packageName]['reference'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
    @psalm-return
    */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();
        return $installed[0]['root'];
    }
    /**
    @psalm-return
    */
    public static function getRawData()
    {
        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED);
        if (null === self::$installed) {
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = include __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }
        return self::$installed;
    }
    /**
    @psalm-return
    */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }
    /**
    @psalm-param
    */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();
        self::$installedIsLocalDir = \false;
    }
    private static function getSelfDir()
    {
        if (self::$selfDir === null) {
            self::$selfDir = strtr(__DIR__, '\\', '/');
        }
        return self::$selfDir;
    }
    /**
    @psalm-return
    */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = method_exists('HumbugBox468\Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
        }
        $installed = array();
        $copiedLocalDir = \false;
        if (self::$canGetVendors) {
            $selfDir = self::getSelfDir();
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                $vendorDir = strtr($vendorDir, '\\', '/');
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (is_file($vendorDir . '/composer/installed.php')) {
                    $required = require $vendorDir . '/composer/installed.php';
                    self::$installedByVendor[$vendorDir] = $required;
                    $installed[] = $required;
                    if (self::$installed === null && $vendorDir . '/composer' === $selfDir) {
                        self::$installed = $required;
                        self::$installedIsLocalDir = \true;
                    }
                }
                if (self::$installedIsLocalDir && $vendorDir . '/composer' === $selfDir) {
                    $copiedLocalDir = \true;
                }
            }
        }
        if (null === self::$installed) {
            if (substr(__DIR__, -8, 1) !== 'C') {
                $required = require __DIR__ . '/installed.php';
                self::$installed = $required;
            } else {
                self::$installed = array();
            }
        }
        if (self::$installed !== array() && !$copiedLocalDir) {
            $installed[] = self::$installed;
        }
        return $installed;
    }
}

Copyright (c) Nils Adermann, Jordi Boggiano

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.

Copyright (C) 2015 Composer

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.
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\Constraint;
class Comparator
{
    public static function greaterThan($version1, $version2)
    {
        return self::compare($version1, '>', $version2);
    }
    public static function greaterThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '>=', $version2);
    }
    public static function lessThan($version1, $version2)
    {
        return self::compare($version1, '<', $version2);
    }
    public static function lessThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '<=', $version2);
    }
    public static function equalTo($version1, $version2)
    {
        return self::compare($version1, '==', $version2);
    }
    public static function notEqualTo($version1, $version2)
    {
        return self::compare($version1, '!=', $version2);
    }
    /**
    @phpstan-param
    */
    public static function compare($version1, $operator, $version2)
    {
        $constraint = new Constraint($operator, $version2);
        return $constraint->matchSpecific(new Constraint('==', $version1), \true);
    }
}
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\Constraint;
use HumbugBox468\Composer\Semver\Constraint\ConstraintInterface;
class CompilingMatcher
{
    /**
    @phpstan-var
    */
    private static $compiledCheckerCache = array();
    /**
    @phpstan-var
    */
    private static $resultCache = array();
    private static $enabled;
    /**
    @phpstan-var
    */
    private static $transOpInt = array(Constraint::OP_EQ => Constraint::STR_OP_EQ, Constraint::OP_LT => Constraint::STR_OP_LT, Constraint::OP_LE => Constraint::STR_OP_LE, Constraint::OP_GT => Constraint::STR_OP_GT, Constraint::OP_GE => Constraint::STR_OP_GE, Constraint::OP_NE => Constraint::STR_OP_NE);
    public static function clear()
    {
        self::$resultCache = array();
        self::$compiledCheckerCache = array();
    }
    /**
    @phpstan-param
    */
    public static function match(ConstraintInterface $constraint, $operator, $version)
    {
        $resultCacheKey = $operator . $constraint . ';' . $version;
        if (isset(self::$resultCache[$resultCacheKey])) {
            return self::$resultCache[$resultCacheKey];
        }
        if (self::$enabled === null) {
            self::$enabled = !\in_array('eval', explode(',', (string) ini_get('disable_functions')), \true);
        }
        if (!self::$enabled) {
            return self::$resultCache[$resultCacheKey] = $constraint->matches(new Constraint(self::$transOpInt[$operator], $version));
        }
        $cacheKey = $operator . $constraint;
        if (!isset(self::$compiledCheckerCache[$cacheKey])) {
            $code = $constraint->compile($operator);
            self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return ' . $code . ';};');
        } else {
            $function = self::$compiledCheckerCache[$cacheKey];
        }
        return self::$resultCache[$resultCacheKey] = $function($version, strpos($version, 'dev-') === 0);
    }
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

class Bound
{
    private $version;
    private $isInclusive;
    public function __construct($version, $isInclusive)
    {
        $this->version = $version;
        $this->isInclusive = $isInclusive;
    }
    public function getVersion()
    {
        return $this->version;
    }
    public function isInclusive()
    {
        return $this->isInclusive;
    }
    public function isZero()
    {
        return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive();
    }
    public function isPositiveInfinity()
    {
        return $this->getVersion() === \PHP_INT_MAX . '.0.0.0' && !$this->isInclusive();
    }
    public function compareTo(Bound $other, $operator)
    {
        if (!\in_array($operator, array('<', '>'), \true)) {
            throw new \InvalidArgumentException('Does not support any other operator other than > or <.');
        }
        if ($this == $other) {
            return \false;
        }
        $compareResult = version_compare($this->getVersion(), $other->getVersion());
        if (0 !== $compareResult) {
            return ('>' === $operator ? 1 : -1) === $compareResult;
        }
        return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
    }
    public function __toString()
    {
        return sprintf('%s [%s]', $this->getVersion(), $this->isInclusive() ? 'inclusive' : 'exclusive');
    }
    public static function zero()
    {
        return new Bound('0.0.0.0-dev', \true);
    }
    public static function positiveInfinity()
    {
        return new Bound(\PHP_INT_MAX . '.0.0.0', \false);
    }
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

class Constraint implements ConstraintInterface
{
    const OP_EQ = 0;
    const OP_LT = 1;
    const OP_LE = 2;
    const OP_GT = 3;
    const OP_GE = 4;
    const OP_NE = 5;
    const STR_OP_EQ = '==';
    const STR_OP_EQ_ALT = '=';
    const STR_OP_LT = '<';
    const STR_OP_LE = '<=';
    const STR_OP_GT = '>';
    const STR_OP_GE = '>=';
    const STR_OP_NE = '!=';
    const STR_OP_NE_ALT = '<>';
    /**
    @phpstan-var
    */
    private static $transOpStr = array('=' => self::OP_EQ, '==' => self::OP_EQ, '<' => self::OP_LT, '<=' => self::OP_LE, '>' => self::OP_GT, '>=' => self::OP_GE, '<>' => self::OP_NE, '!=' => self::OP_NE);
    /**
    @phpstan-var
    */
    private static $transOpInt = array(self::OP_EQ => '==', self::OP_LT => '<', self::OP_LE => '<=', self::OP_GT => '>', self::OP_GE => '>=', self::OP_NE => '!=');
    /**
    @phpstan-var
    */
    protected $operator;
    protected $version;
    protected $prettyString;
    protected $lowerBound;
    protected $upperBound;
    /**
    @phpstan-param
    */
    public function __construct($operator, $version)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(sprintf('Invalid operator "%s" given, expected one of: %s', $operator, implode(', ', self::getSupportedOperators())));
        }
        $this->operator = self::$transOpStr[$operator];
        $this->version = $version;
    }
    public function getVersion()
    {
        return $this->version;
    }
    /**
    @phpstan-return
    */
    public function getOperator()
    {
        return self::$transOpInt[$this->operator];
    }
    public function matches(ConstraintInterface $provider)
    {
        if ($provider instanceof self) {
            return $this->matchSpecific($provider);
        }
        return $provider->matches($this);
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return $this->__toString();
    }
    /**
    @phpstan-return
    */
    public static function getSupportedOperators()
    {
        return array_keys(self::$transOpStr);
    }
    /**
    @phpstan-param
    @phpstan-return
    */
    public static function getOperatorConstant($operator)
    {
        return self::$transOpStr[$operator];
    }
    /**
    @phpstan-param
    */
    public function versionCompare($a, $b, $operator, $compareBranches = \false)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(sprintf('Invalid operator "%s" given, expected one of: %s', $operator, implode(', ', self::getSupportedOperators())));
        }
        $aIsBranch = strpos($a, 'dev-') === 0;
        $bIsBranch = strpos($b, 'dev-') === 0;
        if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
            return $a !== $b;
        }
        if ($aIsBranch && $bIsBranch) {
            return $operator === '==' && $a === $b;
        }
        if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
            return \false;
        }
        return \version_compare($a, $b, $operator);
    }
    public function compile($otherOperator)
    {
        if (strpos($this->version, 'dev-') === 0) {
            if (self::OP_EQ === $this->operator) {
                if (self::OP_EQ === $otherOperator) {
                    return sprintf('$b && $v === %s', \var_export($this->version, \true));
                }
                if (self::OP_NE === $otherOperator) {
                    return sprintf('!$b || $v !== %s', \var_export($this->version, \true));
                }
                return 'false';
            }
            if (self::OP_NE === $this->operator) {
                if (self::OP_EQ === $otherOperator) {
                    return sprintf('!$b || $v !== %s', \var_export($this->version, \true));
                }
                if (self::OP_NE === $otherOperator) {
                    return 'true';
                }
                return '!$b';
            }
            return 'false';
        }
        if (self::OP_EQ === $this->operator) {
            if (self::OP_EQ === $otherOperator) {
                return sprintf('\version_compare($v, %s, \'==\')', \var_export($this->version, \true));
            }
            if (self::OP_NE === $otherOperator) {
                return sprintf('$b || \version_compare($v, %s, \'!=\')', \var_export($this->version, \true));
            }
            return sprintf('!$b && \version_compare(%s, $v, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$otherOperator]);
        }
        if (self::OP_NE === $this->operator) {
            if (self::OP_EQ === $otherOperator) {
                return sprintf('$b || (!$b && \version_compare($v, %s, \'!=\'))', \var_export($this->version, \true));
            }
            if (self::OP_NE === $otherOperator) {
                return 'true';
            }
            return '!$b';
        }
        if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
            if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
                return '!$b';
            }
        } else if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
            return '!$b';
        }
        if (self::OP_NE === $otherOperator) {
            return 'true';
        }
        $codeComparison = sprintf('\version_compare($v, %s, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$this->operator]);
        if ($this->operator === self::OP_LE) {
            if ($otherOperator === self::OP_GT) {
                return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
            }
        } elseif ($this->operator === self::OP_GE) {
            if ($otherOperator === self::OP_LT) {
                return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
            }
        }
        return sprintf('!$b && %s', $codeComparison);
    }
    public function matchSpecific(Constraint $provider, $compareBranches = \false)
    {
        $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
        $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
        $isEqualOp = self::OP_EQ === $this->operator;
        $isNonEqualOp = self::OP_NE === $this->operator;
        $isProviderEqualOp = self::OP_EQ === $provider->operator;
        $isProviderNonEqualOp = self::OP_NE === $provider->operator;
        if ($isNonEqualOp || $isProviderNonEqualOp) {
            if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && strpos($provider->version, 'dev-') === 0) {
                return \false;
            }
            if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && strpos($this->version, 'dev-') === 0) {
                return \false;
            }
            if (!$isEqualOp && !$isProviderEqualOp) {
                return \true;
            }
            return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
        }
        if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
            return !(strpos($this->version, 'dev-') === 0 || strpos($provider->version, 'dev-') === 0);
        }
        $version1 = $isEqualOp ? $this->version : $provider->version;
        $version2 = $isEqualOp ? $provider->version : $this->version;
        $operator = $isEqualOp ? $provider->operator : $this->operator;
        if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
            return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp && self::$transOpInt[$this->operator] !== $noEqualOp && \version_compare($provider->version, $this->version, '=='));
        }
        return \false;
    }
    public function __toString()
    {
        return self::$transOpInt[$this->operator] . ' ' . $this->version;
    }
    public function getLowerBound()
    {
        $this->extractBounds();
        return $this->lowerBound;
    }
    public function getUpperBound()
    {
        $this->extractBounds();
        return $this->upperBound;
    }
    private function extractBounds()
    {
        if (null !== $this->lowerBound) {
            return;
        }
        if (strpos($this->version, 'dev-') === 0) {
            $this->lowerBound = Bound::zero();
            $this->upperBound = Bound::positiveInfinity();
            return;
        }
        switch ($this->operator) {
            case self::OP_EQ:
                $this->lowerBound = new Bound($this->version, \true);
                $this->upperBound = new Bound($this->version, \true);
                break;
            case self::OP_LT:
                $this->lowerBound = Bound::zero();
                $this->upperBound = new Bound($this->version, \false);
                break;
            case self::OP_LE:
                $this->lowerBound = Bound::zero();
                $this->upperBound = new Bound($this->version, \true);
                break;
            case self::OP_GT:
                $this->lowerBound = new Bound($this->version, \false);
                $this->upperBound = Bound::positiveInfinity();
                break;
            case self::OP_GE:
                $this->lowerBound = new Bound($this->version, \true);
                $this->upperBound = Bound::positiveInfinity();
                break;
            case self::OP_NE:
                $this->lowerBound = Bound::zero();
                $this->upperBound = Bound::positiveInfinity();
                break;
        }
    }
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

interface ConstraintInterface
{
    public function matches(ConstraintInterface $provider);
    /**
    @phpstan-param
    */
    public function compile($otherOperator);
    public function getUpperBound();
    public function getLowerBound();
    public function getPrettyString();
    public function setPrettyString($prettyString);
    public function __toString();
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

class MatchAllConstraint implements ConstraintInterface
{
    protected $prettyString;
    public function matches(ConstraintInterface $provider)
    {
        return \true;
    }
    public function compile($otherOperator)
    {
        return 'true';
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        return '*';
    }
    public function getUpperBound()
    {
        return Bound::positiveInfinity();
    }
    public function getLowerBound()
    {
        return Bound::zero();
    }
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

class MatchNoneConstraint implements ConstraintInterface
{
    protected $prettyString;
    public function matches(ConstraintInterface $provider)
    {
        return \false;
    }
    public function compile($otherOperator)
    {
        return 'false';
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        return '[]';
    }
    public function getUpperBound()
    {
        return new Bound('0.0.0.0-dev', \false);
    }
    public function getLowerBound()
    {
        return new Bound('0.0.0.0-dev', \false);
    }
}
<?php

namespace HumbugBox468\Composer\Semver\Constraint;

class MultiConstraint implements ConstraintInterface
{
    /**
    @phpstan-var
    */
    protected $constraints;
    protected $prettyString;
    protected $string;
    protected $conjunctive;
    protected $lowerBound;
    protected $upperBound;
    public function __construct(array $constraints, $conjunctive = \true)
    {
        if (\count($constraints) < 2) {
            throw new \InvalidArgumentException('Must provide at least two constraints for a MultiConstraint. Use ' . 'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use ' . 'MultiConstraint::create() which optimizes and handles those cases automatically.');
        }
        $this->constraints = $constraints;
        $this->conjunctive = $conjunctive;
    }
    public function getConstraints()
    {
        return $this->constraints;
    }
    public function isConjunctive()
    {
        return $this->conjunctive;
    }
    public function isDisjunctive()
    {
        return !$this->conjunctive;
    }
    public function compile($otherOperator)
    {
        $parts = array();
        foreach ($this->constraints as $constraint) {
            $code = $constraint->compile($otherOperator);
            if ($code === 'true') {
                if (!$this->conjunctive) {
                    return 'true';
                }
            } elseif ($code === 'false') {
                if ($this->conjunctive) {
                    return 'false';
                }
            } else {
                $parts[] = '(' . $code . ')';
            }
        }
        if (!$parts) {
            return $this->conjunctive ? 'true' : 'false';
        }
        return $this->conjunctive ? implode('&&', $parts) : implode('||', $parts);
    }
    public function matches(ConstraintInterface $provider)
    {
        if (\false === $this->conjunctive) {
            foreach ($this->constraints as $constraint) {
                if ($provider->matches($constraint)) {
                    return \true;
                }
            }
            return \false;
        }
        if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) {
            return $provider->matches($this);
        }
        foreach ($this->constraints as $constraint) {
            if (!$provider->matches($constraint)) {
                return \false;
            }
        }
        return \true;
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        if ($this->string !== null) {
            return $this->string;
        }
        $constraints = array();
        foreach ($this->constraints as $constraint) {
            $constraints[] = (string) $constraint;
        }
        return $this->string = '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
    }
    public function getLowerBound()
    {
        $this->extractBounds();
        if (null === $this->lowerBound) {
            throw new \LogicException('extractBounds should have populated the lowerBound property');
        }
        return $this->lowerBound;
    }
    public function getUpperBound()
    {
        $this->extractBounds();
        if (null === $this->upperBound) {
            throw new \LogicException('extractBounds should have populated the upperBound property');
        }
        return $this->upperBound;
    }
    public static function create(array $constraints, $conjunctive = \true)
    {
        if (0 === \count($constraints)) {
            return new MatchAllConstraint();
        }
        if (1 === \count($constraints)) {
            return $constraints[0];
        }
        $optimized = self::optimizeConstraints($constraints, $conjunctive);
        if ($optimized !== null) {
            list($constraints, $conjunctive) = $optimized;
            if (\count($constraints) === 1) {
                return $constraints[0];
            }
        }
        return new self($constraints, $conjunctive);
    }
    /**
    @phpstan-return
    */
    private static function optimizeConstraints(array $constraints, $conjunctive)
    {
        if (!$conjunctive) {
            $left = $constraints[0];
            $mergedConstraints = array();
            $optimized = \false;
            for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
                $right = $constraints[$i];
                if ($left instanceof self && $left->conjunctive && $right instanceof self && $right->conjunctive && \count($left->constraints) === 2 && \count($right->constraints) === 2 && ($left0 = (string) $left->constraints[0]) && $left0[0] === '>' && $left0[1] === '=' && ($left1 = (string) $left->constraints[1]) && $left1[0] === '<' && ($right0 = (string) $right->constraints[0]) && $right0[0] === '>' && $right0[1] === '=' && ($right1 = (string) $right->constraints[1]) && $right1[0] === '<' && substr($left1, 2) === substr($right0, 3)) {
                    $optimized = \true;
                    $left = new MultiConstraint(array($left->constraints[0], $right->constraints[1]), \true);
                } else {
                    $mergedConstraints[] = $left;
                    $left = $right;
                }
            }
            if ($optimized) {
                $mergedConstraints[] = $left;
                return array($mergedConstraints, \false);
            }
        }
        return null;
    }
    private function extractBounds()
    {
        if (null !== $this->lowerBound) {
            return;
        }
        foreach ($this->constraints as $constraint) {
            if (null === $this->lowerBound || null === $this->upperBound) {
                $this->lowerBound = $constraint->getLowerBound();
                $this->upperBound = $constraint->getUpperBound();
                continue;
            }
            if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) {
                $this->lowerBound = $constraint->getLowerBound();
            }
            if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) {
                $this->upperBound = $constraint->getUpperBound();
            }
        }
    }
}
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\Constraint;
class Interval
{
    private $start;
    private $end;
    public function __construct(Constraint $start, Constraint $end)
    {
        $this->start = $start;
        $this->end = $end;
    }
    public function getStart()
    {
        return $this->start;
    }
    public function getEnd()
    {
        return $this->end;
    }
    public static function fromZero()
    {
        static $zero;
        if (null === $zero) {
            $zero = new Constraint('>=', '0.0.0.0-dev');
        }
        return $zero;
    }
    public static function untilPositiveInfinity()
    {
        static $positiveInfinity;
        if (null === $positiveInfinity) {
            $positiveInfinity = new Constraint('<', \PHP_INT_MAX . '.0.0.0');
        }
        return $positiveInfinity;
    }
    public static function any()
    {
        return new self(self::fromZero(), self::untilPositiveInfinity());
    }
    public static function anyDev()
    {
        return array('names' => array(), 'exclude' => \true);
    }
    public static function noDev()
    {
        return array('names' => array(), 'exclude' => \false);
    }
}
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\Constraint;
use HumbugBox468\Composer\Semver\Constraint\ConstraintInterface;
use HumbugBox468\Composer\Semver\Constraint\MatchAllConstraint;
use HumbugBox468\Composer\Semver\Constraint\MatchNoneConstraint;
use HumbugBox468\Composer\Semver\Constraint\MultiConstraint;
class Intervals
{
    /**
    @phpstan-var
    */
    private static $intervalsCache = array();
    /**
    @phpstan-var
    */
    private static $opSortOrder = array('>=' => -3, '<' => -2, '>' => 2, '<=' => 3);
    public static function clear()
    {
        self::$intervalsCache = array();
    }
    public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint)
    {
        if ($constraint instanceof MatchAllConstraint) {
            return \true;
        }
        if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) {
            return \false;
        }
        $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), \true));
        $candidateIntervals = self::get($candidate);
        if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) {
            return \false;
        }
        foreach ($intersectionIntervals['numeric'] as $index => $interval) {
            if (!isset($candidateIntervals['numeric'][$index])) {
                return \false;
            }
            if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) {
                return \false;
            }
            if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) {
                return \false;
            }
        }
        if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) {
            return \false;
        }
        if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) {
            return \false;
        }
        foreach ($intersectionIntervals['branches']['names'] as $index => $name) {
            if ($name !== $candidateIntervals['branches']['names'][$index]) {
                return \false;
            }
        }
        return \true;
    }
    public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b)
    {
        if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) {
            return \true;
        }
        if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) {
            return \false;
        }
        $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), \true), \true);
        return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0;
    }
    public static function compactConstraint(ConstraintInterface $constraint)
    {
        if (!$constraint instanceof MultiConstraint) {
            return $constraint;
        }
        $intervals = self::generateIntervals($constraint);
        $constraints = array();
        $hasNumericMatchAll = \false;
        if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) {
            $constraints[] = $intervals['numeric'][0]->getStart();
            $hasNumericMatchAll = \true;
        } else {
            $unEqualConstraints = array();
            for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) {
                $interval = $intervals['numeric'][$i];
                if ($interval->getEnd()->getOperator() === '<' && $i + 1 < $count) {
                    $nextInterval = $intervals['numeric'][$i + 1];
                    if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') {
                        if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) {
                            $unEqualConstraints[] = $interval->getStart();
                        }
                        $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion());
                        continue;
                    }
                }
                if (\count($unEqualConstraints) > 0) {
                    if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) {
                        $unEqualConstraints[] = $interval->getEnd();
                    }
                    if (\count($unEqualConstraints) > 1) {
                        $constraints[] = new MultiConstraint($unEqualConstraints, \true);
                    } else {
                        $constraints[] = $unEqualConstraints[0];
                    }
                    $unEqualConstraints = array();
                    continue;
                }
                if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') {
                    $constraints[] = new Constraint('==', $interval->getStart()->getVersion());
                    continue;
                }
                if ((string) $interval->getStart() === (string) Interval::fromZero()) {
                    $constraints[] = $interval->getEnd();
                } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) {
                    $constraints[] = $interval->getStart();
                } else {
                    $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), \true);
                }
            }
        }
        $devConstraints = array();
        if (0 === \count($intervals['branches']['names'])) {
            if ($intervals['branches']['exclude']) {
                if ($hasNumericMatchAll) {
                    return new MatchAllConstraint();
                }
            }
        } else {
            foreach ($intervals['branches']['names'] as $branchName) {
                if ($intervals['branches']['exclude']) {
                    $devConstraints[] = new Constraint('!=', $branchName);
                } else {
                    $devConstraints[] = new Constraint('==', $branchName);
                }
            }
            if ($intervals['branches']['exclude']) {
                if (\count($constraints) > 1) {
                    return new MultiConstraint(array_merge(array(new MultiConstraint($constraints, \false)), $devConstraints), \true);
                }
                if (\count($constraints) === 1 && (string) $constraints[0] === (string) Interval::fromZero()) {
                    if (\count($devConstraints) > 1) {
                        return new MultiConstraint($devConstraints, \true);
                    }
                    return $devConstraints[0];
                }
                return new MultiConstraint(array_merge($constraints, $devConstraints), \true);
            }
            $constraints = array_merge($constraints, $devConstraints);
        }
        if (\count($constraints) > 1) {
            return new MultiConstraint($constraints, \false);
        }
        if (\count($constraints) === 1) {
            return $constraints[0];
        }
        return new MatchNoneConstraint();
    }
    /**
    @phpstan-return
    */
    public static function get(ConstraintInterface $constraint)
    {
        $key = (string) $constraint;
        if (!isset(self::$intervalsCache[$key])) {
            self::$intervalsCache[$key] = self::generateIntervals($constraint);
        }
        return self::$intervalsCache[$key];
    }
    /**
    @phpstan-return
    */
    private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = \false)
    {
        if ($constraint instanceof MatchAllConstraint) {
            return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
        }
        if ($constraint instanceof MatchNoneConstraint) {
            return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => \false));
        }
        if ($constraint instanceof Constraint) {
            return self::generateSingleConstraintIntervals($constraint);
        }
        if (!$constraint instanceof MultiConstraint) {
            throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got ' . \get_class($constraint) . '.');
        }
        $constraints = $constraint->getConstraints();
        $numericGroups = array();
        $constraintBranches = array();
        foreach ($constraints as $c) {
            $res = self::get($c);
            $numericGroups[] = $res['numeric'];
            $constraintBranches[] = $res['branches'];
        }
        if ($constraint->isDisjunctive()) {
            $branches = Interval::noDev();
            foreach ($constraintBranches as $b) {
                if ($b['exclude']) {
                    if ($branches['exclude']) {
                        $branches['names'] = array_intersect($branches['names'], $b['names']);
                    } else {
                        $branches['exclude'] = \true;
                        $branches['names'] = array_diff($b['names'], $branches['names']);
                    }
                } else if ($branches['exclude']) {
                    $branches['names'] = array_diff($branches['names'], $b['names']);
                } else {
                    $branches['names'] = array_merge($branches['names'], $b['names']);
                }
            }
        } else {
            $branches = Interval::anyDev();
            foreach ($constraintBranches as $b) {
                if ($b['exclude']) {
                    if ($branches['exclude']) {
                        $branches['names'] = array_merge($branches['names'], $b['names']);
                    } else {
                        $branches['names'] = array_diff($branches['names'], $b['names']);
                    }
                } else if ($branches['exclude']) {
                    $branches['names'] = array_diff($b['names'], $branches['names']);
                    $branches['exclude'] = \false;
                } else {
                    $branches['names'] = array_intersect($branches['names'], $b['names']);
                }
            }
        }
        $branches['names'] = array_unique($branches['names']);
        if (\count($numericGroups) === 1) {
            return array('numeric' => $numericGroups[0], 'branches' => $branches);
        }
        $borders = array();
        foreach ($numericGroups as $group) {
            foreach ($group as $interval) {
                $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start');
                $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end');
            }
        }
        $opSortOrder = self::$opSortOrder;
        usort($borders, function ($a, $b) use ($opSortOrder) {
            $order = version_compare($a['version'], $b['version']);
            if ($order === 0) {
                return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
            }
            return $order;
        });
        $activeIntervals = 0;
        $intervals = array();
        $index = 0;
        $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
        $start = null;
        foreach ($borders as $border) {
            if ($border['side'] === 'start') {
                $activeIntervals++;
            } else {
                $activeIntervals--;
            }
            if (!$start && $activeIntervals >= $activationThreshold) {
                $start = new Constraint($border['operator'], $border['version']);
            } elseif ($start && $activeIntervals < $activationThreshold) {
                if (version_compare($start->getVersion(), $border['version'], '=') && ($start->getOperator() === '>' && $border['operator'] === '<=' || $start->getOperator() === '>=' && $border['operator'] === '<')) {
                    unset($intervals[$index]);
                } else {
                    $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
                    $index++;
                    if ($stopOnFirstValidInterval) {
                        break;
                    }
                }
                $start = null;
            }
        }
        return array('numeric' => $intervals, 'branches' => $branches);
    }
    /**
    @phpstan-return
    */
    private static function generateSingleConstraintIntervals(Constraint $constraint)
    {
        $op = $constraint->getOperator();
        if (strpos($constraint->getVersion(), 'dev-') === 0) {
            $intervals = array();
            $branches = array('names' => array(), 'exclude' => \false);
            if ($op === '!=') {
                $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity());
                $branches = array('names' => array($constraint->getVersion()), 'exclude' => \true);
            } elseif ($op === '==') {
                $branches['names'][] = $constraint->getVersion();
            }
            return array('numeric' => $intervals, 'branches' => $branches);
        }
        if ($op[0] === '>') {
            return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev());
        }
        if ($op[0] === '<') {
            return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev());
        }
        if ($op === '!=') {
            return array('numeric' => array(new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())), new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
        }
        return array('numeric' => array(new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion()))), 'branches' => Interval::noDev());
    }
}
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\Constraint;
class Semver
{
    const SORT_ASC = 1;
    const SORT_DESC = -1;
    private static $versionParser;
    public static function satisfies($version, $constraints)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }
        $versionParser = self::$versionParser;
        $provider = new Constraint('==', $versionParser->normalize($version));
        $parsedConstraints = $versionParser->parseConstraints($constraints);
        return $parsedConstraints->matches($provider);
    }
    public static function satisfiedBy(array $versions, $constraints)
    {
        $versions = array_filter($versions, function ($version) use ($constraints) {
            return Semver::satisfies($version, $constraints);
        });
        return array_values($versions);
    }
    public static function sort(array $versions)
    {
        return self::usort($versions, self::SORT_ASC);
    }
    public static function rsort(array $versions)
    {
        return self::usort($versions, self::SORT_DESC);
    }
    private static function usort(array $versions, $direction)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }
        $versionParser = self::$versionParser;
        $normalized = array();
        foreach ($versions as $key => $version) {
            $normalizedVersion = $versionParser->normalize($version);
            $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion);
            $normalized[] = array($normalizedVersion, $key);
        }
        usort($normalized, function (array $left, array $right) use ($direction) {
            if ($left[0] === $right[0]) {
                return 0;
            }
            if (Comparator::lessThan($left[0], $right[0])) {
                return -$direction;
            }
            return $direction;
        });
        $sorted = array();
        foreach ($normalized as $item) {
            $sorted[] = $versions[$item[1]];
        }
        return $sorted;
    }
}
<?php

namespace HumbugBox468\Composer\Semver;

use HumbugBox468\Composer\Semver\Constraint\ConstraintInterface;
use HumbugBox468\Composer\Semver\Constraint\MatchAllConstraint;
use HumbugBox468\Composer\Semver\Constraint\MultiConstraint;
use HumbugBox468\Composer\Semver\Constraint\Constraint;
class VersionParser
{
    private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
    private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
    /**
    @phpstan-return
    */
    public static function parseStability($version)
    {
        $version = (string) preg_replace('{#.+$}', '', (string) $version);
        if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
            return 'dev';
        }
        preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
        if (!empty($match[3])) {
            return 'dev';
        }
        if (!empty($match[1])) {
            if ('beta' === $match[1] || 'b' === $match[1]) {
                return 'beta';
            }
            if ('alpha' === $match[1] || 'a' === $match[1]) {
                return 'alpha';
            }
            if ('rc' === $match[1]) {
                return 'RC';
            }
        }
        return 'stable';
    }
    public static function normalizeStability($stability)
    {
        $stability = strtolower((string) $stability);
        return $stability === 'rc' ? 'RC' : $stability;
    }
    public function normalize($version, $fullVersion = null)
    {
        $version = trim((string) $version);
        $origVersion = $version;
        if (null === $fullVersion) {
            $fullVersion = $version;
        }
        if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
            $version = $match[1];
        }
        if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
            $version = substr($version, 0, strlen($version) - strlen($match[0]));
        }
        if (\in_array($version, array('master', 'trunk', 'default'), \true)) {
            $version = 'dev-' . $version;
        }
        if (stripos($version, 'dev-') === 0) {
            return 'dev-' . substr($version, 4);
        }
        if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
            $version = $match[1];
        }
        if (preg_match('{^v?(\d{1,5}+)(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0');
            $index = 5;
        } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = (string) preg_replace('{\D}', '.', $matches[1]);
            $index = 2;
        }
        if (isset($index)) {
            if (!empty($matches[$index])) {
                if ('stable' === $matches[$index]) {
                    return $version;
                }
                $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
            }
            if (!empty($matches[$index + 2])) {
                $version .= '-dev';
            }
            return $version;
        }
        if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
            try {
                $normalized = $this->normalizeBranch($match[1]);
                if (strpos($normalized, 'dev-') === \false) {
                    return $normalized;
                }
            } catch (\Exception $e) {
            }
        }
        $extraMessage = '';
        if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))?$}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
        } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))? +as +}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
        }
        throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
    }
    public function parseNumericAliasPrefix($branch)
    {
        if (preg_match('{^(?P<version>(\d++\.)*\d++)(?:\.x)?-dev$}i', (string) $branch, $matches)) {
            return $matches['version'] . '.';
        }
        return \false;
    }
    public function normalizeBranch($name)
    {
        $name = trim((string) $name);
        if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
            $version = '';
            for ($i = 1; $i < 5; ++$i) {
                $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
            }
            return str_replace('x', '9999999', $version) . '-dev';
        }
        return 'dev-' . $name;
    }
    public function normalizeDefaultBranch($name)
    {
        if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') {
            return '9999999-dev';
        }
        return (string) $name;
    }
    public function parseConstraints($constraints)
    {
        $prettyConstraint = (string) $constraints;
        $orConstraints = preg_split('{\s*\|\|?\s*}', trim((string) $constraints));
        if (\false === $orConstraints) {
            throw new \RuntimeException('Failed to preg_split string: ' . $constraints);
        }
        $orGroups = array();
        foreach ($orConstraints as $orConstraint) {
            $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
            if (\false === $andConstraints) {
                throw new \RuntimeException('Failed to preg_split string: ' . $orConstraint);
            }
            if (\count($andConstraints) > 1) {
                $constraintObjects = array();
                foreach ($andConstraints as $andConstraint) {
                    foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
                        $constraintObjects[] = $parsedAndConstraint;
                    }
                }
            } else {
                $constraintObjects = $this->parseConstraint($andConstraints[0]);
            }
            if (1 === \count($constraintObjects)) {
                $constraint = $constraintObjects[0];
            } else {
                $constraint = new MultiConstraint($constraintObjects);
            }
            $orGroups[] = $constraint;
        }
        $parsedConstraint = MultiConstraint::create($orGroups, \false);
        $parsedConstraint->setPrettyString($prettyConstraint);
        return $parsedConstraint;
    }
    /**
    @phpstan-return
    */
    private function parseConstraint($constraint)
    {
        if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
            $constraint = $match[1];
        }
        if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
            $constraint = '' !== $match[1] ? $match[1] : '*';
            if ($match[2] !== 'stable') {
                $stabilityModifier = $match[2];
            }
        }
        if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
            $constraint = $match[1];
        }
        if (preg_match('{^(v)?[xX*](\.[xX*])*$}i', $constraint, $match)) {
            if (!empty($match[1]) || !empty($match[2])) {
                return array(new Constraint('>=', '0.0.0.0-dev'));
            }
            return array(new MatchAllConstraint());
        }
        $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';
        if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
            if (strpos($constraint, '~>') === 0) {
                throw new \UnexpectedValueException('Could not parse version constraint ' . $constraint . ': ' . 'Invalid operator "~>", you probably meant to use the "~" operator');
            }
            if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
                $position = 4;
            } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }
            if (!empty($matches[8])) {
                $position++;
            }
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }
            $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);
            $highPosition = max(1, $position - 1);
            $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);
            return array($lowerBound, $upperBound);
        }
        if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
            if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
                $position = 1;
            } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
                $position = 2;
            } else {
                $position = 3;
            }
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }
            $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);
            return array($lowerBound, $upperBound);
        }
        if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
            if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }
            $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
            if ($lowVersion === '0.0.0.0-dev') {
                return array(new Constraint('<', $highVersion));
            }
            return array(new Constraint('>=', $lowVersion), new Constraint('<', $highVersion));
        }
        if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
            $lowStabilitySuffix = '';
            if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
                $lowStabilitySuffix = '-dev';
            }
            $lowVersion = $this->normalize($matches['from']);
            $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
            $empty = function ($x) {
                return $x === 0 || $x === '0' ? \false : empty($x);
            };
            if (!$empty($matches[12]) && !$empty($matches[13]) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
                $highVersion = $this->normalize($matches['to']);
                $upperBound = new Constraint('<=', $highVersion);
            } else {
                $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
                $this->normalize($matches['to']);
                $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
                $upperBound = new Constraint('<', $highVersion);
            }
            return array($lowerBound, $upperBound);
        }
        if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
            try {
                try {
                    $version = $this->normalize($matches[2]);
                } catch (\UnexpectedValueException $e) {
                    if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
                        $version = $this->normalize('dev-' . substr($matches[2], 0, -4));
                    } else {
                        throw $e;
                    }
                }
                $op = $matches[1] ?: '=';
                if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
                    $version .= '-' . $stabilityModifier;
                } elseif ('<' === $op || '>=' === $op) {
                    if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
                        if (strpos($matches[2], 'dev-') !== 0) {
                            $version .= '-dev';
                        }
                    }
                }
                return array(new Constraint($matches[1] ?: '=', $version));
            } catch (\Exception $e) {
            }
        }
        $message = 'Could not parse version constraint ' . $constraint;
        if (isset($e)) {
            $message .= ': ' . $e->getMessage();
        }
        throw new \UnexpectedValueException($message);
    }
    /**
    @phpstan-param
    */
    private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0')
    {
        for ($i = 4; $i > 0; --$i) {
            if ($i > $position) {
                $matches[$i] = $pad;
            } elseif ($i === $position && $increment) {
                $matches[$i] += $increment;
                if ($matches[$i] < 0) {
                    $matches[$i] = $pad;
                    --$position;
                    if ($i === 1) {
                        return null;
                    }
                }
            }
        }
        return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
    }
    private function expandStability($stability)
    {
        $stability = strtolower($stability);
        switch ($stability) {
            case 'a':
                return 'alpha';
            case 'b':
                return 'beta';
            case 'p':
            case 'pl':
                return 'patch';
            case 'rc':
                return 'RC';
            default:
                return $stability;
        }
    }
}
<?php

// Turn display errors on so we show any code problems
ini_set('display_errors', 1);

if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
    require __DIR__ . '/../vendor/autoload.php';
} else if (file_exists(__DIR__ . '/../../../autoload.php')) {
    require __DIR__ . '/../../../autoload.php';
} else {
    fwrite(STDERR, 'ERROR: Composer dependencies not properly set up! Run "composer install" or see README.md for more details' . PHP_EOL);
    exit(1);
}
$composer = json_decode(file_get_contents(__DIR__ . '/../composer.json'));

// Instantiate app, load commands, and run
$app = new FW\Installer\App($composer->version);
$app->loadCommands(require(__DIR__ . '/../commands.php'));
$app->run();
<?php

use Symfony\Component\Console\Input\{InputArgument,InputOption};

return [
    'setup' => [
        'description' => 'Sets up the current directory for FW apps or updates the FW API',
        'arguments' => [
            ['version', InputArgument::OPTIONAL, 'FW API version to install']
        ],
        'options' => [
            ['directory', 'd', InputOption::VALUE_REQUIRED, 'Install directory'],
            ['webroot', 'w', InputOption::VALUE_REQUIRED, 'Webroot directory'],
            ['migrate', 'm', InputOption::VALUE_NONE, 'Migrate from pre-1.0 setup'],
            ['production', 'p', InputOption::VALUE_NONE, 'Set production mode for api'],
            ['update', 'u', InputOption::VALUE_NONE, 'Update the installation'],
            ['force', 'f', InputOption::VALUE_NONE, 'Force an update'],
            ['rollback', 'r', InputOption::VALUE_NONE, 'Rollback to an older version of the installation']
        ]
    ],
    'install' => [
        'description' => 'Installs an FW app, or installs addons in an app folder',
        'arguments' => [
            ['app', InputArgument::OPTIONAL, 'App to install'],
            ['version', InputArgument::OPTIONAL, 'Version of app to install or app git URL']
        ],
        'options' => [
            ['webroot', 'w', InputOption::VALUE_REQUIRED, 'Webroot directory'],
            ['url', 'u', InputOption::VALUE_REQUIRED, 'Url of app (after base domain)'],
            ['force', 'f', InputOption::VALUE_NONE, 'Force installation (ignore if app is already installed)'],
            ['config', 'c', InputOption::VALUE_NONE, 'Runs the install.php script to generate config']
        ],
        'aliases' => 'i'
    ],
    'update' => [
        'description' => 'Updates an FW app',
        'arguments' => [
            ['app', InputArgument::OPTIONAL, 'App to update'],
            ['version', InputArgument::OPTIONAL, 'Version of app to update to'],
        ],
        'options' => [
            ['force', 'f', InputOption::VALUE_NONE, 'Force an update'],
            ['rollback', 'r', InputOption::VALUE_NONE, 'Rollback to an older version']
        ],
        'aliases' => 'u'
    ],
    'login' => [
        'description' => 'Logs into a Git provider',
        'arguments' => [
            ['provider', InputArgument::REQUIRED, 'Provider to login with']
        ]
    ],
    'task' => [
        'description' => 'Runs an FW task, primarily used internally',
        'arguments' => [
            ['taskName', InputArgument::REQUIRED, 'Task to run']
        ],
        'options' => [
            ['undo', 'u', InputOption::VALUE_NONE, 'Undo a task']
        ]
    ],
    'publish' => [
        'description' => 'Publishes an app or addon to the FW registry'
    ],
    'self-update' => [
        'description' => 'Updates the FW installer to the latest version',
        'options' => [
            ['rollback', 'r', InputOption::VALUE_NONE, 'Rollback to previous installer version']
        ],
        'aliases' => 'selfupdate'
    ]
];
{
    "name": "linformatics/fw-installer",
    "version": "1.0.12",
    "description": "A command-line installer for FW-Api and its requisite apps/addons",
    "minimum-stability": "stable",
       "repositories": [
      {
        "type": "vcs",
        "url": "https://github.com/bennerlibrary/Stringy"
      }
    ],
    "require": {
      "php": ">=8.2",
      "symfony/console": "^6.0",
      "symfony/filesystem": "^6.0",
      "symfony/finder": "^2.6",
      "composer/semver": "^1.4",
      "symfony/process": "^6.0",
      "symfony/event-dispatcher": "^6.0",
      "bit3/git-php": "dev-release/1.6.0",
      "bennerinformatics/stringy": "^6.5",
      "jakeasmith/http_build_url": "^1.0",
      "weew/helpers-array": "^1.3",
      "guzzlehttp/guzzle": "^7.8",
      "bennerinformatics/php-path": "^0.1.0",
      "php-parallel-lint/php-console-highlighter": "^1.0"
    },
    "require-dev": {
      "phpunit/phpunit": "^11.0",
      "squizlabs/php_codesniffer": "^2.8.1",
      "php-parallel-lint/php-parallel-lint": "^1.4"
    },
    "license": "MIT",
    "authors": [
      {
        "name": "Austin Burdine",
        "email": "acburdine@gmail.com"
      }
    ],
    "bin": ["bin/fw"],
    "autoload": {
      "psr-4": {"FW\\Installer\\": "src"}
    },
    "scripts": {
      "build": "composer install -o --no-dev && box compile",
      "test": [
        "@lint",
        "@style",
        "phpunit --colors=always"
      ],
      "lint": "parallel-lint --exclude vendor --exclude standards --exclude docs .",
      "style": "phpcs --colors --standard=./standards/fw_phpcs ./src/",
      "style-fix": "phpcbf --standard=./standards/fw_phpcs ./src/"
    }
}
{
    "_readme": [
        "This file locks the dependencies of your project to a known state",
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
        "This file is @generated automatically"
    ],
    "content-hash": "5dae2486cad8dbba116bd58d2a8a9c33",
    "packages": [
        {
            "name": "bennerinformatics/php-path",
            "version": "0.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/BennerInformatics/php-path.git",
                "reference": "32f222ff07148e48380f84122e1bd4b4fd01c4ad"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/BennerInformatics/php-path/zipball/32f222ff07148e48380f84122e1bd4b4fd01c4ad",
                "reference": "32f222ff07148e48380f84122e1bd4b4fd01c4ad",
                "shasum": ""
            },
            "require": {
                "php": ">= 7.0.0"
            },
            "require-dev": {
                "jakub-onderka/php-console-highlighter": "^0.3.2",
                "jakub-onderka/php-parallel-lint": "^0.9.2",
                "phpunit/phpunit": "^6.1",
                "squizlabs/php_codesniffer": "^2.8"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "path.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Austin Burdine",
                    "email": "acburdine@gmail.com"
                }
            ],
            "description": "Set of PHP functions designed to make working with filepaths easier",
            "support": {
                "issues": "https://github.com/BennerInformatics/php-path/issues",
                "source": "https://github.com/BennerInformatics/php-path/tree/master"
            },
            "time": "2017-04-27T21:46:57+00:00"
        },
        {
            "name": "bennerinformatics/stringy",
            "version": "6.5.4",
            "source": {
                "type": "git",
                "url": "https://github.com/bennerlibrary/Stringy.git",
                "reference": "fbbad81f8320d39e6918998978a3934257f52b77"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/bennerlibrary/Stringy/zipball/fbbad81f8320d39e6918998978a3934257f52b77",
                "reference": "fbbad81f8320d39e6918998978a3934257f52b77",
                "shasum": ""
            },
            "require": {
                "defuse/php-encryption": "~2.0",
                "ext-json": "*",
                "php": ">=7.0.0",
                "voku/anti-xss": "~4.1",
                "voku/arrayy": "~7.8",
                "voku/email-check": "~3.1",
                "voku/portable-ascii": "~2.0",
                "voku/portable-utf8": "~6.0",
                "voku/urlify": "~5.0"
            },
            "replace": {
                "danielstjules/stringy": "~3.0",
                "voku/stringy": "*"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Stringy\\": "src/"
                },
                "files": [
                    "src/Create.php"
                ]
            },
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Daniel St. Jules",
                    "email": "danielst.jules@gmail.com",
                    "homepage": "http://www.danielstjules.com",
                    "role": "Maintainer"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/",
                    "role": "Fork-Maintainer"
                }
            ],
            "description": "A string manipulation library with multibyte support",
            "homepage": "https://github.com/danielstjules/Stringy",
            "keywords": [
                "helpers",
                "manipulation",
                "methods",
                "multibyte",
                "string",
                "utf",
                "utf-8",
                "utility",
                "utils"
            ],
            "support": {
                "issues": "https://github.com/voku/Stringy/issues",
                "source": "https://github.com/voku/Stringy"
            },
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/voku"
                },
                {
                    "type": "patreon",
                    "url": "https://www.patreon.com/voku"
                },
                {
                    "type": "tidelift",
                    "url": "https://tidelift.com/funding/github/packagist/voku/stringy"
                },
                {
                    "type": "custom",
                    "url": "https://www.paypal.me/moelleken"
                }
            ],
            "time": "2026-02-17T20:57:56+00:00"
        },
        {
            "name": "bit3/git-php",
            "version": "dev-release/1.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/bit3/git-php.git",
                "reference": "4f733e1e514fb9a6b352eaa18db5fba06957ab9d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/bit3/git-php/zipball/4f733e1e514fb9a6b352eaa18db5fba06957ab9d",
                "reference": "4f733e1e514fb9a6b352eaa18db5fba06957ab9d",
                "shasum": ""
            },
            "require": {
                "php": "^7.4 || ^8.0",
                "psr/log": "^1.0 || ^2.0 || ^3.0",
                "symfony/process": "^4.0 || ^5.0 || ^6.0"
            },
            "require-dev": {
                "phpcq/runner-bootstrap": "^1.0@dev",
                "symfony/filesystem": "^4.0 || ^5.0 || ^6.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-release/1.6.0": "1.6.0-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Bit3\\GitPhp\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "Easy to use GIT wrapper for PHP.",
            "support": {
                "issues": "https://github.com/bit3/git-php/issues",
                "source": "https://github.com/bit3/git-php/tree/release/1.6.0"
            },
            "time": "2023-08-16T09:46:28+00:00"
        },
        {
            "name": "composer/semver",
            "version": "1.7.2",
            "source": {
                "type": "git",
                "url": "https://github.com/composer/semver.git",
                "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/composer/semver/zipball/647490bbcaf7fc4891c58f47b825eb99d19c377a",
                "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a",
                "shasum": ""
            },
            "require": {
                "php": "^5.3.2 || ^7.0 || ^8.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^4.5 || ^5.0.5"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Composer\\Semver\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nils Adermann",
                    "email": "naderman@naderman.de",
                    "homepage": "http://www.naderman.de"
                },
                {
                    "name": "Jordi Boggiano",
                    "email": "j.boggiano@seld.be",
                    "homepage": "http://seld.be"
                },
                {
                    "name": "Rob Bast",
                    "email": "rob.bast@gmail.com",
                    "homepage": "http://robbast.nl"
                }
            ],
            "description": "Semver library that offers utilities, version constraint parsing and validation.",
            "keywords": [
                "semantic",
                "semver",
                "validation",
                "versioning"
            ],
            "support": {
                "irc": "irc://irc.freenode.org/composer",
                "issues": "https://github.com/composer/semver/issues",
                "source": "https://github.com/composer/semver/tree/1.7.2"
            },
            "funding": [
                {
                    "url": "https://packagist.com",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/composer",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
                    "type": "tidelift"
                }
            ],
            "time": "2020-12-03T15:47:16+00:00"
        },
        {
            "name": "defuse/php-encryption",
            "version": "v2.4.0",
            "source": {
                "type": "git",
                "url": "https://github.com/defuse/php-encryption.git",
                "reference": "f53396c2d34225064647a05ca76c1da9d99e5828"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/defuse/php-encryption/zipball/f53396c2d34225064647a05ca76c1da9d99e5828",
                "reference": "f53396c2d34225064647a05ca76c1da9d99e5828",
                "shasum": ""
            },
            "require": {
                "ext-openssl": "*",
                "paragonie/random_compat": ">= 2",
                "php": ">=5.6.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^5|^6|^7|^8|^9|^10",
                "yoast/phpunit-polyfills": "^2.0.0"
            },
            "bin": [
                "bin/generate-defuse-key"
            ],
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Defuse\\Crypto\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Taylor Hornby",
                    "email": "taylor@defuse.ca",
                    "homepage": "https://defuse.ca/"
                },
                {
                    "name": "Scott Arciszewski",
                    "email": "info@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "Secure PHP Encryption Library",
            "keywords": [
                "aes",
                "authenticated encryption",
                "cipher",
                "crypto",
                "cryptography",
                "encrypt",
                "encryption",
                "openssl",
                "security",
                "symmetric key cryptography"
            ],
            "support": {
                "issues": "https://github.com/defuse/php-encryption/issues",
                "source": "https://github.com/defuse/php-encryption/tree/v2.4.0"
            },
            "time": "2023-06-19T06:10:36+00:00"
        },
        {
            "name": "doctrine/deprecations",
            "version": "1.1.5",
            "source": {
                "type": "git",
                "url": "https://github.com/doctrine/deprecations.git",
                "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
                "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
                "shasum": ""
            },
            "require": {
                "php": "^7.1 || ^8.0"
            },
            "conflict": {
                "phpunit/phpunit": "<=7.5 || >=13"
            },
            "require-dev": {
                "doctrine/coding-standard": "^9 || ^12 || ^13",
                "phpstan/phpstan": "1.4.10 || 2.1.11",
                "phpstan/phpstan-phpunit": "^1.0 || ^2",
                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
                "psr/log": "^1 || ^2 || ^3"
            },
            "suggest": {
                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Doctrine\\Deprecations\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
            "homepage": "https://www.doctrine-project.org/",
            "support": {
                "issues": "https://github.com/doctrine/deprecations/issues",
                "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
            },
            "time": "2025-04-07T20:06:18+00:00"
        },
        {
            "name": "guzzlehttp/guzzle",
            "version": "7.10.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/guzzle.git",
                "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
                "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "guzzlehttp/promises": "^2.3",
                "guzzlehttp/psr7": "^2.8",
                "php": "^7.2.5 || ^8.0",
                "psr/http-client": "^1.0",
                "symfony/deprecation-contracts": "^2.2 || ^3.0"
            },
            "provide": {
                "psr/http-client-implementation": "1.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "ext-curl": "*",
                "guzzle/client-integration-tests": "3.0.2",
                "php-http/message-factory": "^1.1",
                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                "psr/log": "^1.1 || ^2.0 || ^3.0"
            },
            "suggest": {
                "ext-curl": "Required for CURL handler support",
                "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                "psr/log": "Required for using the Log middleware"
            },
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "autoload": {
                "files": [
                    "src/functions_include.php"
                ],
                "psr-4": {
                    "GuzzleHttp\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "Jeremy Lindblom",
                    "email": "jeremeamia@gmail.com",
                    "homepage": "https://github.com/jeremeamia"
                },
                {
                    "name": "George Mponos",
                    "email": "gmponos@gmail.com",
                    "homepage": "https://github.com/gmponos"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://github.com/sagikazarmark"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                }
            ],
            "description": "Guzzle is a PHP HTTP client library",
            "keywords": [
                "client",
                "curl",
                "framework",
                "http",
                "http client",
                "psr-18",
                "psr-7",
                "rest",
                "web service"
            ],
            "support": {
                "issues": "https://github.com/guzzle/guzzle/issues",
                "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-23T22:36:01+00:00"
        },
        {
            "name": "guzzlehttp/promises",
            "version": "2.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/promises.git",
                "reference": "481557b130ef3790cf82b713667b43030dc9c957"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
                "reference": "481557b130ef3790cf82b713667b43030dc9c957",
                "shasum": ""
            },
            "require": {
                "php": "^7.2.5 || ^8.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "phpunit/phpunit": "^8.5.44 || ^9.6.25"
            },
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "autoload": {
                "psr-4": {
                    "GuzzleHttp\\Promise\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                }
            ],
            "description": "Guzzle promises library",
            "keywords": [
                "promise"
            ],
            "support": {
                "issues": "https://github.com/guzzle/promises/issues",
                "source": "https://github.com/guzzle/promises/tree/2.3.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-22T14:34:08+00:00"
        },
        {
            "name": "guzzlehttp/psr7",
            "version": "2.8.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/psr7.git",
                "reference": "21dc724a0583619cd1652f673303492272778051"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
                "reference": "21dc724a0583619cd1652f673303492272778051",
                "shasum": ""
            },
            "require": {
                "php": "^7.2.5 || ^8.0",
                "psr/http-factory": "^1.0",
                "psr/http-message": "^1.1 || ^2.0",
                "ralouphie/getallheaders": "^3.0"
            },
            "provide": {
                "psr/http-factory-implementation": "1.0",
                "psr/http-message-implementation": "1.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "http-interop/http-factory-tests": "0.9.0",
                "phpunit/phpunit": "^8.5.44 || ^9.6.25"
            },
            "suggest": {
                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
            },
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "autoload": {
                "psr-4": {
                    "GuzzleHttp\\Psr7\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "George Mponos",
                    "email": "gmponos@gmail.com",
                    "homepage": "https://github.com/gmponos"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://github.com/sagikazarmark"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://sagikazarmark.hu"
                }
            ],
            "description": "PSR-7 message implementation that also provides common utility methods",
            "keywords": [
                "http",
                "message",
                "psr-7",
                "request",
                "response",
                "stream",
                "uri",
                "url"
            ],
            "support": {
                "issues": "https://github.com/guzzle/psr7/issues",
                "source": "https://github.com/guzzle/psr7/tree/2.8.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-23T21:21:41+00:00"
        },
        {
            "name": "jakeasmith/http_build_url",
            "version": "1.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/jakeasmith/http_build_url.git",
                "reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/jakeasmith/http_build_url/zipball/93c273e77cb1edead0cf8bcf8cd2003428e74e37",
                "reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37",
                "shasum": ""
            },
            "type": "library",
            "autoload": {
                "files": [
                    "src/http_build_url.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jake A. Smith",
                    "email": "theman@jakeasmith.com"
                }
            ],
            "description": "Provides functionality for http_build_url() to environments without pecl_http.",
            "support": {
                "issues": "https://github.com/jakeasmith/http_build_url/issues",
                "source": "https://github.com/jakeasmith/http_build_url"
            },
            "time": "2017-05-01T15:36:40+00:00"
        },
        {
            "name": "paragonie/random_compat",
            "version": "v9.99.100",
            "source": {
                "type": "git",
                "url": "https://github.com/paragonie/random_compat.git",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "shasum": ""
            },
            "require": {
                "php": ">= 7"
            },
            "require-dev": {
                "phpunit/phpunit": "4.*|5.*",
                "vimeo/psalm": "^1"
            },
            "suggest": {
                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
            },
            "type": "library",
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Paragon Initiative Enterprises",
                    "email": "security@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
            "keywords": [
                "csprng",
                "polyfill",
                "pseudorandom",
                "random"
            ],
            "support": {
                "email": "info@paragonie.com",
                "issues": "https://github.com/paragonie/random_compat/issues",
                "source": "https://github.com/paragonie/random_compat"
            },
            "time": "2020-10-15T08:29:30+00:00"
        },
        {
            "name": "php-parallel-lint/php-console-color",
            "version": "v1.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/php-parallel-lint/PHP-Console-Color.git",
                "reference": "7adfefd530aa2d7570ba87100a99e2483a543b88"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Color/zipball/7adfefd530aa2d7570ba87100a99e2483a543b88",
                "reference": "7adfefd530aa2d7570ba87100a99e2483a543b88",
                "shasum": ""
            },
            "require": {
                "php": ">=5.3.2"
            },
            "replace": {
                "jakub-onderka/php-console-color": "*"
            },
            "require-dev": {
                "php-parallel-lint/php-code-style": "^2.0",
                "php-parallel-lint/php-parallel-lint": "^1.0",
                "php-parallel-lint/php-var-dump-check": "0.*",
                "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "PHP_Parallel_Lint\\PhpConsoleColor\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-2-Clause"
            ],
            "authors": [
                {
                    "name": "Jakub Onderka",
                    "email": "jakub.onderka@gmail.com"
                }
            ],
            "description": "Simple library for creating colored console ouput.",
            "support": {
                "issues": "https://github.com/php-parallel-lint/PHP-Console-Color/issues",
                "source": "https://github.com/php-parallel-lint/PHP-Console-Color/tree/v1.0.1"
            },
            "time": "2021-12-25T06:49:29+00:00"
        },
        {
            "name": "php-parallel-lint/php-console-highlighter",
            "version": "v1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-parallel-lint/PHP-Console-Highlighter.git",
                "reference": "5b4803384d3303cf8e84141039ef56c8a123138d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Highlighter/zipball/5b4803384d3303cf8e84141039ef56c8a123138d",
                "reference": "5b4803384d3303cf8e84141039ef56c8a123138d",
                "shasum": ""
            },
            "require": {
                "ext-tokenizer": "*",
                "php": ">=5.3.2",
                "php-parallel-lint/php-console-color": "^1.0.1"
            },
            "replace": {
                "jakub-onderka/php-console-highlighter": "*"
            },
            "require-dev": {
                "php-parallel-lint/php-code-style": "^2.0",
                "php-parallel-lint/php-parallel-lint": "^1.0",
                "php-parallel-lint/php-var-dump-check": "0.*",
                "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "PHP_Parallel_Lint\\PhpConsoleHighlighter\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jakub Onderka",
                    "email": "acci@acci.cz",
                    "homepage": "http://www.acci.cz/"
                }
            ],
            "description": "Highlight PHP code in terminal",
            "support": {
                "issues": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/issues",
                "source": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/tree/v1.0.0"
            },
            "time": "2022-02-18T08:23:19+00:00"
        },
        {
            "name": "phpdocumentor/reflection-common",
            "version": "2.2.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
                "shasum": ""
            },
            "require": {
                "php": "^7.2 || ^8.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-2.x": "2.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jaap van Otterdijk",
                    "email": "opensource@ijaap.nl"
                }
            ],
            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
            "homepage": "http://www.phpdoc.org",
            "keywords": [
                "FQSEN",
                "phpDocumentor",
                "phpdoc",
                "reflection",
                "static analysis"
            ],
            "support": {
                "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
                "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
            },
            "time": "2020-06-27T09:03:43+00:00"
        },
        {
            "name": "phpdocumentor/reflection-docblock",
            "version": "5.6.3",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
                "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9",
                "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9",
                "shasum": ""
            },
            "require": {
                "doctrine/deprecations": "^1.1",
                "ext-filter": "*",
                "php": "^7.4 || ^8.0",
                "phpdocumentor/reflection-common": "^2.2",
                "phpdocumentor/type-resolver": "^1.7",
                "phpstan/phpdoc-parser": "^1.7|^2.0",
                "webmozart/assert": "^1.9.1"
            },
            "require-dev": {
                "mockery/mockery": "~1.3.5 || ~1.6.0",
                "phpstan/extension-installer": "^1.1",
                "phpstan/phpstan": "^1.8",
                "phpstan/phpstan-mockery": "^1.1",
                "phpstan/phpstan-webmozart-assert": "^1.2",
                "phpunit/phpunit": "^9.5",
                "psalm/phar": "^5.26"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "5.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Mike van Riel",
                    "email": "me@mikevanriel.com"
                },
                {
                    "name": "Jaap van Otterdijk",
                    "email": "opensource@ijaap.nl"
                }
            ],
            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
            "support": {
                "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
                "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3"
            },
            "time": "2025-08-01T19:43:32+00:00"
        },
        {
            "name": "phpdocumentor/type-resolver",
            "version": "1.10.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/TypeResolver.git",
                "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
                "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
                "shasum": ""
            },
            "require": {
                "doctrine/deprecations": "^1.0",
                "php": "^7.3 || ^8.0",
                "phpdocumentor/reflection-common": "^2.0",
                "phpstan/phpdoc-parser": "^1.18|^2.0"
            },
            "require-dev": {
                "ext-tokenizer": "*",
                "phpbench/phpbench": "^1.2",
                "phpstan/extension-installer": "^1.1",
                "phpstan/phpstan": "^1.8",
                "phpstan/phpstan-phpunit": "^1.1",
                "phpunit/phpunit": "^9.5",
                "rector/rector": "^0.13.9",
                "vimeo/psalm": "^4.25"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-1.x": "1.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Mike van Riel",
                    "email": "me@mikevanriel.com"
                }
            ],
            "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
            "support": {
                "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
                "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
            },
            "time": "2024-11-09T15:12:26+00:00"
        },
        {
            "name": "phpstan/phpdoc-parser",
            "version": "2.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpstan/phpdoc-parser.git",
                "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495",
                "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495",
                "shasum": ""
            },
            "require": {
                "php": "^7.4 || ^8.0"
            },
            "require-dev": {
                "doctrine/annotations": "^2.0",
                "nikic/php-parser": "^5.3.0",
                "php-parallel-lint/php-parallel-lint": "^1.2",
                "phpstan/extension-installer": "^1.0",
                "phpstan/phpstan": "^2.0",
                "phpstan/phpstan-phpunit": "^2.0",
                "phpstan/phpstan-strict-rules": "^2.0",
                "phpunit/phpunit": "^9.6",
                "symfony/process": "^5.2"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "PHPStan\\PhpDocParser\\": [
                        "src/"
                    ]
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "PHPDoc parser with support for nullable, intersection and generic types",
            "support": {
                "issues": "https://github.com/phpstan/phpdoc-parser/issues",
                "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0"
            },
            "time": "2025-08-30T15:50:23+00:00"
        },
        {
            "name": "psr/container",
            "version": "2.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/container.git",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "shasum": ""
            },
            "require": {
                "php": ">=7.4.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Container\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common Container Interface (PHP FIG PSR-11)",
            "homepage": "https://github.com/php-fig/container",
            "keywords": [
                "PSR-11",
                "container",
                "container-interface",
                "container-interop",
                "psr"
            ],
            "support": {
                "issues": "https://github.com/php-fig/container/issues",
                "source": "https://github.com/php-fig/container/tree/2.0.2"
            },
            "time": "2021-11-05T16:47:00+00:00"
        },
        {
            "name": "psr/event-dispatcher",
            "version": "1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/event-dispatcher.git",
                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\EventDispatcher\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "http://www.php-fig.org/"
                }
            ],
            "description": "Standard interfaces for event handling.",
            "keywords": [
                "events",
                "psr",
                "psr-14"
            ],
            "support": {
                "issues": "https://github.com/php-fig/event-dispatcher/issues",
                "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
            },
            "time": "2019-01-08T18:20:26+00:00"
        },
        {
            "name": "psr/http-client",
            "version": "1.0.3",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-client.git",
                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
                "shasum": ""
            },
            "require": {
                "php": "^7.0 || ^8.0",
                "psr/http-message": "^1.0 || ^2.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Client\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for HTTP clients",
            "homepage": "https://github.com/php-fig/http-client",
            "keywords": [
                "http",
                "http-client",
                "psr",
                "psr-18"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-client"
            },
            "time": "2023-09-23T14:17:50+00:00"
        },
        {
            "name": "psr/http-factory",
            "version": "1.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-factory.git",
                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                "shasum": ""
            },
            "require": {
                "php": ">=7.1",
                "psr/http-message": "^1.0 || ^2.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Message\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
            "keywords": [
                "factory",
                "http",
                "message",
                "psr",
                "psr-17",
                "psr-7",
                "request",
                "response"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-factory"
            },
            "time": "2024-04-15T12:06:14+00:00"
        },
        {
            "name": "psr/http-message",
            "version": "2.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-message.git",
                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
                "shasum": ""
            },
            "require": {
                "php": "^7.2 || ^8.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Message\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for HTTP messages",
            "homepage": "https://github.com/php-fig/http-message",
            "keywords": [
                "http",
                "http-message",
                "psr",
                "psr-7",
                "request",
                "response"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-message/tree/2.0"
            },
            "time": "2023-04-04T09:54:51+00:00"
        },
        {
            "name": "psr/log",
            "version": "3.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/log.git",
                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
                "shasum": ""
            },
            "require": {
                "php": ">=8.0.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "3.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Log\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for logging libraries",
            "homepage": "https://github.com/php-fig/log",
            "keywords": [
                "log",
                "psr",
                "psr-3"
            ],
            "support": {
                "source": "https://github.com/php-fig/log/tree/3.0.2"
            },
            "time": "2024-09-11T13:17:53+00:00"
        },
        {
            "name": "ralouphie/getallheaders",
            "version": "3.0.3",
            "source": {
                "type": "git",
                "url": "https://github.com/ralouphie/getallheaders.git",
                "reference": "120b605dfeb996808c31b6477290a714d356e822"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
                "reference": "120b605dfeb996808c31b6477290a714d356e822",
                "shasum": ""
            },
            "require": {
                "php": ">=5.6"
            },
            "require-dev": {
                "php-coveralls/php-coveralls": "^2.1",
                "phpunit/phpunit": "^5 || ^6.5"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "src/getallheaders.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Ralph Khattar",
                    "email": "ralph.khattar@gmail.com"
                }
            ],
            "description": "A polyfill for getallheaders.",
            "support": {
                "issues": "https://github.com/ralouphie/getallheaders/issues",
                "source": "https://github.com/ralouphie/getallheaders/tree/develop"
            },
            "time": "2019-03-08T08:55:37+00:00"
        },
        {
            "name": "symfony/console",
            "version": "v6.4.26",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/console.git",
                "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
                "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/deprecation-contracts": "^2.5|^3",
                "symfony/polyfill-mbstring": "~1.0",
                "symfony/service-contracts": "^2.5|^3",
                "symfony/string": "^5.4|^6.0|^7.0"
            },
            "conflict": {
                "symfony/dependency-injection": "<5.4",
                "symfony/dotenv": "<5.4",
                "symfony/event-dispatcher": "<5.4",
                "symfony/lock": "<5.4",
                "symfony/process": "<5.4"
            },
            "provide": {
                "psr/log-implementation": "1.0|2.0|3.0"
            },
            "require-dev": {
                "psr/log": "^1|^2|^3",
                "symfony/config": "^5.4|^6.0|^7.0",
                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
                "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
                "symfony/http-foundation": "^6.4|^7.0",
                "symfony/http-kernel": "^6.4|^7.0",
                "symfony/lock": "^5.4|^6.0|^7.0",
                "symfony/messenger": "^5.4|^6.0|^7.0",
                "symfony/process": "^5.4|^6.0|^7.0",
                "symfony/stopwatch": "^5.4|^6.0|^7.0",
                "symfony/var-dumper": "^5.4|^6.0|^7.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Console\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Eases the creation of beautiful and testable command line interfaces",
            "homepage": "https://symfony.com",
            "keywords": [
                "cli",
                "command-line",
                "console",
                "terminal"
            ],
            "support": {
                "source": "https://github.com/symfony/console/tree/v6.4.26"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-09-26T12:13:46+00:00"
        },
        {
            "name": "symfony/deprecation-contracts",
            "version": "v3.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/deprecation-contracts.git",
                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "autoload": {
                "files": [
                    "function.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "A generic function and convention to trigger deprecation notices",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-25T14:21:43+00:00"
        },
        {
            "name": "symfony/event-dispatcher",
            "version": "v6.4.25",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/event-dispatcher.git",
                "reference": "b0cf3162020603587363f0551cd3be43958611ff"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff",
                "reference": "b0cf3162020603587363f0551cd3be43958611ff",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/event-dispatcher-contracts": "^2.5|^3"
            },
            "conflict": {
                "symfony/dependency-injection": "<5.4",
                "symfony/service-contracts": "<2.5"
            },
            "provide": {
                "psr/event-dispatcher-implementation": "1.0",
                "symfony/event-dispatcher-implementation": "2.0|3.0"
            },
            "require-dev": {
                "psr/log": "^1|^2|^3",
                "symfony/config": "^5.4|^6.0|^7.0",
                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
                "symfony/error-handler": "^5.4|^6.0|^7.0",
                "symfony/expression-language": "^5.4|^6.0|^7.0",
                "symfony/http-foundation": "^5.4|^6.0|^7.0",
                "symfony/service-contracts": "^2.5|^3",
                "symfony/stopwatch": "^5.4|^6.0|^7.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\EventDispatcher\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-13T09:41:44+00:00"
        },
        {
            "name": "symfony/event-dispatcher-contracts",
            "version": "v3.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/event-dispatcher-contracts.git",
                "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
                "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "psr/event-dispatcher": "^1"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Symfony\\Contracts\\EventDispatcher\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Generic abstractions related to dispatching event",
            "homepage": "https://symfony.com",
            "keywords": [
                "abstractions",
                "contracts",
                "decoupling",
                "interfaces",
                "interoperability",
                "standards"
            ],
            "support": {
                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-25T14:21:43+00:00"
        },
        {
            "name": "symfony/filesystem",
            "version": "v6.4.24",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/filesystem.git",
                "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
                "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/polyfill-ctype": "~1.8",
                "symfony/polyfill-mbstring": "~1.8"
            },
            "require-dev": {
                "symfony/process": "^5.4|^6.4|^7.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Filesystem\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides basic utilities for the filesystem",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/filesystem/tree/v6.4.24"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-07-10T08:14:14+00:00"
        },
        {
            "name": "symfony/finder",
            "version": "v2.8.52",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/finder.git",
                "reference": "1444eac52273e345d9b95129bf914639305a9ba4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/finder/zipball/1444eac52273e345d9b95129bf914639305a9ba4",
                "reference": "1444eac52273e345d9b95129bf914639305a9ba4",
                "shasum": ""
            },
            "require": {
                "php": ">=5.3.9"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.8-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Finder\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony Finder Component",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/finder/tree/v2.8.50"
            },
            "time": "2018-11-11T11:18:13+00:00"
        },
        {
            "name": "symfony/polyfill-ctype",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-ctype.git",
                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "provide": {
                "ext-ctype": "*"
            },
            "suggest": {
                "ext-ctype": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Ctype\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Gert de Pagter",
                    "email": "BackEndTea@gmail.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for ctype functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "ctype",
                "polyfill",
                "portable"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-09T11:45:10+00:00"
        },
        {
            "name": "symfony/polyfill-iconv",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-iconv.git",
                "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
                "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "provide": {
                "ext-iconv": "*"
            },
            "suggest": {
                "ext-iconv": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Iconv\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for the Iconv extension",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "iconv",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-17T14:58:18+00:00"
        },
        {
            "name": "symfony/polyfill-intl-grapheme",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
                "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
                "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's grapheme_* functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "grapheme",
                "intl",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-06-27T09:58:17+00:00"
        },
        {
            "name": "symfony/polyfill-intl-idn",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-idn.git",
                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2",
                "symfony/polyfill-intl-normalizer": "^1.10"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Idn\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Laurent Bassin",
                    "email": "laurent@bassin.info"
                },
                {
                    "name": "Trevor Rowbotham",
                    "email": "trevor.rowbotham@pm.me"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "idn",
                "intl",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-10T14:38:51+00:00"
        },
        {
            "name": "symfony/polyfill-intl-normalizer",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
                "reference": "3833d7255cc303546435cb650316bff708a1c75c"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
                "reference": "3833d7255cc303546435cb650316bff708a1c75c",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
                },
                "classmap": [
                    "Resources/stubs"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's Normalizer class and related functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "intl",
                "normalizer",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-09T11:45:10+00:00"
        },
        {
            "name": "symfony/polyfill-mbstring",
            "version": "v1.33.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-mbstring.git",
                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
                "shasum": ""
            },
            "require": {
                "ext-iconv": "*",
                "php": ">=7.2"
            },
            "provide": {
                "ext-mbstring": "*"
            },
            "suggest": {
                "ext-mbstring": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Mbstring\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for the Mbstring extension",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "mbstring",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-12-23T08:48:59+00:00"
        },
        {
            "name": "symfony/polyfill-php72",
            "version": "v1.31.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-php72.git",
                "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
                "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "type": "metapackage",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2024-09-09T11:45:10+00:00"
        },
        {
            "name": "symfony/process",
            "version": "v6.4.26",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/process.git",
                "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
                "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Process\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Executes commands in sub-processes",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/process/tree/v6.4.26"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-09-11T09:57:09+00:00"
        },
        {
            "name": "symfony/service-contracts",
            "version": "v3.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/service-contracts.git",
                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "psr/container": "^1.1|^2.0",
                "symfony/deprecation-contracts": "^2.5|^3"
            },
            "conflict": {
                "ext-psr": "<1.1|>=2"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Symfony\\Contracts\\Service\\": ""
                },
                "exclude-from-classmap": [
                    "/Test/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Generic abstractions related to writing services",
            "homepage": "https://symfony.com",
            "keywords": [
                "abstractions",
                "contracts",
                "decoupling",
                "interfaces",
                "interoperability",
                "standards"
            ],
            "support": {
                "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-04-25T09:37:31+00:00"
        },
        {
            "name": "symfony/string",
            "version": "v7.3.4",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/string.git",
                "reference": "f96476035142921000338bad71e5247fbc138872"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
                "reference": "f96476035142921000338bad71e5247fbc138872",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2",
                "symfony/polyfill-ctype": "~1.8",
                "symfony/polyfill-intl-grapheme": "~1.0",
                "symfony/polyfill-intl-normalizer": "~1.0",
                "symfony/polyfill-mbstring": "~1.0"
            },
            "conflict": {
                "symfony/translation-contracts": "<2.5"
            },
            "require-dev": {
                "symfony/emoji": "^7.1",
                "symfony/http-client": "^6.4|^7.0",
                "symfony/intl": "^6.4|^7.0",
                "symfony/translation-contracts": "^2.5|^3.0",
                "symfony/var-exporter": "^6.4|^7.0"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "Resources/functions.php"
                ],
                "psr-4": {
                    "Symfony\\Component\\String\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
            "homepage": "https://symfony.com",
            "keywords": [
                "grapheme",
                "i18n",
                "string",
                "unicode",
                "utf-8",
                "utf8"
            ],
            "support": {
                "source": "https://github.com/symfony/string/tree/v7.3.4"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2025-09-11T14:36:48+00:00"
        },
        {
            "name": "voku/anti-xss",
            "version": "4.1.42",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/anti-xss.git",
                "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/anti-xss/zipball/bca1f8607e55a3c5077483615cd93bd8f11bd675",
                "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "voku/portable-utf8": "~6.0.2"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "4.1.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "EllisLab Dev Team",
                    "homepage": "http://ellislab.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/"
                }
            ],
            "description": "anti xss-library",
            "homepage": "https://github.com/voku/anti-xss",
            "keywords": [
                "anti-xss",
                "clean",
                "security",
                "xss"
            ],
            "support": {
                "issues": "https://github.com/voku/anti-xss/issues",
                "source": "https://github.com/voku/anti-xss/tree/4.1.42"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/anti-xss",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/anti-xss",
                    "type": "tidelift"
                }
            ],
            "time": "2023-07-03T14:40:46+00:00"
        },
        {
            "name": "voku/arrayy",
            "version": "7.9.6",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/Arrayy.git",
                "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/Arrayy/zipball/0e20b8c6eef7fc46694a2906e0eae2f9fc11cade",
                "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "php": ">=7.0.0",
                "phpdocumentor/reflection-docblock": "~4.3 || ~5.0",
                "symfony/polyfill-mbstring": "~1.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "src/Create.php"
                ],
                "psr-4": {
                    "Arrayy\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/",
                    "role": "Maintainer"
                }
            ],
            "description": "Array manipulation library for PHP, called Arrayy!",
            "keywords": [
                "Arrayy",
                "array",
                "helpers",
                "manipulation",
                "methods",
                "utility",
                "utils"
            ],
            "support": {
                "docs": "https://voku.github.io/Arrayy/",
                "issues": "https://github.com/voku/Arrayy/issues",
                "source": "https://github.com/voku/Arrayy"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/arrayy",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/arrayy",
                    "type": "tidelift"
                }
            ],
            "time": "2022-12-27T12:58:32+00:00"
        },
        {
            "name": "voku/email-check",
            "version": "3.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/email-check.git",
                "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/email-check/zipball/6ea842920bbef6758b8c1e619fd1710e7a1a2cac",
                "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "symfony/polyfill-intl-idn": "~1.10"
            },
            "require-dev": {
                "fzaninotto/faker": "~1.7",
                "phpunit/phpunit": "~6.0 || ~7.0"
            },
            "suggest": {
                "ext-intl": "Use Intl for best performance"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "email-check (syntax, dns, trash, ...) library",
            "homepage": "https://github.com/voku/email-check",
            "keywords": [
                "check-email",
                "email",
                "mail",
                "mail-check",
                "validate-email",
                "validate-email-address",
                "validate-mail"
            ],
            "support": {
                "issues": "https://github.com/voku/email-check/issues",
                "source": "https://github.com/voku/email-check/tree/3.1.0"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/email-check",
                    "type": "tidelift"
                }
            ],
            "time": "2021-01-27T14:14:33+00:00"
        },
        {
            "name": "voku/portable-ascii",
            "version": "2.0.3",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/portable-ascii.git",
                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "suggest": {
                "ext-intl": "Use Intl for transliterator_transliterate() support"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "https://www.moelleken.org/"
                }
            ],
            "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
            "homepage": "https://github.com/voku/portable-ascii",
            "keywords": [
                "ascii",
                "clean",
                "php"
            ],
            "support": {
                "issues": "https://github.com/voku/portable-ascii/issues",
                "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/portable-ascii",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
                    "type": "tidelift"
                }
            ],
            "time": "2024-11-21T01:49:47+00:00"
        },
        {
            "name": "voku/portable-utf8",
            "version": "6.0.13",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/portable-utf8.git",
                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "symfony/polyfill-iconv": "~1.0",
                "symfony/polyfill-intl-grapheme": "~1.0",
                "symfony/polyfill-intl-normalizer": "~1.0",
                "symfony/polyfill-mbstring": "~1.0",
                "symfony/polyfill-php72": "~1.0",
                "voku/portable-ascii": "~2.0.0"
            },
            "require-dev": {
                "phpstan/phpstan": "1.9.*@dev",
                "phpstan/phpstan-strict-rules": "1.4.*@dev",
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0",
                "thecodingmachine/phpstan-strict-rules": "1.0.*@dev",
                "voku/phpstan-rules": "3.1.*@dev"
            },
            "suggest": {
                "ext-ctype": "Use Ctype for e.g. hexadecimal digit detection",
                "ext-fileinfo": "Use Fileinfo for better binary file detection",
                "ext-iconv": "Use iconv for best performance",
                "ext-intl": "Use Intl for best performance",
                "ext-json": "Use JSON for string detection",
                "ext-mbstring": "Use Mbstring for best performance"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "(Apache-2.0 or GPL-2.0)"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Hamid Sarfraz",
                    "homepage": "http://pageconfig.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "Portable UTF-8 library - performance optimized (unicode) string functions for php.",
            "homepage": "https://github.com/voku/portable-utf8",
            "keywords": [
                "UTF",
                "clean",
                "php",
                "unicode",
                "utf-8",
                "utf8"
            ],
            "support": {
                "issues": "https://github.com/voku/portable-utf8/issues",
                "source": "https://github.com/voku/portable-utf8/tree/6.0.13"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/portable-utf8",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-utf8",
                    "type": "tidelift"
                }
            ],
            "time": "2023-03-08T08:35:38+00:00"
        },
        {
            "name": "voku/stop-words",
            "version": "2.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/stop-words.git",
                "reference": "8e63c0af20f800b1600783764e0ce19e53969f71"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/stop-words/zipball/8e63c0af20f800b1600783764e0ce19e53969f71",
                "reference": "8e63c0af20f800b1600783764e0ce19e53969f71",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "Stop-Words via PHP",
            "keywords": [
                "stop words",
                "stop-words"
            ],
            "support": {
                "issues": "https://github.com/voku/stop-words/issues",
                "source": "https://github.com/voku/stop-words/tree/master"
            },
            "time": "2018-11-23T01:37:27+00:00"
        },
        {
            "name": "voku/urlify",
            "version": "5.0.7",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/urlify.git",
                "reference": "014b2074407b5db5968f836c27d8731934b330e4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/urlify/zipball/014b2074407b5db5968f836c27d8731934b330e4",
                "reference": "014b2074407b5db5968f836c27d8731934b330e4",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "voku/portable-ascii": "~2.0",
                "voku/portable-utf8": "~6.0",
                "voku/stop-words": "~2.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Johnny Broadway",
                    "email": "johnny@johnnybroadway.com",
                    "homepage": "http://www.johnnybroadway.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://moelleken.org/"
                }
            ],
            "description": "PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.",
            "homepage": "https://github.com/voku/urlify",
            "keywords": [
                "encode",
                "iconv",
                "link",
                "slug",
                "translit",
                "transliterate",
                "transliteration",
                "url",
                "urlify"
            ],
            "support": {
                "issues": "https://github.com/voku/urlify/issues",
                "source": "https://github.com/voku/urlify/tree/5.0.7"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/urlify",
                    "type": "tidelift"
                }
            ],
            "time": "2022-01-24T19:08:46+00:00"
        },
        {
            "name": "webmozart/assert",
            "version": "1.11.0",
            "source": {
                "type": "git",
                "url": "https://github.com/webmozarts/assert.git",
                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
                "shasum": ""
            },
            "require": {
                "ext-ctype": "*",
                "php": "^7.2 || ^8.0"
            },
            "conflict": {
                "phpstan/phpstan": "<0.12.20",
                "vimeo/psalm": "<4.6.1 || 4.6.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^8.5.13"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.10-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Webmozart\\Assert\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Bernhard Schussek",
                    "email": "bschussek@gmail.com"
                }
            ],
            "description": "Assertions to validate method input/output with nice error messages.",
            "keywords": [
                "assert",
                "check",
                "validate"
            ],
            "support": {
                "issues": "https://github.com/webmozarts/assert/issues",
                "source": "https://github.com/webmozarts/assert/tree/1.11.0"
            },
            "time": "2022-06-03T18:03:27+00:00"
        },
        {
            "name": "weew/helpers-array",
            "version": "v1.3.1",
            "source": {
                "type": "git",
                "url": "https://github.com/weew/helpers-array.git",
                "reference": "9bff63111f9765b4277750db8d276d92b3e16ed0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/weew/helpers-array/zipball/9bff63111f9765b4277750db8d276d92b3e16ed0",
                "reference": "9bff63111f9765b4277750db8d276d92b3e16ed0",
                "shasum": ""
            },
            "require-dev": {
                "phpunit/phpunit": "^4.7",
                "satooshi/php-coveralls": "^0.6.1"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "src/array.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Maxim Kott",
                    "email": "maximkott@gmail.com"
                }
            ],
            "description": "Useful collection of php array helpers.",
            "support": {
                "issues": "https://github.com/weew/helpers-array/issues",
                "source": "https://github.com/weew/helpers-array/tree/master"
            },
            "time": "2016-07-21T11:18:01+00:00"
        }
    ],
    "packages-dev": [
        {
            "name": "myclabs/deep-copy",
            "version": "1.13.4",
            "source": {
                "type": "git",
                "url": "https://github.com/myclabs/DeepCopy.git",
                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
                "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
                "shasum": ""
            },
            "require": {
                "php": "^7.1 || ^8.0"
            },
            "conflict": {
                "doctrine/collections": "<1.6.8",
                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
            },
            "require-dev": {
                "doctrine/collections": "^1.6.8",
                "doctrine/common": "^2.13.3 || ^3.2.2",
                "phpspec/prophecy": "^1.10",
                "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "src/DeepCopy/deep_copy.php"
                ],
                "psr-4": {
                    "DeepCopy\\": "src/DeepCopy/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "Create deep copies (clones) of your objects",
            "keywords": [
                "clone",
                "copy",
                "duplicate",
                "object",
                "object graph"
            ],
            "support": {
                "issues": "https://github.com/myclabs/DeepCopy/issues",
                "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
            },
            "funding": [
                {
                    "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-01T08:46:24+00:00"
        },
        {
            "name": "nikic/php-parser",
            "version": "v5.6.1",
            "source": {
                "type": "git",
                "url": "https://github.com/nikic/PHP-Parser.git",
                "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
                "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
                "shasum": ""
            },
            "require": {
                "ext-ctype": "*",
                "ext-json": "*",
                "ext-tokenizer": "*",
                "php": ">=7.4"
            },
            "require-dev": {
                "ircmaxell/php-yacc": "^0.0.7",
                "phpunit/phpunit": "^9.0"
            },
            "bin": [
                "bin/php-parse"
            ],
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "5.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "PhpParser\\": "lib/PhpParser"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Nikita Popov"
                }
            ],
            "description": "A PHP parser written in PHP",
            "keywords": [
                "parser",
                "php"
            ],
            "support": {
                "issues": "https://github.com/nikic/PHP-Parser/issues",
                "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
            },
            "time": "2025-08-13T20:13:15+00:00"
        },
        {
            "name": "phar-io/manifest",
            "version": "2.0.4",
            "source": {
                "type": "git",
                "url": "https://github.com/phar-io/manifest.git",
                "reference": "54750ef60c58e43759730615a392c31c80e23176"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
                "reference": "54750ef60c58e43759730615a392c31c80e23176",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-libxml": "*",
                "ext-phar": "*",
                "ext-xmlwriter": "*",
                "phar-io/version": "^3.0.1",
                "php": "^7.2 || ^8.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Arne Blankerts",
                    "email": "arne@blankerts.de",
                    "role": "Developer"
                },
                {
                    "name": "Sebastian Heuer",
                    "email": "sebastian@phpeople.de",
                    "role": "Developer"
                },
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "Developer"
                }
            ],
            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
            "support": {
                "issues": "https://github.com/phar-io/manifest/issues",
                "source": "https://github.com/phar-io/manifest/tree/2.0.4"
            },
            "funding": [
                {
                    "url": "https://github.com/theseer",
                    "type": "github"
                }
            ],
            "time": "2024-03-03T12:33:53+00:00"
        },
        {
            "name": "phar-io/version",
            "version": "3.2.1",
            "source": {
                "type": "git",
                "url": "https://github.com/phar-io/version.git",
                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
                "shasum": ""
            },
            "require": {
                "php": "^7.2 || ^8.0"
            },
            "type": "library",
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Arne Blankerts",
                    "email": "arne@blankerts.de",
                    "role": "Developer"
                },
                {
                    "name": "Sebastian Heuer",
                    "email": "sebastian@phpeople.de",
                    "role": "Developer"
                },
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "Developer"
                }
            ],
            "description": "Library for handling version information and constraints",
            "support": {
                "issues": "https://github.com/phar-io/version/issues",
                "source": "https://github.com/phar-io/version/tree/3.2.1"
            },
            "time": "2022-02-21T01:04:05+00:00"
        },
        {
            "name": "php-parallel-lint/php-parallel-lint",
            "version": "v1.4.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git",
                "reference": "6db563514f27e19595a19f45a4bf757b6401194e"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e",
                "reference": "6db563514f27e19595a19f45a4bf757b6401194e",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "php": ">=5.3.0"
            },
            "replace": {
                "grogy/php-parallel-lint": "*",
                "jakub-onderka/php-parallel-lint": "*"
            },
            "require-dev": {
                "nette/tester": "^1.3 || ^2.0",
                "php-parallel-lint/php-console-highlighter": "0.* || ^1.0",
                "squizlabs/php_codesniffer": "^3.6"
            },
            "suggest": {
                "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet"
            },
            "bin": [
                "parallel-lint"
            ],
            "type": "library",
            "autoload": {
                "classmap": [
                    "./src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-2-Clause"
            ],
            "authors": [
                {
                    "name": "Jakub Onderka",
                    "email": "ahoj@jakubonderka.cz"
                }
            ],
            "description": "This tool checks the syntax of PHP files about 20x faster than serial check.",
            "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint",
            "keywords": [
                "lint",
                "static analysis"
            ],
            "support": {
                "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues",
                "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0"
            },
            "time": "2024-03-27T12:14:49+00:00"
        },
        {
            "name": "phpunit/php-code-coverage",
            "version": "11.0.11",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
                "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
                "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-libxml": "*",
                "ext-xmlwriter": "*",
                "nikic/php-parser": "^5.4.0",
                "php": ">=8.2",
                "phpunit/php-file-iterator": "^5.1.0",
                "phpunit/php-text-template": "^4.0.1",
                "sebastian/code-unit-reverse-lookup": "^4.0.1",
                "sebastian/complexity": "^4.0.1",
                "sebastian/environment": "^7.2.0",
                "sebastian/lines-of-code": "^3.0.1",
                "sebastian/version": "^5.0.2",
                "theseer/tokenizer": "^1.2.3"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.5.2"
            },
            "suggest": {
                "ext-pcov": "PHP extension that provides line coverage",
                "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "11.0.x-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
            "keywords": [
                "coverage",
                "testing",
                "xunit"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-27T14:37:49+00:00"
        },
        {
            "name": "phpunit/php-file-iterator",
            "version": "5.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
                "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6",
                "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "5.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
            "keywords": [
                "filesystem",
                "iterator"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
                "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-08-27T05:02:59+00:00"
        },
        {
            "name": "phpunit/php-invoker",
            "version": "5.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/php-invoker.git",
                "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2",
                "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "ext-pcntl": "*",
                "phpunit/phpunit": "^11.0"
            },
            "suggest": {
                "ext-pcntl": "*"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "5.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Invoke callables with a timeout",
            "homepage": "https://github.com/sebastianbergmann/php-invoker/",
            "keywords": [
                "process"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
                "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
                "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T05:07:44+00:00"
        },
        {
            "name": "phpunit/php-text-template",
            "version": "4.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/php-text-template.git",
                "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
                "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "4.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Simple template engine.",
            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
            "keywords": [
                "template"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
                "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
                "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T05:08:43+00:00"
        },
        {
            "name": "phpunit/php-timer",
            "version": "7.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/php-timer.git",
                "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
                "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "7.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Utility class for timing",
            "homepage": "https://github.com/sebastianbergmann/php-timer/",
            "keywords": [
                "timer"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/php-timer/issues",
                "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
                "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T05:09:35+00:00"
        },
        {
            "name": "phpunit/phpunit",
            "version": "11.5.42",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/phpunit.git",
                "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c",
                "reference": "1c6cb5dfe412af3d0dfd414cfd110e3b9cfdbc3c",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-json": "*",
                "ext-libxml": "*",
                "ext-mbstring": "*",
                "ext-xml": "*",
                "ext-xmlwriter": "*",
                "myclabs/deep-copy": "^1.13.4",
                "phar-io/manifest": "^2.0.4",
                "phar-io/version": "^3.2.1",
                "php": ">=8.2",
                "phpunit/php-code-coverage": "^11.0.11",
                "phpunit/php-file-iterator": "^5.1.0",
                "phpunit/php-invoker": "^5.0.1",
                "phpunit/php-text-template": "^4.0.1",
                "phpunit/php-timer": "^7.0.1",
                "sebastian/cli-parser": "^3.0.2",
                "sebastian/code-unit": "^3.0.3",
                "sebastian/comparator": "^6.3.2",
                "sebastian/diff": "^6.0.2",
                "sebastian/environment": "^7.2.1",
                "sebastian/exporter": "^6.3.2",
                "sebastian/global-state": "^7.0.2",
                "sebastian/object-enumerator": "^6.0.1",
                "sebastian/type": "^5.1.3",
                "sebastian/version": "^5.0.2",
                "staabm/side-effects-detector": "^1.0.5"
            },
            "suggest": {
                "ext-soap": "To be able to generate mocks based on WSDL files"
            },
            "bin": [
                "phpunit"
            ],
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "11.5-dev"
                }
            },
            "autoload": {
                "files": [
                    "src/Framework/Assert/Functions.php"
                ],
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "The PHP Unit Testing framework.",
            "homepage": "https://phpunit.de/",
            "keywords": [
                "phpunit",
                "testing",
                "xunit"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
                "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.42"
            },
            "funding": [
                {
                    "url": "https://phpunit.de/sponsors.html",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
                    "type": "tidelift"
                }
            ],
            "time": "2025-09-28T12:09:13+00:00"
        },
        {
            "name": "sebastian/cli-parser",
            "version": "3.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/cli-parser.git",
                "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180",
                "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "3.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Library for parsing CLI options",
            "homepage": "https://github.com/sebastianbergmann/cli-parser",
            "support": {
                "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
                "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
                "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:41:36+00:00"
        },
        {
            "name": "sebastian/code-unit",
            "version": "3.0.3",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/code-unit.git",
                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64",
                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.5"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "3.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Collection of value objects that represent the PHP code units",
            "homepage": "https://github.com/sebastianbergmann/code-unit",
            "support": {
                "issues": "https://github.com/sebastianbergmann/code-unit/issues",
                "security": "https://github.com/sebastianbergmann/code-unit/security/policy",
                "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2025-03-19T07:56:08+00:00"
        },
        {
            "name": "sebastian/code-unit-reverse-lookup",
            "version": "4.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
                "reference": "183a9b2632194febd219bb9246eee421dad8d45e"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e",
                "reference": "183a9b2632194febd219bb9246eee421dad8d45e",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "4.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                }
            ],
            "description": "Looks up which function or method a line of code belongs to",
            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
            "support": {
                "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
                "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy",
                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:45:54+00:00"
        },
        {
            "name": "sebastian/comparator",
            "version": "6.3.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/comparator.git",
                "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8",
                "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-mbstring": "*",
                "php": ">=8.2",
                "sebastian/diff": "^6.0",
                "sebastian/exporter": "^6.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.4"
            },
            "suggest": {
                "ext-bcmath": "For comparing BcMath\\Number objects"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "6.3-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                },
                {
                    "name": "Jeff Welch",
                    "email": "whatthejeff@gmail.com"
                },
                {
                    "name": "Volker Dusch",
                    "email": "github@wallbash.com"
                },
                {
                    "name": "Bernhard Schussek",
                    "email": "bschussek@2bepublished.at"
                }
            ],
            "description": "Provides the functionality to compare PHP values for equality",
            "homepage": "https://github.com/sebastianbergmann/comparator",
            "keywords": [
                "comparator",
                "compare",
                "equality"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/comparator/issues",
                "security": "https://github.com/sebastianbergmann/comparator/security/policy",
                "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-10T08:07:46+00:00"
        },
        {
            "name": "sebastian/complexity",
            "version": "4.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/complexity.git",
                "reference": "ee41d384ab1906c68852636b6de493846e13e5a0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0",
                "reference": "ee41d384ab1906c68852636b6de493846e13e5a0",
                "shasum": ""
            },
            "require": {
                "nikic/php-parser": "^5.0",
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "4.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Library for calculating the complexity of PHP code units",
            "homepage": "https://github.com/sebastianbergmann/complexity",
            "support": {
                "issues": "https://github.com/sebastianbergmann/complexity/issues",
                "security": "https://github.com/sebastianbergmann/complexity/security/policy",
                "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:49:50+00:00"
        },
        {
            "name": "sebastian/diff",
            "version": "6.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/diff.git",
                "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
                "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0",
                "symfony/process": "^4.2 || ^5"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "6.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                },
                {
                    "name": "Kore Nordmann",
                    "email": "mail@kore-nordmann.de"
                }
            ],
            "description": "Diff implementation",
            "homepage": "https://github.com/sebastianbergmann/diff",
            "keywords": [
                "diff",
                "udiff",
                "unidiff",
                "unified diff"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/diff/issues",
                "security": "https://github.com/sebastianbergmann/diff/security/policy",
                "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:53:05+00:00"
        },
        {
            "name": "sebastian/environment",
            "version": "7.2.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/environment.git",
                "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4",
                "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.3"
            },
            "suggest": {
                "ext-posix": "*"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "7.2-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                }
            ],
            "description": "Provides functionality to handle HHVM/PHP environments",
            "homepage": "https://github.com/sebastianbergmann/environment",
            "keywords": [
                "Xdebug",
                "environment",
                "hhvm"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/environment/issues",
                "security": "https://github.com/sebastianbergmann/environment/security/policy",
                "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
                    "type": "tidelift"
                }
            ],
            "time": "2025-05-21T11:55:47+00:00"
        },
        {
            "name": "sebastian/exporter",
            "version": "6.3.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/exporter.git",
                "reference": "70a298763b40b213ec087c51c739efcaa90bcd74"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74",
                "reference": "70a298763b40b213ec087c51c739efcaa90bcd74",
                "shasum": ""
            },
            "require": {
                "ext-mbstring": "*",
                "php": ">=8.2",
                "sebastian/recursion-context": "^6.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.3"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "6.3-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                },
                {
                    "name": "Jeff Welch",
                    "email": "whatthejeff@gmail.com"
                },
                {
                    "name": "Volker Dusch",
                    "email": "github@wallbash.com"
                },
                {
                    "name": "Adam Harvey",
                    "email": "aharvey@php.net"
                },
                {
                    "name": "Bernhard Schussek",
                    "email": "bschussek@gmail.com"
                }
            ],
            "description": "Provides the functionality to export PHP variables for visualization",
            "homepage": "https://www.github.com/sebastianbergmann/exporter",
            "keywords": [
                "export",
                "exporter"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/exporter/issues",
                "security": "https://github.com/sebastianbergmann/exporter/security/policy",
                "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
                    "type": "tidelift"
                }
            ],
            "time": "2025-09-24T06:12:51+00:00"
        },
        {
            "name": "sebastian/global-state",
            "version": "7.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/global-state.git",
                "reference": "3be331570a721f9a4b5917f4209773de17f747d7"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7",
                "reference": "3be331570a721f9a4b5917f4209773de17f747d7",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2",
                "sebastian/object-reflector": "^4.0",
                "sebastian/recursion-context": "^6.0"
            },
            "require-dev": {
                "ext-dom": "*",
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "7.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                }
            ],
            "description": "Snapshotting of global state",
            "homepage": "https://www.github.com/sebastianbergmann/global-state",
            "keywords": [
                "global state"
            ],
            "support": {
                "issues": "https://github.com/sebastianbergmann/global-state/issues",
                "security": "https://github.com/sebastianbergmann/global-state/security/policy",
                "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:57:36+00:00"
        },
        {
            "name": "sebastian/lines-of-code",
            "version": "3.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/lines-of-code.git",
                "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a",
                "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a",
                "shasum": ""
            },
            "require": {
                "nikic/php-parser": "^5.0",
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "3.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Library for counting the lines of code in PHP source code",
            "homepage": "https://github.com/sebastianbergmann/lines-of-code",
            "support": {
                "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
                "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T04:58:38+00:00"
        },
        {
            "name": "sebastian/object-enumerator",
            "version": "6.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
                "reference": "f5b498e631a74204185071eb41f33f38d64608aa"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa",
                "reference": "f5b498e631a74204185071eb41f33f38d64608aa",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2",
                "sebastian/object-reflector": "^4.0",
                "sebastian/recursion-context": "^6.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "6.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                }
            ],
            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
            "support": {
                "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
                "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T05:00:13+00:00"
        },
        {
            "name": "sebastian/object-reflector",
            "version": "4.0.1",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/object-reflector.git",
                "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9",
                "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "4.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                }
            ],
            "description": "Allows reflection of object attributes, including inherited and non-public ones",
            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
            "support": {
                "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
                "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
                "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-07-03T05:01:32+00:00"
        },
        {
            "name": "sebastian/recursion-context",
            "version": "6.0.3",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/recursion-context.git",
                "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc",
                "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.3"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "6.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de"
                },
                {
                    "name": "Jeff Welch",
                    "email": "whatthejeff@gmail.com"
                },
                {
                    "name": "Adam Harvey",
                    "email": "aharvey@php.net"
                }
            ],
            "description": "Provides functionality to recursively process PHP variables",
            "homepage": "https://github.com/sebastianbergmann/recursion-context",
            "support": {
                "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
                "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
                "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-13T04:42:22+00:00"
        },
        {
            "name": "sebastian/type",
            "version": "5.1.3",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/type.git",
                "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
                "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^11.3"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "5.1-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Collection of value objects that represent the types of the PHP type system",
            "homepage": "https://github.com/sebastianbergmann/type",
            "support": {
                "issues": "https://github.com/sebastianbergmann/type/issues",
                "security": "https://github.com/sebastianbergmann/type/security/policy",
                "source": "https://github.com/sebastianbergmann/type/tree/5.1.3"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                },
                {
                    "url": "https://liberapay.com/sebastianbergmann",
                    "type": "liberapay"
                },
                {
                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
                    "type": "thanks_dev"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/sebastian/type",
                    "type": "tidelift"
                }
            ],
            "time": "2025-08-09T06:55:48+00:00"
        },
        {
            "name": "sebastian/version",
            "version": "5.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/sebastianbergmann/version.git",
                "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874",
                "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "5.0-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Sebastian Bergmann",
                    "email": "sebastian@phpunit.de",
                    "role": "lead"
                }
            ],
            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
            "homepage": "https://github.com/sebastianbergmann/version",
            "support": {
                "issues": "https://github.com/sebastianbergmann/version/issues",
                "security": "https://github.com/sebastianbergmann/version/security/policy",
                "source": "https://github.com/sebastianbergmann/version/tree/5.0.2"
            },
            "funding": [
                {
                    "url": "https://github.com/sebastianbergmann",
                    "type": "github"
                }
            ],
            "time": "2024-10-09T05:16:32+00:00"
        },
        {
            "name": "squizlabs/php_codesniffer",
            "version": "2.9.2",
            "source": {
                "type": "git",
                "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
                "reference": "2acf168de78487db620ab4bc524135a13cfe6745"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745",
                "reference": "2acf168de78487db620ab4bc524135a13cfe6745",
                "shasum": ""
            },
            "require": {
                "ext-simplexml": "*",
                "ext-tokenizer": "*",
                "ext-xmlwriter": "*",
                "php": ">=5.1.2"
            },
            "require-dev": {
                "phpunit/phpunit": "~4.0"
            },
            "bin": [
                "scripts/phpcs",
                "scripts/phpcbf"
            ],
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.x-dev"
                }
            },
            "autoload": {
                "classmap": [
                    "CodeSniffer.php",
                    "CodeSniffer/CLI.php",
                    "CodeSniffer/Exception.php",
                    "CodeSniffer/File.php",
                    "CodeSniffer/Fixer.php",
                    "CodeSniffer/Report.php",
                    "CodeSniffer/Reporting.php",
                    "CodeSniffer/Sniff.php",
                    "CodeSniffer/Tokens.php",
                    "CodeSniffer/Reports/",
                    "CodeSniffer/Tokenizers/",
                    "CodeSniffer/DocGenerators/",
                    "CodeSniffer/Standards/AbstractPatternSniff.php",
                    "CodeSniffer/Standards/AbstractScopeSniff.php",
                    "CodeSniffer/Standards/AbstractVariableSniff.php",
                    "CodeSniffer/Standards/IncorrectPatternException.php",
                    "CodeSniffer/Standards/Generic/Sniffs/",
                    "CodeSniffer/Standards/MySource/Sniffs/",
                    "CodeSniffer/Standards/PEAR/Sniffs/",
                    "CodeSniffer/Standards/PSR1/Sniffs/",
                    "CodeSniffer/Standards/PSR2/Sniffs/",
                    "CodeSniffer/Standards/Squiz/Sniffs/",
                    "CodeSniffer/Standards/Zend/Sniffs/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Greg Sherwood",
                    "role": "lead"
                }
            ],
            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
            "homepage": "http://www.squizlabs.com/php-codesniffer",
            "keywords": [
                "phpcs",
                "standards"
            ],
            "support": {
                "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
                "source": "https://github.com/squizlabs/PHP_CodeSniffer",
                "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
            },
            "funding": [
                {
                    "url": "https://github.com/PHPCSStandards",
                    "type": "github"
                },
                {
                    "url": "https://github.com/jrfnl",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/php_codesniffer",
                    "type": "open_collective"
                }
            ],
            "time": "2018-11-07T22:31:41+00:00"
        },
        {
            "name": "staabm/side-effects-detector",
            "version": "1.0.5",
            "source": {
                "type": "git",
                "url": "https://github.com/staabm/side-effects-detector.git",
                "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
                "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
                "shasum": ""
            },
            "require": {
                "ext-tokenizer": "*",
                "php": "^7.4 || ^8.0"
            },
            "require-dev": {
                "phpstan/extension-installer": "^1.4.3",
                "phpstan/phpstan": "^1.12.6",
                "phpunit/phpunit": "^9.6.21",
                "symfony/var-dumper": "^5.4.43",
                "tomasvotruba/type-coverage": "1.0.0",
                "tomasvotruba/unused-public": "1.0.0"
            },
            "type": "library",
            "autoload": {
                "classmap": [
                    "lib/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "A static analysis tool to detect side effects in PHP code",
            "keywords": [
                "static analysis"
            ],
            "support": {
                "issues": "https://github.com/staabm/side-effects-detector/issues",
                "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
            },
            "funding": [
                {
                    "url": "https://github.com/staabm",
                    "type": "github"
                }
            ],
            "time": "2024-10-20T05:08:20+00:00"
        },
        {
            "name": "theseer/tokenizer",
            "version": "1.2.3",
            "source": {
                "type": "git",
                "url": "https://github.com/theseer/tokenizer.git",
                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-tokenizer": "*",
                "ext-xmlwriter": "*",
                "php": "^7.2 || ^8.0"
            },
            "type": "library",
            "autoload": {
                "classmap": [
                    "src/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Arne Blankerts",
                    "email": "arne@blankerts.de",
                    "role": "Developer"
                }
            ],
            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
            "support": {
                "issues": "https://github.com/theseer/tokenizer/issues",
                "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
            },
            "funding": [
                {
                    "url": "https://github.com/theseer",
                    "type": "github"
                }
            ],
            "time": "2024-03-03T12:36:25+00:00"
        }
    ],
    "aliases": [],
    "minimum-stability": "stable",
    "stability-flags": {
        "bit3/git-php": 20
    },
    "prefer-stable": false,
    "prefer-lowest": false,
    "platform": {
        "php": ">=8.2"
    },
    "platform-dev": {},
    "plugin-api-version": "2.9.0"
}
<?php

namespace FW\Installer;

use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Updater;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Stringy\StaticStringy as S;

class App extends BaseApplication {

    const NO_LOCATION = 0;
    const LOCATION_ROOT = 1;
    const LOCATION_APP = 2;
    const LOCATION_ADDON = 3;

    protected $container;

    public function __construct($version) {
        parent::__construct('fw-installer', $version);

        $this->setupErrorHandling();
    }

    public function loadCommands(array $commands) {
        $location = $this->determineLocation();

        if ($location == self::LOCATION_APP) {
            $this->loadAddonCommands($commands);
        }

        foreach ($commands as $cmdName => $cmdConfig) {
            $command = $this->register($cmdName);

            $definition = [];

            // If command has aliases, add them
            if (array_has($cmdConfig, 'aliases')) {
                $aliases = array_get($cmdConfig, 'aliases');
                $command->setAliases(is_array($aliases) ? $aliases : [$aliases]);
            }

            // add command descriptions
            if (array_has($cmdConfig, 'description')) {
                $command->setDescription(array_get($cmdConfig, 'description'));
            }

            // Add command arguments
            if (array_has($cmdConfig, 'arguments')) {
                foreach ($cmdConfig['arguments'] as $argDefinition) {
                    $definition[] = new InputArgument(...$argDefinition);
                }
            }

            // Add command options
            if (array_has($cmdConfig, 'options')) {
                foreach ($cmdConfig['options'] as $optDefinition) {
                    $definition[] = new InputOption(...$optDefinition);
                }
            }

            // If any arguments or options were defined, add them to the command
            if (!empty($definition)) {
                $command->setDefinition(new InputDefinition($definition));
            }

            // Define the command execute handler
            $command->setCode(function (
                InputInterface $input,
                OutputInterface $output
            ) use ($command, $cmdName, $location, $cmdConfig) {
                $io = new SymfonyStyle($input, $output);

                $context = Utils\RunContext::load();
                $context->location = $context->location ?: $location;

                if ($cmdConfig['addon'] ?? false) {
                    $cmdInstance = new Command\Addon($command, $input, $io, $context, $cmdConfig['source']);
                } else {
                    $cmdClass = 'FW\Installer\Command\\' . S::upperCamelize($cmdName);
                    $cmdInstance = new $cmdClass($command, $input, $io, $context);
                }

                if (!method_exists($cmdInstance, 'execute')) {
                    throw new \RuntimeException("Execute method not defined for command {$cmdName}");
                }

                // We want the input arguments to be passed as the arguments to the execute function
                $args = array_slice(array_values($input->getArguments()), 1);
                try {
                    $cmdInstance->execute(...$args);
                } catch (CommandException $e) {
                    // command exceptions mean we hit an expected error, the error message should be sufficient
                    $io->error($e->getMessage());
                    $verbosity = $output->getVerbosity();
                    // if verbose, print the excception cause if it exists
                    if ($verbosity >= OutputInterface::VERBOSITY_VERBOSE) {
                        $prev = $e->getPrevious();
                        if ($prev) {
                            throw $prev;
                            // if no cause and very verbose, print this exception
                        } else if ($verbosity >= OutputInterface::VERBOSITY_VERY_VERBOSE) {
                            throw $e;
                        }
                    }
                }
                // $sub will be true if we're running as a subcommand,
                // and we don't want to call the update check if we're doing that
                if (!$context->sub) {
                    // After command has finished executing, run the update check
                    $command->getApplication()->updateCheck($io);
                }
            });
        }
    }

    public function updateCheck(SymfonyStyle $io) {
        $updater = new Updater($this->getVersion());

        if ($updater->hasUpdate()) {
            $newVersion = $updater->getCurrentRemoteSemver();
            $oldVersion = $updater->getCurrentLocalSemver();

            $io->writeln("<comment>! [NOTE] A new version of the fw-installer is available.\n!</>");
            $io->writeln("<comment>! New Version: <fg=cyan>{$newVersion}</>");
            $io->writeln("<comment>!\n! Current Version: <fg=cyan>{$oldVersion}</>");
            $io->writeln("<comment>!\n! Run `fw self-update` to update it.\n</>");
        }
    }

    protected function setupErrorHandling() {
        $dispatcher = new EventDispatcher();
        $this->setDispatcher($dispatcher);

        Utils\ErrorHandler::load($dispatcher);
    }

    protected function determineLocation() {
        // TODO: figure out a better way of determining context for fw-api installs?
        if (file_exists(path_resolve('.fw'))) {
            return self::LOCATION_ROOT;
        }

        if (file_exists(path_resolve('fw.json'))) {
            $meta = json_decode(file_get_contents(path_resolve('fw.json')), true);

            if (!$meta) {
                return self::NO_LOCATION;
            }

            if (isset($meta['appId'])) {
                return self::LOCATION_APP;
            }

            return self::LOCATION_ADDON;
        }

        return self::NO_LOCATION;
    }

    protected function loadAddonCommands(array &$commands) {
        $loadedAddons = [];
        //first load commands from addons that are actually installed
        if (file_exists('./addons')) {
            $files = new \FilesystemIterator(
                path_resolve('addons'),
                \FilesystemIterator::CURRENT_AS_PATHNAME |
                    \FilesystemIterator::FOLLOW_SYMLINKS |
                    \FilesystemIterator::SKIP_DOTS
            );

            $argDefinitions = [
                'required' => InputArgument::REQUIRED,
                'optional' => InputArgument::OPTIONAL
            ];

            $optDefinitions = [
                'value' => InputOption::VALUE_REQUIRED,
                'none' => InputOption::VALUE_NONE
            ];

            foreach ($files as $path) {
                if (!is_dir($path)) {
                    continue;
                }

                // If fw.json doesn't exist, it's not a valid app or addon, so don't load it
                if (!file_exists("{$path}/fw.json")) {
                    continue;
                }

                $addonMeta = json_decode(file_get_contents("{$path}/fw.json"), true);
                $loadedAddons[] = $addonMeta['name'];
                if (!isset($addonMeta['commands'])) {
                    continue;
                }

                foreach ($addonMeta['commands'] as $commandName => $commandConfig) {
                    $command = [
                        'addon' => true,
                        'source' => path_join($path, $commandConfig['source'])
                    ];

                    if (isset($commandConfig['description'])) {
                        $command['description'] = $commandConfig['description'];
                    }

                    if (isset($commandConfig['arguments'])) {
                        $command['arguments'] = array_map(function ($arg) use ($argDefinitions) {
                            $arg[1] = $argDefinitions[$arg[1]];
                            return $arg;
                        }, $commandConfig['arguments']);
                    }

                    if (isset($commandConfig['options'])) {
                        $command['options'] = array_map(function ($opt) use ($optDefinitions) {
                            $opt[2] = $optDefinitions[$opt[2]];
                        }, $commandConfig['options']);
                    }

                    $commands[$commandName] = $command;
                }
            }
        }
        //after loading the commands for the addons that are loaded, also check for addons needed that are only globally defined

        if (file_exists('fw.json')) {
            $appJson = json_decode(file_get_contents("fw.json"), true);
            $addonRequirements = array_keys($appJson['dependencies']['addons']);
            if (!file_exists('./addons')) {
                return;
            }
            $files = new \FilesystemIterator(
                path_resolve('./addons'),
                \FilesystemIterator::CURRENT_AS_PATHNAME |
                    \FilesystemIterator::FOLLOW_SYMLINKS |
                    \FilesystemIterator::SKIP_DOTS

            );

            $argDefinitions = [
                'required' => InputArgument::REQUIRED,
                'optional' => InputArgument::OPTIONAL
            ];

            $optDefinitions = [
                'value' => InputOption::VALUE_REQUIRED,
                'none' => InputOption::VALUE_NONE
            ];

            foreach ($files as $path) {
                if (!is_dir($path)) {
                    continue;
                }

                // If fw.json doesn't exist, it's not a valid app or addon, so don't load it
                if (!file_exists("{$path}/fw.json")) {
                    continue;
                }

                $addonMeta = json_decode(file_get_contents("{$path}/fw.json"), true);

                if (in_array($addonMeta['name'], $loadedAddons)) {
                    continue;
                }
                $loadedAddons[] = $addonMeta['name'];
                if (!isset($addonMeta['commands'])) {
                    continue;
                }

                foreach ($addonMeta['commands'] as $commandName => $commandConfig) {
                    $command = [
                        'addon' => true,
                        'source' => path_join($path, $commandConfig['source'])
                    ];

                    if (isset($commandConfig['description'])) {
                        $command['description'] = $commandConfig['description'];
                    }

                    if (isset($commandConfig['arguments'])) {
                        $command['arguments'] = array_map(function ($arg) use ($argDefinitions) {
                            $arg[1] = $argDefinitions[$arg[1]];
                            return $arg;
                        }, $commandConfig['arguments']);
                    }

                    if (isset($commandConfig['options'])) {
                        $command['options'] = array_map(function ($opt) use ($optDefinitions) {
                            $opt[2] = $optDefinitions[$opt[2]];
                        }, $commandConfig['options']);
                    }

                    $commands[$commandName] = $command;
                }
            }
        }

    }
}
<?php

namespace FW\Installer\Command;

use FW\Installer\Utils\RunContext;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * Addons now have the ability to define their own commands, based on files
 * that export the "execute" function. This command class is responsible
 * for taking the path to the file that exports that function, and actually running
 */
class Addon extends BaseCommand {

    /** @inheritdoc */
    protected static $loadRegistry = false;

    protected $commandFile;

    public function __construct(
        Command $c,
        InputInterface $input,
        SymfonyStyle $io,
        RunContext $context,
        string $pathToCommand = ''
    ) {
        if (!$pathToCommand || !file_exists($pathToCommand)) {
            throw new \InvalidArgumentException('Path to command file must be a valid path');
        }

        parent::__construct($c, $input, $io, $context);

        $this->commandFile = $pathToCommand;
    }

    /**
     * Runs the addon command
     * @param  array $args variable list of arguments
     * @return mixed       Results vary based on the command
     */
    public function execute(...$args) {
        $executeFunction = require_once($this->commandFile);

        if (!is_object($executeFunction) || !($executeFunction instanceof \Closure)) {
            throw new \InvalidArgumentException('Addon command file does not return a valid Closure function');
        }

        $boundFn = $executeFunction->bindTo($this);
        return $boundFn(...$args);
    }
}
<?php

namespace FW\Installer\Command;

use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Registry;
use FW\Installer\Utils\RunContext;
use FW\Installer\Helpers\Process;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Stringy\StaticStringy as S;

abstract class BaseCommand {

    /**
     * If this is set to false (in child classes),
     * the Registry class will not be instantiated.
     *
     * There are only a couple of commands that *won't* use the registry,
     * which is why the default is true.
     *
     * @var boolean
     */
    protected static $loadRegistry = true;

    /**
     * @var Registry
     */
    protected $registry;

    /**
     * @var Command
     */
    protected $command;

    /**
     * @var InputInterface
     */
    protected $input;

    /**
     * @var SymfonyStyle
     */
    protected $io;

    /**
     * @var RunContext
     */
    protected $context;

    /**
     * @var array
     */
    protected $taskStack;

    /**
     * Creates a new instance of this command
     * @param Command        $c
     * @param InputInterface $input
     * @param SymfonyStyle   $io
     * @param RunContext     $context
     */
    public function __construct(Command $c, InputInterface $input, SymfonyStyle $io, RunContext $context) {
        $this->command = $c;
        $this->input = $input;
        $this->io = $io;
        $this->context = $context;

        if (static::$loadRegistry) {
            $this->registry = new Registry($c->getApplication()->getVersion());
        }

        $this->taskStack = [];
    }

    /**
     * Reverts operation of this command
     * @deprecated Not fully implemented
     */
    public function undo() {
        // Subclasses can override this method to do any additional undo operations
        // TODO: reimplement this

        if (count($this->taskStack)) {
            foreach ($this->taskStack as $name) {
                // $task->undo();
            }
        }
    }

    /**
     * Runs the specified task with the given parameters
     * @param  string  $name    Name of the task to run
     * @param  array   $options Array of parameters to pass into the task
     * @param  string  $message Message to display while the task runs
     * @param  boolean $halt    If true, throws an exception if the process fails
     * @param  boolean $timeout Timeout in seconds, or null for no timeout
     * @return int              Process exit code
     */
    protected function task(string $name, array $options = [], $message = null, $halt = true, $timeout = 60) {
        $message = $message ?: "Running task {$name}";
        $this->context->sub = true;
        $this->context->taskOptions = $options;
        $this->context->save();

        $process = new Process(["fw", "task", $name], $this->io, [
            'message' => $message,
            'timeout' => $timeout
        ]);

        // TODO: handle task failure
        // if ($this->process->run()) {}
        $result = $process->run();

        $this->context->reload();
        $this->context->sub = null;
        $this->context->taskOptions = null;

        // Put task on task stack so we can undo it later if necessary
        array_unshift($this->taskStack, $name);

        if ($halt && !$result) {
            throw new CommandException($process->getErrorMessage($name));
        }

        return $result;
    }
}
<?php

namespace FW\Installer\Command;

use Symfony\Component\Filesystem\Filesystem;
use Bit3\GitPhp\GitRepository;
use Bit3\GitPhp\GitException;

use FW\Installer\App;
use FW\Installer\Providers\BaseProvider;
use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Config;
use FW\Installer\Utils\Dependencies;
use FW\Installer\Utils\VersionUtils;
use FW\Installer\Utils\AppInstall;

class Install extends BaseCommand {

    /**
     * Installs an FW app, or installs addons in an app folder
     * @param  string $app     Name of the app to install. Unused in app folders
     * @param  string $version Either the app version of a URL for a repository containing the app. If undefined installs the latest version
     */
    public function execute($app, $version) {
        // If we are inside an app folder, try to install any addons
        // this app needs
        if ($this->context->location == App::LOCATION_APP) {
            $rootConfig = new Config('../../.fw');
            $appConfig = new Config('fw.json');
            $appId = $appConfig->get('appId');
            $appDir = getcwd();

            chdir('../../');

            $addons = $this->checkDependencies(
                $rootConfig,
                $appConfig->get('dependencies', []),
                "App '{$appId}' has several dependency incompatibilities"
            );

            // set update to true so we can update a dependency in a dev environment without deleting the folder
            $this->installAddons($addons, $appDir, true);
            // run install script if requested
            if ($this->input->getOption('config')) {
                $this->installScript($appDir);
            }
            $this->io->success("App '{$appId}' dependencies installed");
            return;
        }

        // If we are not inside an app folder, we MUST be in a root folder. Error out if not
        if ($this->context->location != App::LOCATION_ROOT) {
            throw new CommandException('You must be at the root of a valid FW installation to use this command.');
        }

        // If the app argument is not supplied, we need to error
        if (!$app) {
            throw new CommandException('You must supply an app id to install');
        }

        // there are two ways to install from Git:
        // * the old way: run `fw install <git URL>`: requires prompting the user for an app idea
        // * the new way: run `fw install <app ID> <git URL>`: overall more consistent behavior and saves a prompt
        // both ways are supported for compatibility, but in general the second way is preferred

        // if an invalid version is passed, assume the user passed app ID and git URL
        if ($version && !VersionUtils::valid($version)) {
            $git = $version;
        } else {
            // Check whether or not the provided app is actually a git url
            $git = filter_var(
                $app,
                FILTER_VALIDATE_URL
            ) ? $app : null;

            // If provided app is a git repo link, ask for app id
            // Otherwise, if given an app ID and a version or URL, use that
            if ($git) {
                $app = $this->io->ask('What is the app id of the app you are cloning?', '', function ($appId) {
                    if (!empty($appId)) {
                        return $appId;
                    }

                    throw new \RuntimeException("App id must be specified!");
                });
            }
        }

        // The install directory is `apps` + the id of the app
        $installDir = path_resolve('apps', $app);
        if (file_exists($installDir) && count(scandir($installDir)) > 2) {
            if (!$this->input->getOption('force')) {
                throw new CommandException("App '{$app}' is already installed, use 'fw update {$app}'.");
            }

            $fs = new Filesystem();
            $fs->remove($installDir);
        }

        $config = new Config('.fw');
        $addons = $git ? $this->gitInstall($git, $installDir, $config) :
            $this->registryInstall($app, $installDir, $config, $version);

        if ($addons === false) {
            return;
        }

        if (file_exists(path_join($installDir, 'server', 'composer.json'))) {
            $this->task('composer', [
                'dir' => path_join($installDir, 'server')
            ], 'Installing composer dependencies');
        }

        $webroot = $this->input->getOption('webroot') ?:
            $config->get('webroot') ?:
            $this->io->ask('Web Root', './public', function ($webroot) {
                if (!file_exists(realpath($webroot))) {
                    if (rtrim($webroot, '/\\') == './public') {
                        $fs = new Filesystem();
                        $fs->mkdir('./public');
                        return $webroot;
                    }

                    throw new \RuntimeException('Webroot folder does not exist.');
                }

                return $webroot;
            });

        $url = $this->input->getOption('url') ?: $this->io->ask('App Url', "/{$app}/");

        if ($url != '/') {
            // Make sure we pad the url with a leading and trailing slash
            $url = '/' . trim($url, '/');
        }

        if ($git) {
            $outputDirectory = path_resolve($webroot, $url);
            $gitConfig = new Config(path_join($installDir, 'config.json'));
            $gitConfig->set('outputDirectory', $outputDirectory)->save();
        } else {
            $appConfig = new Config(path_join($installDir, 'fw.json'));
            // Save webroot and url to app so they can be used during update
            $appConfig->set('webroot', $webroot)->set('url', $url)->save();
            $this->task('assets', [
                'install' => $installDir,
                'webroot' => $webroot,
                'url' => $url
            ], 'Moving public files');
        }

        $this->installAddons($addons, $installDir);
        $this->installScript($installDir);

        // Ensure ALL addon composer dependencies are installed
        $addonsDir = path_join($installDir, 'addons');

        if (file_exists($addonsDir)) {
            foreach (scandir($addonsDir) as $addon) {
                if (in_array($addon, ['.', '..'])) {
                    continue;
                }

                $addonPath = realpath(path_join($addonsDir, $addon));

                if (file_exists(path_join($addonPath, 'composer.json'))) {
                    $this->task('composer', [
                        'dir' => realpath($addonPath)
                    ], "Installing composer dependencies for '{$addon}'");
                }
            }
        }
        $this->io->success("App '{$app}' installed");
    }

    /**
     * Installs an app from the registry
     * @param  string $app        App ID to install
     * @param  string $version    App version to install
     * @param  string $installDir Directory to install the app into
     * @param  Config $rootConfig Root FW config object
     * @return array              Associative array of resolved dependencies for the app, or false if a dependency check failed
     */
    protected function registryInstall(
        string $app, 
        string $installDir, 
        Config $rootConfig,
        ?string $version = null )
        {
        $availableVersions = $this->registry->versions('app', $app);

        if (!$availableVersions) {
            throw new CommandException("App '{$app}' does not exist in the registry.");
        }

        $versionToUse = VersionUtils::getVersionToInstall($availableVersions['versions'], $version);
        $typeInfo = $this->registry->json('app', $app, $versionToUse);
        $typeJson = $typeInfo['json'];
        $provider = BaseProvider::providerFor($typeJson['repo']);

        if (!$provider) {
            throw new CommandException("Provider could not be determined for app '{$app}'");
        }

        $addons = $this->checkDependencies(
            $rootConfig,
            $typeJson['dependencies'] ?? [],
            "App '{$app}' could not be installed for the following reasons:",
            true
        );

        if (is_null($addons)) {
            return false;
        }

       $source = $typeInfo['version'];

        if ($provider instanceof \FW\Installer\Providers\Github) {
            $source = $this->getGithubAssetUrl($provider, $typeInfo['version']);
        }

        $this->task('download', [
            'provider' => $provider,
            'version' => $source,
            'dir' => $installDir
        ], "Downloading {$typeInfo['name']} v{$typeInfo['version']}");

        return $addons;
    }

    /**
     * Installs an app from a Git URL
     * @param  string $url        Git URL containing the app
     * @param  string $installDir Folder to install the app into
     * @param  Config $rootConfig Root FW config object
     * @return array              Associative array of resolved dependencies for the app
     */
    protected function gitInstall(string $url, string $installDir, Config $rootConfig) {
    	$repo = new GitRepository($installDir);

		if (!file_exists($installDir)) {
			mkdir($installDir);
		}

        try {
            $repo->lsRemote()->execute($url);
        } catch (GitException $e) {
            throw new CommandException('Git url provided could not be resolved to a valid git repository.', $e);
        }

        // disable timeout because large repos can take a while to clone
        $this->task('git-clone', [
           'dir' => $installDir,
           'url' => $url
        ], 'Cloning app from repository', null, null);

        $metaFilePath = path_join($installDir, 'fw.json');

        if (!file_exists($metaFilePath)) {
            $this->io->caution('fw installer schema file not found in repository. Ignoring additional setup.');

            return [];
        }

        $metaFile = new Config($metaFilePath);

        return $this->checkDependencies(
            $rootConfig,
            $metaFile->get('dependencies', []),
            'Incompatibility issues found, you should fix them'
        );
    }

    /**
     * Checks to see if dependencies are installed correctly
     * @param  Config  $rootConfig     Main FW config object
     * @param  array   $dependencies   Associative array of requested dependencies
     * @param  string  $failureMessage Message to display if the check fails
     * @param  boolean $returnNull     If true, returns null if a dependency check fails instead instead of the dependencies
     * @return array                   Associative array of resolved dependencies
     */
    protected function checkDependencies(
        Config $rootConfig,
        array $dependencies,
        string $failureMessage,
        bool $returnNull = false
    ) {
        $deps = new Dependencies($rootConfig, $this->registry, $dependencies);
        $conflicts = $deps->invalid();

        if (empty($conflicts)) {
            return $deps->addons();
        }

        $this->io->caution($failureMessage);

        foreach ($conflicts as $index => $message) {
            $i = $index + 1;
            $this->io->writeln("{$i}. {$message}\n");
        }

        if ($returnNull) {
            return null;
        }

        return $deps->addons();
    }

    /**
     * Installs all addons for an app
     * @param  array   $addons Array of addons to install
     * @param  string  $dir    App directory to install the addons
     * @param  boolean $update If true, updates the addons, false will skip if already installed
     */
    protected function installAddons(array $addons, string $dir, bool $update = false) {
        foreach ($addons as $addon => $version) {
            $this->task('addon', [
                'addon'   => $addon,
                'version' => $version,
                'install' => $dir,
                'update'  => $update
            ], "Installing addon '{$addon}'");
        }
    }

    /**
     * Runs the install.php script from the app folder
     * @param  string $installDir App folder
     */
    protected function installScript(string $installDir) {
        if (file_exists(path_join($installDir, 'install.php'))) {
            // install.php inside an app folder supports returning a function
            $globalConfig = new Config(path_resolve('config/local.php'), 'php', true);
            $localConfig = new Config(path_resolve($installDir, 'server/config/local.php'), 'php', true);

            $appInstall = new AppInstall($this->io, $globalConfig, $localConfig, path_join(
                $installDir,
                'install.php'
            ));

            chdir($installDir);

            $appInstall->run();
        }
    }

    protected function getGithubAssetUrl($provider, $version){
        $owner = $provider->getOwner();
        $repo  = $provider->getRepo();

        $creds = \FW\Installer\Utils\SystemConfig::load('github-credentials');
        $token = $creds->get('token');

        $client = new \GuzzleHttp\Client([
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'User-Agent'    => 'fw-installer',
                'Accept'        => 'application/vnd.github+json'
            ]
        ]);

        $url = "https://api.github.com/repos/{$owner}/{$repo}/releases";

        $response = $client->get($url);
        $data = json_decode(\GuzzleHttp\Psr7\Utils::copyToString($response->getBody()), true);

        foreach ($data as $release) {
            $tag = $release['tag_name'];
            $v = ltrim($tag, 'v');

            if ($v === $version && !empty($release['assets'])) {
                return $release['assets'][0]['url']; // API URL
            }
        }

        throw new \RuntimeException("Release {$version} not found for {$repo}");
    }
}
<?php

namespace FW\Installer\Command;

use FW\Installer\Providers\BaseProvider;

class Login extends BaseCommand {

    /** @inheritdoc */
    protected static $loadRegistry = false;

    /**
     * Logs into a Git provider for the sake of downloading and publishing apps and addons
     * @param  string $provider Provider, currently supports "bitbucket" and "github"
     */
    public function execute($provider) {
        BaseProvider::handleLogin($provider, $this->io);
    }
}
<?php

namespace FW\Installer\Command;

use GuzzleHttp\Psr7;
use Stringy\StaticStringy as S;

use FW\Installer\App;
use FW\Installer\Providers\BaseProvider;
use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Config;

class Publish extends BaseCommand {

    /**
     * Publishes an app or addon to the FW registry
     */
    public function execute() {
        if ($this->context->location != App::LOCATION_APP && $this->context->location != App::LOCATION_ADDON) {
            throw new CommandException('Publish command must be run inside an app or addon folder');
        }

        $config = new Config('fw.json');
        $type = $this->context->location == App::LOCATION_APP ? 'app' : 'addon';
        $name = ($type == 'app') ? $config->get('appId') : S::dasherize($config->get('name'));
        $version = $config->get('version');

        $zipPath = path_resolve("{$version}.zip");

        if (!file_exists($zipPath)) {
            throw new CommandException("No release zip exists for the current version of the {$type}");
        }

        if (($zipStream = fopen($zipPath, 'r')) === false) {
            throw new CommandException('Release zip file could not be opened.');
        }

        if (!$config->has('repo')) {
            throw new CommandException('fw config file is missing repository link');
        }

        $provider = BaseProvider::providerFor($config->get('repo'));

        if (!$provider) {
            throw new CommandException('Provider could not be found for given repository');
        }

        // Handle initial login
        $this->registry->login($this->io);

        $result = $this->registry->publish($type, $name, $version, $config->all());

        if ($result === false) {
            $this->registry->login($this->io, true);
            $result = $this->registry->publish($type, $name, $version, $config->all());
        }

        $provider->publish($version, Psr7\Utils::streamFor($zipStream));
        $this->io->success("{$name}@{$version} published");
    }
}
<?php

namespace FW\Installer\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Updater;

class SelfUpdate {

    /** @inheritdoc */
    protected static $loadRegistry = false;

    protected $io;
    protected $command;
    protected $input;

    public function __construct(Command $c, InputInterface $input, SymfonyStyle $io) {
        $this->command = $c;
        $this->io = $io;
        $this->input = $input;
    }

    /**
     * Updates the FW installer to the latest version
     */
    public function execute() {
        $updater = new Updater($this->command->getApplication()->getVersion());

        ($this->input->getOption('rollback')) ? $this->rollback($updater) : $this->update($updater);
    }

    /**
     * Updates the FW installer to the latest version
     * @param  Updater $updater
     */
    protected function update(Updater $updater) {
        try {
            $result = $updater->update();
            if ($result) {
                $newVersion = $updater->getNewVersion();

                $this->io->success(
                    "Updated to version {$newVersion} (SHA512).\n" .
                    'Run `fw self-update --rollback` to revert to the previous version'
                );
                exit(0);
            } else {
                $this->io->success('No update needed.');
            }
        } catch (\Exception $e) {
            throw new CommandException('Update Failed!', $e);
        }
    }

    /**
     * Rolls back the FW installer to the previous version installed
     * @param  Updater $updater
     */
    protected function rollback(Updater $updater) {
        try {
            $result = $updater->rollback();
            if ($result) {
                $this->io->success("Rolled back to previous version");
                exit(0);
            } else {
                $this->io->error('Rollback failed!');
            }
        } catch (\Exception $e) {
            throw new CommandException('Rollback Failed!', $e);
        }
    }
}
<?php

namespace FW\Installer\Command;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
use Symfony\Component\Filesystem\Filesystem;

use FW\Installer\App;
use FW\Installer\Helpers\Process;
use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\VersionUtils;
use FW\Installer\Utils\File;
use FW\Installer\Utils\Config;

class Setup extends BaseCommand {

    /**
     * Bitbucket repo containing FW API builds
     * @var string
     */
    const API_REPO = 'https://api.bitbucket.org/2.0/repositories/linformatics/fw-api/';

    /** @inheritdoc */
    protected static $loadRegistry = false;

    /**
     * Sets up the current directory for FW apps or updates the FW API
     * @param  string $version Version to install
     */
    public function execute($version) {
        $prevVersion = null;
        $rollback = $this->input->getOption('rollback');
        $update = $rollback || $this->input->getOption('update');
        if ($update) {
            // if updating, we must be in a FW root
            if ($this->context->location != App::LOCATION_ROOT) {
                throw new CommandException('You must be at the root of a valid FW installation to use this command.');
            }

            // if updating, determine what we are updating from in order to limit to newer versions
            $config = new Config('.fw');
            $prevVersion = $config->get('apiVersion');
        }

        $migrate = $this->input->getOption('migrate');
        $fs = new Filesystem();

        if ($migrate) {
            if (!file_exists(path_resolve('.fw-installer'))) {
                throw new CommandException('Migration can only be run inside a legacy fw-installer setup');
            }

            $apps = json_decode(file_get_contents('apps.json'), true);

            $filesToRemove = array_filter(scandir(getcwd()), function ($file) {
                // Don't try to remove ., .., the apps folder, or the config folder
                return !in_array($file, ['.', '..', 'apps', 'config']);
            });

            $fs->remove($filesToRemove);

            foreach ($apps as $appCode => $appDir) {
                $fs->rename($appDir, path_resolve('apps', $appCode), true);
            }
        } else {
            $directory = $this->input->getOption('directory') ?: getcwd();

            // if updating
            if($update) {
                // verify that there is no .git in the core directory so we don't update to a dev FW enviroment
                if(in_array('.git', scandir($directory . "/core"))) {
                    throw new CommandException("Directory specified ({$directory}) is a FW API development environment.");
                }
            // Otherwise verify that the directory we want to install FW in exists and is empty
            } else if (!File::ensureOutputDirectory($directory)) {
                throw new CommandException("Directory specified ({$directory}) could not be created or is not empty.");
            }

            // Now that we've ensured the directory is set up, chdir into it
            chdir($directory);
        }

        // grab our versions list
        $availableVersions = $this->getVersions();
        $versionToUse = VersionUtils::getVersionToInstall(array_keys($availableVersions), $version, $prevVersion, $rollback);

        if (!$versionToUse) {
            // No versions to update to, if user supplies a force option we will use the latest available version
            if (!$rollback && $this->input->getOption('force')) {
                $versionToUse = $availableVersions[0];
            } else {
                $this->io->success($rollback ? 'No version for rollback' : 'No new available versions.');
                return;
            }
        }

        // Download and extract the FW Api version that we want to use
        $this->task('download', [
            'provider' => new \FW\Installer\Providers\Github('bennerlibrary', 'fw-api'),
            'version' => $availableVersions[$versionToUse], // ✅ pass URL as "version"
            'dir' => './core',
            'update' => $update,
            'remove' => $update
        ], "Downloading FW Api v{$versionToUse}");

        // Run `composer install`
        $this->task('composer', ['dir' => './core'], 'Installing dependencies');

        // Do some additional filesystem work
        // when updating these already exist
        if(!$update) {
            $fs->mkdir('./apps');
            $fs->mkdir('./config');
        }
        $fs->copy('./core/config/global.php', './config/global.php', false);
        $fs->copy('./core/api.php', './api.php', true);

        if ($this->input->getOption('production')) {
            $globalConf = new Config('./config/global.php', 'php');
            $globalConf->set('mode', 'production')->save();
        }

        $config = new Config('.fw');
        $config->set([
            'apiVersion' => $versionToUse,
            'installerVersion' => $this->command->getApplication()->getVersion()
        ]);

        if ($this->input->getOption('webroot')) {
            $config->set('webroot', $this->input->getOption('webroot'));
        }

        $config->save();
        $this->io->success('Setup complete.');
    }

    /**
     * Gets a list of all FW API versions
     * @return array associative array of version number to URL
     */
    protected function getVersions() {

    $owner = 'bennerlibrary';
    $repo = 'fw-api';

    // load credentials the same way your provider does
    $creds = \FW\Installer\Utils\SystemConfig::load('github-credentials');
    $token = $creds->get('token');

    if (!$token) {
        throw new \RuntimeException('GitHub token required. Run fw login github.');
    }

    $client = new \GuzzleHttp\Client([
        'headers' => [
            'Authorization' => "Bearer {$token}",
            'User-Agent' => 'fw-installer',
            'Accept' => 'application/vnd.github+json'
        ]
    ]);

    $url = "https://api.github.com/repos/{$owner}/{$repo}/releases";

    $response = $client->get($url);
    $data = json_decode(\GuzzleHttp\Psr7\Utils::copyToString($response->getBody()), true);

    $versions = [];

    foreach ($data as $release) {
        if (empty($release['tag_name'])) {
            continue;
        }

        // normalize "v1.2.0" → "1.2.0"
        $version = ltrim($release['tag_name'], 'v');

        //  prefer uploaded asset if exists
        if (!empty($release['assets'])) {
            foreach ($release['assets'] as $asset) {
                if (str_ends_with($asset['name'], '.zip')) {
                    $versions[$version] = $asset['url'];
                    break;
                }
            }
        }

        // fallback to GitHub auto-zip
        if (!isset($versions[$version])) {
            $versions[$version] = $release['zipball_url'];
        }
    }

    // Sort newest release first
    uksort($versions, fn($a, $b) => version_compare($b, $a));

    return $versions;
    }
}
<?php

namespace FW\Installer\Command;

use FW\Installer\Utils\RunContext;
use Stringy\StaticStringy as S;

/**
 * This command is used to run the sub-parts of various tasks. Because there is no easy
 * way to use a loading spinner in PHP (it's single-threaded and a loading spinner
 * requires multi-threading), this task command is called as a sub-command so that
 * we can use a loading spinner
 */
class Task extends BaseCommand {

    /**
     * Runs an FW task, primarily used internally
     * @param  string $taskName Task to execute
     */
    public function execute($taskName) {
        $taskClass = '\FW\Installer\Task\\' . S::upperCamelize($taskName);

        if (!class_exists($taskClass) || !is_a($taskClass, '\FW\Installer\Task\AbstractTask', true)) {
            throw new \InvalidArgumentException("Task {$name} is not defined or is not a valid task.");
        }

        $task = new $taskClass($taskName, $this->io, $this->context, $this->registry);

        if ($this->input->getOption('undo')) {
            $task->undo();
        } else {
            $task->run();
        }

        $this->context->save();
    }
}
<?php

namespace FW\Installer\Command;

use FW\Installer\App;
use FW\Installer\Providers\BaseProvider;
use FW\Installer\Utils\AppInstall;
use FW\Installer\Utils\CommandException;
use FW\Installer\Utils\Config;
use FW\Installer\Utils\Dependencies;
use FW\Installer\Utils\Registry;
use FW\Installer\Utils\VersionUtils;

use Symfony\Component\Filesystem\Filesystem;

class Update extends BaseCommand {

    /**
     * Updates an FW app
     * @param  string $app     App to update, not required inside an app folder
     * @param  string $version Version to update, if undefined updates to the latest version
     */
    public function execute($app, $version) {
        // TODO: a lot of redundant logic exists between this and install, a superclass might be worth it
        // If we are inside an app folder, determine the app to update
        // from the appId of the app folder we're in
        if ($this->context->location == App::LOCATION_APP) {
            $appConfig = new Config('fw.json');
            $app = $appConfig->get('appId');
            $appFolder = getcwd();
            chdir('../..'); // We need to be at the API root in order for some tasks to run correctly
        } else if ($this->context->location == App::LOCATION_ROOT) {
            if (!$app) {
                throw new CommandException('You must supply an app id to update!');
            }

            $appFolder = path_resolve('apps', $app);

            if (!file_exists($appFolder)) {
                throw new CommandException("App '{$app}' has not been installed.");
            }

            $appConfig = new Config(path_join($appFolder, 'fw.json'));
        } else {
            throw new CommandException('You must only run this command from the root of an FW install or in an app folder');
        }

        $webroot = $appConfig->get('webroot');
        $url = $appConfig->get('url');

        if (file_exists(path_join($appFolder, '.git'))) {
            // If the .git folder exists, we're inside of a git clone,
            // so abort updating because we don't want to screw things up
            throw new CommandException('You are attempting to update an app cloned from a git repository' .
                ' This can have unintended consequences, aborting.');
        }

        $availableVersions = $this->registry->versions('app', $app);

        if (!$availableVersions) {
            throw new CommandException("App '{$app}' does not exist in the registry.");
        }

        $rollback = $this->input->getOption('rollback');

        if ($rollback && !$this->io->confirm('Warning, this will only rollback the app! '.
                "Features from addons such as database migrations may need rollback first.\n" .
                ' Do you want to continue with the rollback?')) {
            return;
        }

        $versionToUse = VersionUtils::getVersionToInstall(
            $availableVersions['versions'],
            $version,
            $appConfig->get('version'),
            $rollback
        );

        if (!$versionToUse) {
            // No versions to update to, if user supplies a force option we will use the latest available version
            if (!$rollback && $this->input->getOption('force')) {
                $versionToUse = $availableVersions[0];
            } else {
                $this->io->success($rollback ? 'No version for rollback' : 'No new available versions.');
                return;
            }
        }

        $typeInfo = $this->registry->json('app', $app, $versionToUse);
        $typeJson = $typeInfo['json'];
        $provider = BaseProvider::providerFor($typeJson['repo']);

        if (!$provider) {
            throw new CommandException("Provider could not be determined for '{$app}'");
        }

        $rootConfig = new Config('.fw');

        $deps = new Dependencies($rootConfig, $this->registry, $typeJson['dependencies'] ?? []);
        $conflicts = $deps->invalid();

        if (count($conflicts)) {
            $this->io->error("App '{$app}' could not be updated for the following reasons:");

            foreach ($conflicts as $index => $message) {
                $i = $index + 1; // Arrays are 0-indexed and we want a list starting from 1.
                $this->io->writeln("{$i}. {$message}");
            }

            return;
        }

        $source = $typeInfo['version'];

        if ($provider instanceof \FW\Installer\Providers\Github) {
            $source = $provider->getReleaseAssetUrl($typeInfo['version']);
        }

        $this->task('download', [
            'provider' => $provider,
            'version'  => $source,
            'dir'      => $appFolder,
            'update'   => true
        ], "Downloading {$typeInfo['name']} v{$typeInfo['version']}");

        if (file_exists(path_join($appFolder, 'server', 'composer.json'))) {
            $this->task('composer', [
                'dir' => path_join($appFolder, 'server')
            ], 'Installing composer dependencies');
        }

        $this->io->confirm($webroot);
        if (!$webroot) {
            $webroot = $rootConfig->get('webroot') ?:
                $this->io->ask('Web Root', './public', function ($webroot) {
                    if (!file_exists(realpath($webroot))) {
                        if (rtrim($webroot, '/\\') == './public') {
                            $fs = new Filesystem();
                            $fs->mkdir('./public');
                            return $webroot;
                        }

                        throw new \RuntimeException('Webroot folder does not exist.');
                    }

                    return $webroot;
                });
        }

        if (!$url) {
            $url = $this->io->ask('App Url', "/{$app}/");
        }

        $appConfig->reload();
        $appConfig->set('webroot', $webroot)->set('url', $url)->save();

        $this->task('assets', [
            'install' => $appFolder,
            'webroot' => $webroot,
            'url' => $url,
            'update' => true
        ], 'Updating public files');

        foreach ($deps->addons() as $addon => $version) {
            $this->task('addon', [
                'addon' => $addon,
                'version' => $version,
                'install' => $appFolder,
                'update' => true
            ], "Updating addon '{$addon}'");
        }

        if (file_exists(path_join($appFolder, 'install.php'))) {
            $globalConfig = new Config(path_resolve('config/local.php'), 'php', true);
            $localConfig = new Config(path_resolve($appFolder, 'server/config/local.php'), 'php', true);

            $appInstall = new AppInstall($this->io, $globalConfig, $localConfig, path_join($appFolder, 'install.php'));
            chdir($appFolder);

            $appInstall->run(true);
        }

        $action = $rollback ? 'rollback' : 'updated';
        $this->io->success("App '{$app}' $action to version '{$typeInfo['version']}'");
    }
}
<?php

namespace FW\Installer\Helpers;

use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process as ProcessRunner;

class Process {

    private static $defaultOptions = [
        'spinner' => ['/', '-', '\\', '|'],
        'message' => null, // Will use command name
        'cwd' => null, // Will use getcwd()
        'env' => null,
        'timeout' => null
    ];

    protected $spinFrames;
    protected $message;
    protected $process;
    protected $output;
    protected $suppressOutput;

    public function __construct(array $command, OutputInterface $output, array $options = [], $suppressOutput = false) {
        $options = array_merge(self::$defaultOptions, $options);
        $stringCommand = join(" ", $command);
        $this->message = $options['message'] ?: "Running command '$stringCommand'";
        $this->spinFrames = $options['spinner'];
        $this->process = new ProcessRunner($command, $options['cwd'], $options['env'], null, $options['timeout']);
        $this->output = $output;
        $this->suppressOutput = $suppressOutput;
    }

    public function run() {
        if ($this->suppressOutput) {
            $this->process->run();
            return $this->process->isSuccessful();
        }

        if (strtolower(substr(PHP_OS, 0, 3)) !== 'win') {
            $this->output->write("\033[?25l");
        }

        $spinPos = 0;
        $this->process->start();

        while ($this->process->isRunning()) {
            $this->output->write("{$this->message}: {$this->spinFrames[$spinPos]}\r");
            $spinPos = ($spinPos + 1) % count($this->spinFrames);
            usleep(85000);
        }

        $finish = $this->process->isSuccessful() ? "<info>Complete!</info>" : "<fg=red>Failed!</>";
        $this->output->writeln("{$this->message}: {$finish}");

        if (strtolower(substr(PHP_OS, 0, 3)) !== 'win') {
            $this->output->write("\033[?25h");
        }

        return $this->process->isSuccessful();
    }

    public function getOutput() {
        return $this->process->getOutput();
    }

    public function getErrorOutput() {
        return $this->process->getErrorOutput();
    }

    public function getErrorMessage($name) {
        if ($this->process->isSuccessful()) {
            throw new \InvalidArgumentException('Expected a failed process, but the given process was successful.');
        }
        $error = "Task {$name} failed";
        $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s\n\n================",
            $this->process->getOutput(),
            $this->process->getErrorOutput()
        );
        return $error;
    }
}
<?php

namespace FW\Installer\Helpers;

use Symfony\Component\Console\Style\SymfonyStyle;
use FW\Installer\Utils\Config;

class Prompt {

    protected $io;
    protected $config;

    public function __construct(SymfonyStyle $io, Config $config) {
        $this->io = $io;
        $this->config = $config;
    }

    public function ask(string $section, array $prompts) {
        if ($this->config->has($section) &&
            !$this->io->confirm("The section '{$section}' is already defined in your config." .
                ' Do you want to re-configure it?', false)) {
            return;
        }

        $this->io->section("{$section} configuration");
        $single = false;

        if ($prompts['single'] ?? false) {
            $single = true;
            $prompts = [
                $section => $prompts['value']
            ];
        }

        foreach ($prompts as $itemKey => $promptConfig) {
            $result = $this->runSingle($promptConfig);

            if (is_null($result)) {
                continue;
            }

            $this->config->set($single ? $section : "{$section}.{$itemKey}", $result);
        }

        $this->config->save();
    }

    protected function runSingle($prompt) {
        $type = isset($prompt['type']) ? $prompt['type'] : '';
        $hidden = isset($prompt['hidden']) ? $prompt['hidden'] : false;
        $default = isset($prompt['default']) ? $prompt['default'] : '';
        $required = isset($prompt['required']) ? $prompt['required'] : false;
        $choices = isset($prompt['choices']) ? $prompt['choices'] : [];


        if ($type == 'bool') {
            $default = (bool) $default;
        } else if ($type == 'int') {
            $default = intval($default);
        }

        if (!empty($choices)) {
            $default = $default ?: null;
            $value = $this->io->choice($prompt['prompt'], $choices, $default);
        } else {
            $method = ($type == 'bool') ? 'confirm' : 'ask';

            $isValueProvided = true;

            $validator = function ($answer) use (&$isValueProvided, $required) {
                if (!$answer && !$required) {
                    $isValueProvided = false;
                    return '*optional*';
                } else if (!$answer) {
                    throw new \RuntimeException('A value is required.');
                }

                return $answer;
            };

            if ($hidden) {
                $value = $this->io->askHidden($prompt['prompt'], $validator);
            } else {
                $value = $this->io->$method($prompt['prompt'], $default, $validator);
            }

            if (!$isValueProvided && $value == '*optional*') {
                return null;
            }
        }
        if ($type == 'int') {
            return intval($value);
        }
        return $value;
    }
}
<?php

namespace FW\Installer\Providers;

use FW\Installer\Utils\CommandException;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

abstract class BaseProvider {

    /**
     * Regular expression used to parse a git repository link and get the provider as well
     * as the repository owner and name
     *
     * @var string
     */
    // @codingStandardsIgnoreLine
    protected static $gitRegex = '/^(?P<host>(git@|https:\/\/)(?P<provider>[\w\.@]+)(\/|:))(?P<owner>[\w,\-,\_]+)\/(?P<repo>[\w,\-,\_]+)(.git){0,1}((\/){0,1})$/i';

    /**
     * List of known providers
     * @var array
     */
    protected static $providers = [
        'Bitbucket',
        'Github'
    ];

    /**
     * Return a Provider instance given a repository URL
     * @param $url
     * @return BaseProvider
     */
    public static function providerFor($url): BaseProvider {
        $urlParts = [];

        if (!preg_match(self::$gitRegex, $url, $urlParts)) {
            return null;
        }

        foreach (self::$providers as $provider) {
            if (preg_match("/{$provider}/i", $urlParts['provider'])) {
                $class = __NAMESPACE__ . "\\{$provider}";

                return new $class($urlParts['owner'], $urlParts['repo']);
            }
        }

        return null;
    }

    public static function handleLogin($provider, SymfonyStyle $io) {
        $provider = ucfirst($provider);

        if (!in_array($provider, self::$providers)) {
            throw new CommandException("Provider '{$provider}' does not exist");
        }

        $class = __NAMESPACE__ . "\\{$provider}";

        if (method_exists($class, 'login')) {
            $class::login($io);
            $io->success('Credentials saved');
        }
    }

    abstract public function download(string $source, StreamInterface $stream);
    abstract public function publish(string $version, StreamInterface $stream);
}
<?php

namespace FW\Installer\Providers;

use GuzzleHttp\Client;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

use FW\Installer\Utils\Config;
use FW\Installer\Utils\SystemConfig;

/**
 * Class Bitbucket
 * Provides handlers for downloading and publishing packages from Bitbucket repositories
 *
 * @package FW\Installer\Providers
 */
class Bitbucket extends BaseProvider {

    const CREDENTIALS_FILE = 'bitbucket-credentials';

    /**
     * Crentials file
     * @var Config
     */
    protected $credentials;

    /**
     * Repository owner
     * @var string
     */
    protected $owner;

    /**
     * Repository name
     * @var string
     */
    protected $repo;

    public function __construct(string $owner, string $repo) {
        $this->owner = $owner;
        $this->repo = $repo;

        $this->credentials = SystemConfig::load(self::CREDENTIALS_FILE);
    }

    /**
     * Download a versioned downloads file from the instantiated owner
     * and repository
     *
     * @param string $version
     * @param StreamInterface $stream
     */
    public function download(string $version, StreamInterface $stream) {
        $url = "https://api.bitbucket.org/2.0/repositories/{$this->owner}/{$this->repo}/downloads/{$version}.zip";

        $requestOpts = [
            'sink' => $stream
        ];

        if ($this->credentials->has('email') && $this->credentials->has('token')) {
            $requestOpts['auth'] = [$this->credentials->get('email'), $this->credentials->get('token')];
        }

        $client = new Client();
        $client->get($url, $requestOpts);
    }

    public function publish(string $version, StreamInterface $stream) {
        $url = "https://api.bitbucket.org/2.0/repositories/{$this->owner}/{$this->repo}/downloads";

        $requestOpts = [
            'multipart' => [
                [
                    'name' => 'files',
                    'contents' => $stream,
                    'filename' => "{$version}.zip"
                ]
            ]
        ];

        if ($this->credentials->has('email') && $this->credentials->has('token')) {
            $requestOpts['auth'] = [$this->credentials->get('email'), $this->credentials->get('token')];
        }

        $client = new Client();
        $client->post($url, $requestOpts);
    }

    public static function login(SymfonyStyle $io) {
        $email = $io->ask('Email', '', function ($email) {
            if (!$email) {
                throw new \RuntimeException('You must supply an email address');
            }

            return $email;
        });

        $token = $io->askHidden('API Token', function ($token) {
            if (!$token) {
                throw new \RuntimeException('You must supply an API token');
            }

            return $token;
        });

        $creds = SystemConfig::load(self::CREDENTIALS_FILE);
        $creds->set('email', $email)->set('token', $token)->save();
    }
}
<?php

namespace FW\Installer\Providers;

use GuzzleHttp\Client;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use FW\Installer\Utils\SystemConfig;

class Github extends BaseProvider {

    const CREDENTIALS_FILE = 'github-credentials';

    protected $credentials;
    protected $owner;
    protected $repo;

    public function __construct(string $owner, string $repo) {
        $this->owner = $owner;
        $this->repo = $repo;

        $this->credentials = SystemConfig::load(self::CREDENTIALS_FILE);
    }

    // Add getters for install logic
    public function getOwner(): string {
        return $this->owner;
    }
    public function getRepo(): string {
        return $this->repo;
    }

    /**
     * Resolve release asset URL (for private repos)
     */
    public function getReleaseAssetUrl(string $version): string {

        $token = trim($this->credentials->get('token'));

        if (!$token) {
            throw new \RuntimeException('GitHub token required.');
        }

        $client = new Client([
            'headers' => [
                'Authorization' => "token {$token}",
                'User-Agent'    => 'fw-installer',
                'Accept'        => 'application/vnd.github+json'
            ]
        ]);

        $url = "https://api.github.com/repos/{$this->owner}/{$this->repo}/releases";

        $response = $client->get($url);
        $data = json_decode(\GuzzleHttp\Psr7\Utils::copyToString($response->getBody()), true);

        foreach ($data as $release) {
            $tag = $release['tag_name'];
            $v = ltrim($tag, 'v');

            if ($v === $version && !empty($release['assets'])) {
                return $release['assets'][0]['url']; // ✅ correct API URL
            }
        }

        throw new \RuntimeException("Release {$version} not found for {$this->repo}");
    }

    /**
     * Download a release asset
     */
    public function download(string $url, StreamInterface $stream) {

        $token = trim($this->credentials->get('token'));

        if (!$token) {
            throw new \RuntimeException('GitHub token required.');
        }

        $client = new Client([
            'headers' => [
                'Authorization' => "token {$token}",
                'User-Agent'    => 'fw-installer',
                'Accept'        => 'application/octet-stream'
            ]
        ]);

        $client->request('GET', $url, [
            'sink' => $stream
        ]);
    }
    /**
     * Create release and upload asset
     */
    public function publish(string $version, StreamInterface $stream) {

        $token = $this->credentials->get('token');

        if (!$token) {
            throw new \RuntimeException('GitHub token required. Run fw login github.');
        }

        $client = new Client([
            'headers' => [
                'Authorization' => "token {$token}",
                'Accept' => 'application/vnd.github+json',
                'User-Agent' => 'fw-installer'
            ]
        ]);

        // reset stream pointer
        if ($stream->isSeekable()) {
            $stream->rewind();
        }

        // reuse release if it already exists
        try {
            $response = $client->get(
                "https://api.github.com/repos/{$this->owner}/{$this->repo}/releases/tags/v{$version}"
            );

            $releaseData = json_decode($response->getBody(), true);

        } catch (\Exception $e) {
            // create if not found
            $response = $client->post(
                "https://api.github.com/repos/{$this->owner}/{$this->repo}/releases",
                [
                    'json' => [
                        'tag_name' => "v{$version}",
                        'name' => "v{$version}",
                        'draft' => false,
                        'prerelease' => false
                    ]
                ]
            );

            $releaseData = json_decode($response->getBody(), true);
        }

        if (!isset($releaseData['upload_url'])) {
            throw new \RuntimeException('Failed to create or fetch GitHub release');
        }

        $uploadUrl = explode('{', $releaseData['upload_url'])[0];

        // remove existing asset with same name
        if (!empty($releaseData['assets'])) {
            foreach ($releaseData['assets'] as $asset) {
                if ($asset['name'] === "fw-api-{$version}.zip") {
                    $client->delete($asset['url'], [
                        'headers' => [
                            'Accept' => 'application/vnd.github+json'
                        ]
                    ]);
                }
            }
        }

        // Upload asset
        $client->post(
            "{$uploadUrl}?name=fw-api-{$version}.zip",
            [
                'headers' => [
                    'Content-Type' => 'application/zip'
                ],
                'body' => $stream
            ]
        );
    }

    /**
     * Store GitHub token
     */
    public static function login(SymfonyStyle $io) {
        $token = $io->askHidden('GitHub Personal Access Token', function ($token) {
            if (!$token) {
                throw new \RuntimeException('Token is required');
            }
            return trim($token);
        });

        $creds = SystemConfig::load(self::CREDENTIALS_FILE);
        $creds->set('token', $token)->save();
    }
}<?php

namespace FW\Installer\Task;

use FW\Installer\Utils\RunContext;
use FW\Installer\Utils\Registry;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Stringy\StaticStringy as S;

abstract class AbstractTask {

    /**
     * @var string
     */
    protected $name;

    /**
     * @var array
     */
    protected $options;

    /**
     * @var SymfonyStyle
     */
    protected $io;

    /**
     * @var RunContext
     */
    protected $context;

    /**
     * @var Registry
     */
    protected $registry;

    public function __construct($name, SymfonyStyle $io, RunContext $context, Registry $registry, array $options = []) {
        $this->name = $name;
        $this->io = $io;
        $this->context = $context;
        $this->registry = $registry;

        $this->options = count($options) ? $options : $this->context->taskOptions;
    }

    abstract public function run();
    abstract public function undo();

    protected function validateOptions(array $keysToCheck) {
        $missingOpts = [];

        foreach ($keysToCheck as $key) {
            if (!isset($this->options[$key])) {
                $missingOpts[] = $key;
            }
        }

        if (count($missingOpts)) {
            throw new \RuntimeException("Missing options for task {$this->name}: " . implode(', ', $missingOpts));
        }
    }

    protected function subTask(string $taskName, array $options) {
        $taskClass = '\FW\Installer\Task\\' . S::upperCamelize($taskName);

        if (!class_exists($taskClass) || !is_a($taskClass, '\FW\Installer\Task\AbstractTask', true)) {
            throw new \InvalidArgumentException("Task {$name} is not defined or is not a valid task.");
        }

        $subTask = new $taskClass($taskName, $this->io, $this->context, $this->registry, $options);
        $subTask->run();
        return $subTask;
    }
}
<?php

namespace FW\Installer\Task;

use FW\Installer\Providers\BaseProvider;
use FW\Installer\Utils\Registry;
use FW\Installer\Utils\Config;

class Addon extends AbstractTask {

    public function run() {
        $this->validateOptions(['install', 'addon', 'version']);

        $addon = $this->options['addon'];
        $addonInfo = $this->registry->json('addon', $addon, $this->options['version']);
        $addonMeta = $addonInfo['json'];

        $provider = BaseProvider::providerFor($addonMeta['repo']);

        if (!$provider) {
            throw new \RuntimeException("Provider could not be determined for addon '{$addon}'");
        }

        $addonInstallDir = path_join($this->options['install'], 'addons', $addon);
        $update = (bool) ($this->options['update'] ?? false);

        if (file_exists($addonInstallDir)) {
            if (!$update) {
                // Addon is already installed and we are not updating, skip
                return;
            }

            if (is_link($addonInstallDir)) {
                // Addon is under development and has been linked via the
                // `fw link` command, we don't want to override it
                return;
            }

            $currentAddon = new Config(path_join($addonInstallDir, 'fw.json'));

            if ($currentAddon->get('version', $addonInfo['version']) == $addonInfo['version']) {
                // Addon versions are the same, skip
                return;
            }
        }

        // Download addon
        $source = $addonInfo['version'];

        if ($provider instanceof \FW\Installer\Providers\Github) {
            $source = $provider->getReleaseAssetUrl($addonInfo['version']);
        }

        $this->subTask('download', [
            'provider' => $provider,
            'version' => $source,
            'dir' => $addonInstallDir,
            'update' => $update,
            'remove' => true
        ]);

        // if composer.json exists, run composer subtask
        if (file_exists(path_join($addonInstallDir, 'composer.json'))) {
            $this->subTask(
                'composer',
                ['dir' => $addonInstallDir],
                "Installing composer dependencies for '{$addon}'"
            );

            if (!file_exists(path_join($addonInstallDir, 'vendor/autoload.php'))) {
                throw new \RuntimeException("Composer install failed for '{$addon}'");
            }
        }
    }

    public function undo() {
    }
}
<?php

namespace FW\Installer\Task;

use Symfony\Component\Filesystem\Filesystem;

class Assets extends AbstractTask {

    protected $webPath;

    public function run() {
        $this->validateOptions(['install', 'webroot', 'url']);
        $fs = new Filesystem();

        $webPath = path_resolve($this->options['webroot'], $this->options['url']);
        $publicDir = path_join($this->options['install'], 'public');

        if ($this->options['update'] ?? false) {
            $fs->remove($webPath);
        }

        $fs->mkdir($webPath);

        $public = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator(
                $publicDir,
                \FilesystemIterator::KEY_AS_PATHNAME |
                \FilesystemIterator::CURRENT_AS_FILEINFO |
                \FilesystemIterator::FOLLOW_SYMLINKS |
                \FilesystemIterator::SKIP_DOTS
            ),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($public as $path => $file) {
            // skip if file is directory
            if ($file->isDir()) {
                continue;
            }

            $publicPath = path_join(
                $webPath,
                $fs->makePathRelative(dirname($path), $publicDir),
                $file->getBasename()
            );

            $strippedURL = trim($this->options['url'], '/');

            if ($file->getExtension() == 'php') {
                $apiPath = $fs->makePathRelative(getcwd(), dirname($publicPath));
                $contents = str_replace('{{api}}', "{$apiPath}api.php", file_get_contents($path));
                $fs->dumpFile($publicPath, $contents);
            } else if (in_array($file->getExtension(), ['html', 'js', 'css', 'webmanifest'])) {
                $contents = str_replace('@@ROOT_URL@@', $strippedURL, file_get_contents($path));
                $fs->dumpFile($publicPath, $contents);
            } else {
                $fs->copy($path, $publicPath, true);
            }
        }
    }

    public function undo() {
    }
}
<?php

namespace FW\Installer\Task;

use FW\Installer\Helpers\Process;

class Composer extends AbstractTask {

    protected $dir;
    protected $completed = false;

    public function run() {
        $this->validateOptions(['dir']);

        if (!file_exists(path_join($this->options['dir'], 'composer.json'))) {
            return true;
        }

        $composer = new Process(["composer", "install", "-o", "--no-dev"], $this->io, [
            'cwd' => $this->options['dir']
        ], true);

        if (!$composer->run()) {
            throw new \RuntimeException('Composer install failed.');
        }

        $this->dir = $this->options['dir'];
        $this->completed = true;
    }

    public function undo() {
        if (!$this->completed) {
            return true;
        }

        return Utils\File::remove($this->dir . '/vendor');
    }
}
<?php

namespace FW\Installer\Task;

use FW\Installer\Utils\File;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;

class Download extends AbstractTask {
    protected $directory;

    public function run() {
        $this->validateOptions(['dir']);
        $target = rtrim($this->options['dir'], '/\\');
        $update = (bool) ($this->options['update'] ?? false);
        $remove = (bool) ($this->options['remove'] ?? false);

        // Step 1: Ensure output directory can be created, and is not empty
        if (!File::ensureOutputDirectory($target)) {
            if (!$update) {
                throw new \RuntimeException('Output directory could not be created or is not empty.');
            }

            if ($update && $remove) {
                File::remove($target);
            }
        }

        $tmp = tmpfile();
        $stream = Psr7\Utils::streamFor($tmp);

        if (isset($this->options['provider']) && isset($this->options['version'])) {
            $provider = $this->options['provider'];
            $provider->download($this->options['version'], $stream);
        } else if (isset($this->options['url']) && !empty($this->options['url'])) {
            $client = new Client();
            $client->get($this->options['url'], ['sink' => $stream]);
        } else {
            throw new \InvalidArgumentException('Either a provider & version or a url must be specified');
        }

        $zip = new \ZipArchive();

        if ($zip->open($stream->getMetadata('uri')) !== true) {
            throw new \RuntimeException('Zip could not be opened');
        }

        $zip->extractTo($target);
        $zip->close();
        fclose($tmp);

        $this->directory = $target;
    }

    public function undo() {
        if (!$this->directory) {
            return true;
        }

        return Utils\File::remove($this->directory);
    }
}
<?php

namespace FW\Installer\Task;

use Bit3\GitPhp\GitRepository;
use Bit3\GitPhp\GitException;

class GitClone extends AbstractTask {

    public function run() {
        $this->validateOptions(['dir', 'url']);

        $repo = new GitRepository($this->options['dir']);
        $repo->cloneRepository()->execute($this->options['url']);
    }

    public function undo() {
    }
}
<?php

namespace FW\Installer\Utils;

use FW\Installer\Helpers\Prompt;
use FW\Installer\Helpers\Process;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Exception\InvalidArgumentException;

/**
 * When apps are installed, they have the ability to define some custom behavior that is called
 * during the install process. The function that we support returning from an install.php will
 * be called with an instance of this class as its context, so this class contains some basic
 * utilities that will be useful to apps during installation.
 *
 * Class AppInstall
 *
 * @package FW\Installer\Utils
 */
class AppInstall {

    /**
     * IO Handler
     * @var SymfonyStyle
     */
    protected $io;

    /**
     * Global configuration file
     * @var Config
     */
    protected $globalConfig;

    /**
     * Local app configuration file
     * @var Config
     */
    protected $appConfig;

    /**
     * Callback App function
     * @var \Closure
     */
    protected $appFn;

    /**
     * AppInstall constructor.
     * @param SymfonyStyle $io
     * @param Config $globalConfig
     * @param Config $appConfig
     * @param string $pathToFn
     */
    public function __construct(SymfonyStyle $io, Config $globalConfig, Config $appConfig, string $pathToFn) {
        $this->io = $io;
        $this->globalConfig = $globalConfig;
        $this->appConfig = $appConfig;

        $this->appFn = require_once($pathToFn);

        if (!($this->appFn instanceof \Closure)) {
            throw new \InvalidArgumentException('install.php does not contain a vaild function');
        }
    }

    /**
     * @param string $cmd
     * @param string $message
     * @param array $options
     */
    public function process(string $cmd, string $message, array $options = []) {
        $options['message'] = $message;

        $process = new Process(explode(" ", $cmd), $this->io, $options);

        // TODO: error handling
        if (!$process->run()) {
            echo $process->getOutput();
        }

        return;
    }

    /**
     * @param string $configType
     * @param string $section
     * @param array $prompts
     * @return AppInstall the current instance
     */
    public function prompt(string $configType, string $section, array $prompts): AppInstall {
        $config = strtolower($configType) . "Config";
        $prompt = new Prompt($this->io, $this->$config);
        $prompt->ask($section, $prompts);

        return $this;
    }

    /**
     * @param string $configType
     * @param string $section
     * @return mixed config value for section
     */
    public function getFromConfig(string $configType, string $section) {
        if (strtolower($configType) != 'app' && strtolower($configType) != 'global') {
            throw new InvalidArgumentException("Invalid config type: $configType! Your Config Type must be either 'app' or 'global'");
        }
        $config = strtolower($configType) . "Config";

        return $this->$config->get($section, null);
    }



    /**
     * @return mixed
     */
    public function run(bool $update = false) {
        $fn = $this->appFn->bindTo($this);

        return $fn($update);
    }
}
<?php

namespace FW\Installer\Utils;

/**
 * Exception when the user provides wrong input (arguments or context) to a command.
 * Unlike InvalidArgumentException, this is only thrown by our code thus is caught
 *
 * @author Austin Burdine <aburdine@olivet.edu>
 * @since  1.0.3
 */
class CommandException extends \Exception {
    /**
     * Constructs a new instance
     * @param string     $message   Message to display for the exception
     * @param \Exception $previous  Exception to print if verbosity is debug
     */
    public function __construct(string $message, ?\Exception $previous = NULL) {
        parent::__construct($message, 0, $previous);
    }
}
<?php

namespace FW\Installer\Utils;

class Config {

    private static $validTypes = ['php', 'json'];

    protected $values;
    protected $type;
    protected $file;

    public function __construct($file, $type = 'json', $absolute = false) {
        if (!file_exists($file)) {
            $this->values = [];
            $this->type = $type;
            $this->file = $absolute ? $file : path_resolve($file);
            return;
        }

        $this->file = realpath($file);

        $extension = substr(strrchr($this->file, "."), 1);
        $type = in_array($extension, self::$validTypes) ? $extension : $type;

        if (!in_array($type, self::$validTypes)) {
            throw new \InvalidArgumentException("Invalid config type: '{$type}'");
        }

        $this->type = $type;

        if ($type == 'json') {
            $this->values = json_decode(file_get_contents($this->file), true) ?: [];
        } else if ($type == 'php') {
            $this->values = require $this->file;
        }
    }

    public function all(): array {
        return $this->values;
    }

    public function has($key): bool {
        return array_has($this->values, $key);
    }

    public function get($key, $alt = '') {
        return array_get($this->values, $key, $alt);
    }

    public function set($key, $value = null): Config {
        if (!$value && is_array($key)) {
            foreach ($key as $k => $v) {
                array_set($this->values, $k, $v);
            }

            return $this;
        }

        array_set($this->values, $key, $value);
        return $this;
    }

    public function save() {
        // ensure directory is created if it doesn't exist
        if (!file_exists(dirname($this->file))) {
            mkdir(dirname($this->file), 0755, true);
        }

        $contents = '';

        if ($this->type == 'php') {
            $contents = '<?php return ' . var_export($this->values, true) . ';';
        } else if ($this->type == 'json') {
            $contents = json_encode($this->values, JSON_FORCE_OBJECT);
        }

        return file_put_contents($this->file, $contents);
    }

    public function reload() {
        if (!file_exists($this->file)) {
            return;
        }

        if ($this->type == 'json') {
            $this->values = json_decode(file_get_contents($this->file), true) ?: [];
        } else if ($this->type == 'php') {
            $this->values = require $this->file;
        }
    }
}
<?php

namespace FW\Installer\Utils;

use Composer\Semver\Semver;

class Dependencies {

    protected $deps;
    protected $registry;
    protected $apiVersion;
    protected $rootFolder;

    protected $addons;

    public function __construct(Config $config, Registry $registry, array $deps) {
        $this->deps = $deps;
        $this->registry = $registry;
        $this->apiVersion = $config->get('apiVersion');

        $this->addons = [];
    }

    public function invalid() {
        $invalid = [];

        if (isset($this->deps['api']) && !Semver::satisfies($this->apiVersion, $this->deps['api'])) {
            $invalid[] = "Invalid fw-api Version. Run `fw setup --update` to install latest version.\n" .
                "    Required: <fg=cyan>{$this->deps['api']}</>\n" .
                "    Installed: <fg=yellow>{$this->apiVersion}</>";
        }

        if (isset($this->deps['apps'])) {
            $apps = $this->getInstalledApps();

            foreach ($this->deps['apps'] as $appCode => $version) {
                if (!isset($apps[$appCode])) {
                    // App is not installed
                    $invalid[] = "Missing app: '{$appCode}'. Run `fw install {$appCode}` to install the app.";
                } else if (!Semver::satisfies($apps[$appCode], $version)) {
                    // App version is different than the one required by the app we're trying to install
                    $invalid[] = "Invalid version for app '{$appCode}'. Run `fw update {$appCode}` to update the app.\n" .
                        "    Required: <fg=cyan>{$version}</>\n" .
                        "    Installed: <fg=yellow>{$apps[$appCode]}</>";
                }
            }
        }

        if (isset($this->deps['addons'])) {
            foreach ($this->deps['addons'] as $addon => $version) {
                $availableVersions = $this->registry->versions('addon', $addon);

                if (!$availableVersions) {
                    $invalid[] = "Addon not found in registry: '{$addon}'";
                    continue;
                }

                $resolvedVersion = null;

                foreach ($availableVersions['versions'] as $ver) {
                    if (Semver::satisfies($ver, $version)) {
                        $resolvedVersion = $ver;
                        break;
                    }
                }

                if (!$resolvedVersion) {
                    $invalid[] = "No valid version found for addon '{$addon}' with version constraint: {$version}";
                    continue;
                }

                $this->addons[$addon] = $resolvedVersion;
            }
        }

        return $invalid;
    }

    public function addons() {
        return $this->addons;
    }

    protected function getInstalledApps() {
        $files = new \FilesystemIterator('apps', \FilesystemIterator::KEY_AS_PATHNAME |
            \FilesystemIterator::CURRENT_AS_FILEINFO |
            \FilesystemIterator::FOLLOW_SYMLINKS |
            \FilesystemIterator::SKIP_DOTS);
        $versions = [];

        foreach ($files as $path => $file) {
            // Skip if not a directory
            if (!$file->isDir()) {
                continue;
            }

            // If fw.json doesn't exist, it's not a valid app or addon, so don't load it
            if (!file_exists("{$path}/fw.json")) {
                continue;
            }

            $appMeta = json_decode(file_get_contents("{$path}/fw.json"), true);
            $versions[$appMeta['appId']] = $appMeta['version'];
        }

        return $versions;
    }
}
<?php

namespace FW\Installer\Utils;

use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;

class ErrorHandler {

    public static function load(EventDispatcher $dispatcher) {
        set_error_handler(array(get_called_class(), 'handleError'));

        $dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleErrorEvent $e) {
            $command = $e->getCommand();
            $input = $e->getInput();
            $output = $e->getOutput();
            $error = $e->getError();

            $output->getFormatter()->setStyle('fwerror', new OutputFormatterStyle('red', 'black', ['bold']));

            $message = $error->getMessage();
            $output->writeln("<fwerror>An error occurred: </fwerror><comment>{$message}</comment>");

            $file = $error->getFile() ?: 'N/A';
            $output->writeln("<fwerror>File: </fwerror><comment>{$file}</comment>");

            $line = $error->getLine() ?: 'N/A';
            $output->writeln("<fwerror>Line Number: </fwerror><comment>{$line}</comment>");

            $output->writeln('<fwerror>Additional Information:</fwerror>');
            if ($command != null) {
                $output->writeln('<fwerror>Command: </fwerror><comment>' . $command->getName() . '</comment>');
            } else {
                $output->writeln('<fwerror>Command: </fwerror><comment>NULL</comment>');
            }
            $output->writeln('<fwerror>Arguments:</fwerror>');

            foreach ($input->getArguments() as $key => $value) {
                if ($key == 'command') {
                    continue;
                }
                $output->writeln("<comment>    {$key}: {$value}</comment>");
            }

            $output->writeln('<fwerror>Options:</fwerror>');

            foreach ($input->getOptions() as $key => $value) {
                $value = $value ?: false;
                $output->writeln("<comment>    {$key}: {$value}</comment>");
            }

            $fileOutput = $error->getMessage() . "\n" . $error->getFile() .
                "\n" . $error->getLine() . "\n" . $error->getTraceAsString();
            file_put_contents(getcwd() . '/fw-installer-error.log', $fileOutput);

            exit(1);
        });
    }

    /**
     * Handle PHP error
     * @param  int $errno
     * @param  string $errstr
     * @param  string $errfile
     * @param  int $errline
     */
    public static function handleError($errno, $errstr, $errfile, $errline) {
        throw new \ErrorException($errstr, $errno, $errno, $errfile, $errline);
    }
}
<?php

namespace FW\Installer\Utils;

use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;

class File {

    public static function remove($dir) {
        $fs = new Filesystem();

        try {
            $fs->remove($dir);
            return true;
        } catch (IOExceptionInterface $e) {
            return false;
        }
    }

    /**
     * Ensure output directory exists and is empty
     *
     * @param string $dir Directory to create and verify
     * @return boolean
     */
    public static function ensureOutputDirectory($dir) {
        $fs = new Filesystem();

        try {
            $fs->mkdir($dir);

            return self::directoryEmpty($dir);
        } catch (IOExceptionInterface $e) {
            return false;
        }
    }

    protected static function directoryEmpty($dir) {
        $files = scandir($dir);
        $count = count($files);
        // declare the directory empty if only the error log exists
        return $count == 2 || ($count == 3 && in_array('fw-installer-error.log', $files));
    }
}
<?php

namespace FW\Installer\Utils;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Composer\Semver\Semver;
use Symfony\Component\Console\Style\SymfonyStyle;

use FW\Installer\Utils\SystemConfig;

class Registry {

    const REGISTRY_URL = 'https://fw.bennerlibrary.com/';
    const CREDENTIALS_FILE = 'fw-credentials';

    protected $client;
    protected $registryVersion;

    public function __construct($installerVersion) {
        $this->client = new Client(['base_uri' => Registry::REGISTRY_URL]);

        $registryMeta = json_decode($this->client->get('/')->getBody()->getContents(), true);

        $this->registryVersion = $registryMeta['versions']['registry'];

        if (!Semver::satisfies($installerVersion, $registryMeta['versions']['installer'])) {
            throw new \RuntimeException('This installer version is not compatible with the registry.' .
                'Please ensure you are running the latest version of the installer.');
        }
    }

    public function versions($type, $name) {
        if ($type != 'app' && $type != 'addon') {
            throw new \InvalidArgumentException("Type '{$type}' is not valid.");
        }

        try {
            $result = $this->client->get("/{$type}/{$name}/");
            return json_decode($result->getBody()->getContents(), true);
        } catch (RequestException $e) {
            if ($e->getResponse()->getStatusCode() != 404) {
                throw $e;
            }

            // Registry will return 404 if no versions found
            return null; // No versions found for $name
        }
    }

    public function json($type, $name, $version) {
        if ($type != 'app' && $type != 'addon') {
            throw new \InvalidArgumentException("Type '{$type}' is not valid.");
        }

        try {
            $result = $this->client->get("/{$type}/{$name}/{$version}/");
            return json_decode($result->getBody()->getContents(), true);
        } catch (RequestException $e) {
            if ($e->getResponse()->getStatusCode() != 404) {
                throw $e;
            }

            return null;
        }
    }

    public function publish(string $type, string $name, string $version, array $data) {
        $creds = SystemConfig::load(self::CREDENTIALS_FILE);
        $token = $creds->get('token');

        if (!$token) {
            return false;
        }

        try {
            $this->client->post("/{$type}/{$name}/{$version}/", [
                'json' => [
                    'token' => $token,
                    'json' => $data
                ]
            ]);

            return true;
        } catch (RequestException $e) {
            $status = $e->getResponse()->getStatusCode();

            if ($status == 401) {
                return false;
            } else if ($status == 422) {
                throw new \RuntimeException("Version {$version} already published for {$type} '{$name}'");
            } else {
                throw $e;
            }
        }
    }

    public function login(SymfonyStyle $io, bool $force = false) {
        $loggedIn = false;

        $creds = SystemConfig::load(self::CREDENTIALS_FILE);

        if ($creds->has('token') && !$force) {
            return;
        }

        do {
            $username = $io->ask('Username', '', function ($user) {
                if (!$user) {
                    throw new \RuntimeException('You must supply a username');
                }

                return $user;
            });

            $password = $io->askHidden('Password', function ($pass) {
                if (!$pass) {
                    throw new \RuntimeException('You must supply a password');
                }

                return $pass;
            });

            try {
                $result = $this->client->post('/login/', [
                    'json' => [
                        'user' => $username,
                        'pass' => $password
                    ]
                ]);

                $data = json_decode($result->getBody()->getContents(), true);

                $creds->set('token', $data['token'])->save();
                $loggedIn = true;
            } catch (RequestException $e) {
                $status = $e->getResponse()->getStatusCode();

                if ($status == 404 || $status == 401) {
                    $io->error('Invalid username or password');
                } else {
                    throw $e;
                }
            }
        } while (!$loggedIn);
    }
}
<?php

namespace FW\Installer\Utils;

/**
 * In order to make process spinners run correctly, we need to run command tasks
 * in sub-processes.
 *
 */
class RunContext {

    const SERIAL_FILE = '.fw_installer_context';
    private static $contextInstance;

    protected $values;

    public function __construct(array $initialValues = []) {
        $this->values = $initialValues;
    }

    public function __get($key) {
        return $this->values[$key] ?? null;
    }

    public function __set($key, $value) {
        if (!$value) {
            unset($this->values[$key]);
        } else {
            $this->values[$key] = $value;
        }

        return $this;
    }

    public function all() {
        return $this->values;
    }

    public function reload() {
        $ctx = self::load(false, true);
        $this->values = $ctx->all();
        return $this;
    }

    public function save() {
        $savePath = path_resolve(self::SERIAL_FILE);

        if (file_exists($savePath)) {
            unlink($savePath);
        }

        file_put_contents($savePath, serialize($this));
    }

    public static function load($ignoreContext = false, $ignoreSingleton = false) {
        if (self::$contextInstance && !$ignoreSingleton) {
            return self::$contextInstance;
        }

        $serializedContext = path_resolve(self::SERIAL_FILE);

        if ($ignoreContext || !file_exists($serializedContext)) {
            $ctx = new RunContext();
        } else {
            $ctx = unserialize(file_get_contents($serializedContext));
            unlink($serializedContext);
        }

        if (!$ignoreSingleton) {
            self::$contextInstance = $ctx;
        }

        return $ctx;
    }
}
<?php

namespace FW\Installer\Utils;

/**
 * Class for managing system-level configs
 */
class SystemConfig {

    const SYSTEM_FOLDER = '.fw';

    public static function load($file): Config {
        return new Config(path_join(self::getDataFolder(PHP_OS), $file), 'json', true);
    }

    protected static function getDataFolder($os) {
        if (stristr($os, 'dar') || stristr($os, 'linux')) {
            // System is macOS or Linux, use the HOME folder plus the value of SYSTEM_FOLDER
            return path_join(getenv('HOME'), self::SYSTEM_FOLDER);
        } else if (stristr($os, 'win')) {
            // Platform is Windows, stick things in the AppData folder
            return path_join(getenv('APPDATA'), self::SYSTEM_FOLDER);
        }

        throw new \RuntimeException('Platform \'' . PHP_OS . '\' is not supported.');
    }
}
<?php

namespace FW\Installer\Utils;

use GuzzleHttp\Client;
use Composer\Semver\Comparator;

class Updater
{
    private static $pharUrl = 'https://linformatics.bitbucket.io/installer-new/fw.phar';
    private static $shaUrl = 'https://linformatics.bitbucket.io/installer-new/fw.version';
    private static $versionUrl = 'https://linformatics.bitbucket.io/installer-new/fw.semver';
    private const SHA512_REGEX = '/^[0-9a-f]{128}$/i';
    private $currentVersion;
    private $client;

    public function __construct($currentVersion) {
        $this->currentVersion = $currentVersion;

        $this->client = new Client([
            'headers' => [
                'User-Agent' => 'Mozilla/5.0',
                'Accept'     => '*/*',
            ],
            'timeout' => 30,
        ]);
    }
    // Compatibility shim to keep hasUpdate working
    public function hasUpdate(): bool
    {
        return $this->newVersionAvailable();
    }

    /**
     * Check if a new version is available
     */
    public function newVersionAvailable(): bool
    {
        $remoteSha = $this->getRemoteSha512();
        $localSha  = $this->getLocalSha512();

        if ($remoteSha === $localSha) {
            return false;
        }

        $newSemver = $this->getCurrentRemoteSemver();
        $oldSemver = $this->currentVersion;

        return Comparator::greaterThan($newSemver, $oldSemver);
    }

    /**
     * Download and replace the PHAR
     */
    public function update(string $localPharPath): void
    {
        $tempFile = $localPharPath . '.tmp';

        $response = $this->client->get(self::$pharUrl);
        file_put_contents($tempFile, $response->getBody()->getContents());

        copy($tempFile, $localPharPath);
        @unlink($tempFile);
    }

    private function getRemoteSha512(): string
    {
        $raw = trim(
            $this->client->get(self::$shaUrl)->getBody()->getContents()
        );

        if (!preg_match(self::SHA512_REGEX, $raw)) {
            $preview = substr($raw, 0, 80);
            throw new \RuntimeException(
                "Invalid SHA512 format: \"{$preview}\""
            );
        }

        return $raw;
    }

    private function getLocalSha512(): string
    {
        return hash_file('sha512', \Phar::running(false));
    }

    public function getCurrentRemoteSemver(): string
    {
        $version = trim(
            $this->client->get(self::$versionUrl)->getBody()->getContents()
        );

        if (empty($version)) {
            throw new \RuntimeException("Version request returned empty response.");
        }

        return $version;
    }
}<?php

namespace FW\Installer\Utils;

use Composer\Semver\Comparator;

/**
 * Composer's semver utility doesn't provide a couple
 * of necessary methods, so they are implemented here
 */
class VersionUtils {

    // @codingStandardsIgnoreLine
    private static $semver_regex = '/^\bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b$/i';

    /**
     * @param string $version Version to check
     * @return boolean
     */
    public static function valid(string $version) {
        return preg_match(self::$semver_regex, $version);
    }

    /**
     * Gets the version to install based on the available versions
     * @param  array   $availableVersions Array of valid versions to pull
     * @param  string  $version           Preferred version, if invalid will error
     * @param  string  $previousVersion   Current installed version
     * @param  boolean $rollback          If true, compare to versions before the previous one. If false, compare to after
     * @return string  The version to install from the valid versions
     */
    public static function getVersionToInstall(array $availableVersions, $version = null, ?string $previousVersion = null, bool $rollback = false) {
        if ($previousVersion) {
            // if rollback, ask for versions before this
            if ($rollback) {
                $availableVersions = array_values(array_filter($availableVersions, function ($v) use ($previousVersion) {
                    return Comparator::lessThan($v, $previousVersion);
                }));
            } else {
                $availableVersions = array_values(array_filter($availableVersions, function ($v) use ($previousVersion) {
                    return Comparator::greaterThan($v, $previousVersion);
                }));
            }

            if (empty($availableVersions)) {
                return null;
            }
        }

        if (!$version) {
            return $availableVersions[0];
        }

        if (!VersionUtils::valid($version)) {
            throw new \InvalidArgumentException("Version {$version} is invalid.");
        }

        if (substr($version, 0, 1) == 'v') {
            // Remove trailing v if one exists
            $version = ltrim($version, 'v');
        }

        $filtered = array_values(array_filter($availableVersions, function ($v) use ($version) {
            return $v == $version;
        }));

        if (count($filtered) === 0) {
            throw new \InvalidArgumentException("Version {$version} doesn't exist.");
        }

        return current($filtered);
    }
}
<?php

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, $err);
        } elseif (!headers_sent()) {
            echo $err;
        }
    }
    throw new RuntimeException($err);
}

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit99acc0ea0763a3d8cd50e9c30b597c03::getLoader();
<?php

if (!function_exists('path_normalize_reduce')) {
    /**
     * Helper callback to array_reduce. This is not designed to be called
     * by itself; it is used inside path_join
     *
     * @param array $carry The carry from the array_reduce call
     * @param string $item The current item
     * @return array Array after running the function on it
     */
    function path_normalize_reduce(array $carry, string $item): array {
        if ($item === '.') { // Same directory
            return $carry;
        } else if ($item !== '..' || !count($carry)) {
            // This adds the element to the end of the carry array in two cases
            // 1: Normal part of the path
            // 2: '..', which means go back a directory. Normally we'd remove the last
            //    element of the array in this case, but if the array is empty it means
            //    that all prior elements have also been removed, and the resulting path
            //    will actually go back directories in the end. Therefore, we add it to
            //    the array instead
            $carry[] = $item;
            return $carry;
        }

        $last = array_pop($carry);

        if ($last === '..') {
            // if the previous element is also a .., that means we hit case 2 in the above conditional,
            // so we need to re-add the array element
            array_push($carry, $last, $item);
        }

        return $carry;
    }
}

if (!function_exists('path_join')) {
    function path_join(string $first, string ...$paths): string {
        if (empty($first)) {
            throw new \InvalidArgumentException('The first argument to path_join cannot be an empty string.');
        }

        $splitRegex = '/\/|\\\\/';
        $letter = null;
        $parts = [];

        $firstParts = preg_split($splitRegex, rtrim($first, '/\\'));

        // Check if the first part of the path is a drive letter
        if ($firstParts && count($firstParts) > 0 && preg_match('/[A-Za-z]:/', $firstParts[0])) {
            $letter = array_shift($firstParts);
        }

        $parts = array_reduce($firstParts, 'path_normalize_reduce', []);

        foreach ($paths as $path) {
            // Split path into its composite parts
            $pathParts = preg_split($splitRegex, trim($path, '/\\'));
            // Run it through the reduce function
            $parts = array_reduce($pathParts, 'path_normalize_reduce', $parts);
        }

        if ($letter && !empty($parts) && $parts[0] === '..') {
            // Letter exists and path ended up going back from that
            // This is an invalid path on Windows, so we should throw an exception
            throw new \InvalidArgumentException('Invalid folder path (you can\'t go back past the root!)');
        }

        // Join the parts with a '/'
        $joinedPath = implode('/', $parts);
        return $letter ? "{$letter}/{$joinedPath}" : $joinedPath;
    }
}

if (!function_exists('path_is_absolute')) {
    /**
     * Checks if a path is absolute
     * @param string $path Path to check
     * @return bool
     */
    function path_is_absolute(string $path): bool {
        return !empty($path) && (bool) preg_match('/^(\/|\\\\|[A-Za-z]:(?![^\/\\\\]))/', $path);
    }
}

if (!function_exists('path_resolve')) {
    /**
     * Similar to path_join except it will always return an absolute path.
     * If the first argument to this function is *not* an absolute path, this function
     * will prepend the current working directory to it.
     *
     * PHP does have a realpath method, however realpath does two things that we don't want:
     *   1) It caches the path found
     *   2) It returns null if the file/folder doesn't exist
     *
     * @param string ...$paths paths to join together & resolve to an absolute path
     */
    function path_resolve(string $first, string ...$paths): string {
        return path_is_absolute($first) ? path_join($first, ...$paths) : path_join(getcwd(), $first, ...$paths);
    }
}
<?php

use PHPUnit\Framework\TestCase;

class PathTest extends TestCase {

    public function testPathIsAbsolute() {
        // Check empty inputs
        $this->assertEquals(false, path_is_absolute(''), 'path_is_absolute returns false for empty string input');

        // Test unix paths
        $this->assertEquals(true, path_is_absolute('/some/absolute/path'), 'unix-style absolute path');
        $this->assertEquals(false, path_is_absolute('../../rel/path'), 'unix-style non-absolute paths');
        $this->assertEquals(false, path_is_absolute('path/is/relative'), 'path_is_absolute returns false for unix-style non-absolute paths');

        // Test windows paths
        $this->assertEquals(true, path_is_absolute('\server\share\asdf'), 'windows-style absolute path without drive letter');
        $this->assertEquals(true, path_is_absolute('C:\Users\someuser'), 'windows-style absolute path with drive letter');
        $this->assertEquals(true, path_is_absolute('c:\Users\someuser2'), 'windows-style absolute path with lowercase drive letter');
    }

    public function testPathNormalizeResolve() {
        $test = ['a', 'b', 'c'];
        $this->assertEquals($test, path_normalize_reduce($test, '.'), 'item is single dot');
        $this->assertEquals(['a', 'b', 'c', 'd'], path_normalize_reduce($test, 'd'), 'item is regular path name');
        $this->assertEquals(['..'], path_normalize_reduce([], '..'), 'array is empty and item is ..');
        $this->assertEquals(['a', 'b'], path_normalize_reduce($test, '..'), 'item is ..');
        $this->assertEquals(['..', '..'], path_normalize_reduce(['..'], '..'), 'array is [..], item is ..');
    }

    public function testPathJoinFirstArgEmpty() {
        // path_join should throw exception if first argument is empty
        $this->expectException(\InvalidArgumentException::class);

        path_join('', 'foo', 'bar');
    }

    public function testPathJoinInvalidPath() {
        $this->expectException(\InvalidArgumentException::class);

        path_join('C:\foo', '..', '..');
    }

    public function testPathJoin() {
        $this->assertEquals('a/b/c', path_join('a', 'b', 'c'), 'simple case');
        $this->assertEquals('a/b/c/d', path_join('a\\', '/b/c/', '\d'), 'simple case with prepending/trailing slashes');
        $this->assertEquals('/a/b/c', path_join('/a/b', './c/'), 'simple case with unix absolute path');
        $this->assertEquals('/a/b', path_join('/', 'a', 'b'), 'simple case with slash as first arg');
        $this->assertEquals('/a/b', path_join('\\', 'a', 'b'), 'simple case with windows slash as first arg');
        $this->assertEquals('C:/a/b/c', path_join('C:\a\b', './c/'), 'simple case with windows absolute path');
        $this->assertEquals('a/c', path_join('a/b', './d/', '../../c/'), 'moderate case with ..');
        $this->assertEquals('../b/c', path_join('a', '..', '../b/', 'c'), 'moderate case with .. removing first arg');
    }

    public function testPathResolve() {
        $cwd = getcwd();

        $this->assertEquals("{$cwd}/a/b", path_resolve('a', 'b'), 'without passing absolute path');
        $this->assertEquals('/a/b/c', path_resolve('/a', 'b/c'), 'unix-style absolute path');
        $this->assertEquals('/a/b/c', path_resolve('\\a', 'b/c'), 'windows-style absolute path w/o drive letter');
        $this->assertEquals('C:/a/b/c', path_resolve('C:\a', 'b/c'), 'windows-style absolute path w/ drive letter');
    }
}
<?php

declare(strict_types=1);

namespace Stringy;

/**
 * @template TKey of array-key
 * @template T of Stringy
 * @extends \Arrayy\Collection\Collection<TKey,T>
 */
class CollectionStringy extends \Arrayy\Collection\Collection
{
    /**
     * Creates an CollectionInterface object.
     *
     * @param mixed  $data
     * @param string $iteratorClass
     * @param bool   $checkPropertiesInConstructor
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
     *
     * @template TKeyCreate as array-key
     * @template TCreate of Stringy
     *
     * @phpstan-param  array<TKeyCreate,TCreate> $data
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator<array-key, mixed>> $iteratorClass
     * @phpstan-return static<TKeyCreate,TCreate>
     *
     * @psalm-mutation-free
     */
    public static function create(
        $data = [],
        string $iteratorClass = \Arrayy\ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        return new static(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    public function getType(): string
    {
        return Stringy::class;
    }

    /**
     * @return Stringy[]
     *
     * @phpstan-return array<array-key,Stringy>
     */
    public function getAll(): array
    {
        return parent::getAll();
    }

    /**
     * @return \Generator|Stringy[]
     *
     * @phpstan-return \Generator<mixed,Stringy>|\Generator<TKey,T>
     * @psalm-mutation-free
     */
    public function getGenerator(): \Generator
    {
        return parent::getGenerator();
    }

    /**
     * @return string[]
     */
    public function toStrings(): array
    {
        // init
        $result = [];

        foreach ($this->getArray() as $key => $value) {
            \assert($value instanceof Stringy);
            $result[$key] = $value->toString();
        }

        return $result;
    }

    /**
     * @param string ...$string
     *
     * @return $this
     */
    public function addString(string ...$string): self
    {
        foreach ($string as $stringTmp) {
            /** @phpstan-ignore-next-line | FP? */
            $this->add(Stringy::create($stringTmp));
        }

        return $this;
    }

    /**
     * @param Stringy ...$stringy
     *
     * @return $this
     */
    public function addStringy(Stringy ...$stringy): self
    {
        foreach ($stringy as $stringyTmp) {
            /** @phpstan-ignore-next-line | FP? */
            $this->add($stringyTmp);
        }

        return $this;
    }

    /**
     * @param string[] $strings
     *
     * @return static
     */
    public static function createFromStrings($strings = []): self
    {
        /** @noinspection AlterInForeachInspection */
        foreach ($strings as &$string) {
            $string = Stringy::create($string);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var Stringy[] $strings */
        $strings = $strings;

        return new static($strings);
    }
}
<?php

namespace Stringy;

if (!\function_exists('Stringy\create')) {
    /**
     * Creates a Stringy object and returns it on success.
     *
     * @param object|scalar $str      Value to modify, after being cast to string
     * @param string        $encoding The character encoding
     *
     * @throws \InvalidArgumentException if an array or object without a
     *                                   __toString method is passed as the first argument
     *
     * @return Stringy A Stringy object
     */
    function create($str, ?string $encoding = null)
    {
        return new Stringy($str, $encoding);
    }
}

if (!\function_exists('Stringy\collection')) {
    /**
     * @param string[]|Stringy[]|null $input
     *
     * @throws \TypeError
     *
     * @return CollectionStringy<int,Stringy>
     */
    function collection($input = null)
    {
        // init
        $newCollection = new CollectionStringy();

        if ($input === null) {
            return $newCollection;
        }

        /**
         * @psalm-suppress DocblockTypeContradiction
         */
        if (!\is_array($input)) {
            $input = [$input];
        }

        foreach ($input as &$stringOrStringy) {
            if (\is_string($stringOrStringy)) {
                $stringOrStringy = new Stringy($stringOrStringy);
            }
            assert($stringOrStringy instanceof Stringy);

            /** @phpstan-ignore-next-line - FP? */
            $newCollection[] = $stringOrStringy;
        }

        return $newCollection;
    }
}
<?php

declare(strict_types=1);

namespace Stringy;

/**
 * INFO: "Method Parameter Information" via PhpStorm |
 * https://www.jetbrains.com/phpstorm/help/viewing-method-parameter-information.html
 *
 * @method static Stringy append(string $stringInput, string $stringAppend, ?string $encoding = null)
 * @method static Stringy appendPassword(string $stringInput, int $length)
 * @method static Stringy appendUniqueIdentifier(string $stringInput, string $extraPrefix = '')
 * @method static Stringy appendRandomString(string $stringInput, int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
 * @method static Stringy at(string $stringInput, int $index, ?string $encoding = null)
 * @method static Stringy between(string $stringInput, string $start, string $end, int $offset = 0, ?string $encoding = null)
 * @method static Stringy camelize(string $stringInput, ?string $encoding = null)
 * @method static string[] chars(string $stringInput, ?string $encoding = null)
 * @method static Stringy collapseWhitespace(string $stringInput, ?string $encoding = null)
 * @method static bool   contains(string $stringInput, string $needle, bool $caseSensitive = true, ?string $encoding = null)
 * @method static bool   containsAll(string $stringInput, array $needle, bool $caseSensitive = true, ?string $encoding = null)
 * @method static bool   containsAny(string $stringInput, string $needle, bool $caseSensitive = true, ?string $encoding = null)
 * @method static int    count(string $stringInput, ?string $encoding = null)
 * @method static int    countSubstr(string $stringInput, string $substring, bool $caseSensitive = true, ?string $encoding = null)
 * @method static Stringy dasherize(string $stringInput, ?string $encoding = null)
 * @method static Stringy delimit(string $stringInput, string  $delimiter, ?string $encoding = null)
 * @method static bool   endsWith(string $stringInput, string $substring, bool $caseSensitive = true, ?string $encoding = null)
 * @method static Stringy ensureLeft(string $stringInput, string $substring, ?string $encoding = null)
 * @method static Stringy ensureRight(string $stringInput, string $substring, ?string $encoding = null)
 * @method static Stringy escape(string $stringInput, ?string $encoding = null)
 * @method static Stringy extractText(string $stringInput, string $search = '', ?int $length = null, string $ellipsis = '...')
 * @method static Stringy first(string $stringInput, int $n, ?string $encoding = null)
 * @method static bool   hasLowerCase(string $stringInput, ?string $encoding = null)
 * @method static bool   hasUpperCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy htmlDecode(string $stringInput, int $flags = ENT_COMPAT, ?string $encoding = null)
 * @method static Stringy htmlEncode(string $stringInput, int $flags = ENT_COMPAT, ?string $encoding = null)
 * @method static Stringy humanize(string $stringInput, ?string $encoding = null)
 * @method static int|bool indexOf(string $stringInput, string $needle, int $offset = 0, ?string $encoding = null)
 * @method static int|bool indexOfLast(string $stringInput, string $needle, int $offset = 0, ?string $encoding = null)
 * @method static Stringy insert(string $stringInput, string $substring, int $index = 0, ?string $encoding = null)
 * @method static bool is(string $stringInput, string $pattern, ?string $encoding = null)
 * @method static bool isAlpha(string $stringInput, ?string $encoding = null)
 * @method static bool isAlphanumeric(string $stringInput, ?string $encoding = null)
 * @method static bool isBase64(string $stringInput, ?string $encoding = null)
 * @method static bool isBlank(string $stringInput, ?string $encoding = null)
 * @method static bool isHexadecimal(string $stringInput, ?string $encoding = null)
 * @method static bool isHtml(string $stringInput, ?string $encoding = null)
 * @method static bool isJson(string $stringInput, ?string $encoding = null)
 * @method static bool isLowerCase(string $stringInput, ?string $encoding = null)
 * @method static bool isSerialized(string $stringInput, ?string $encoding = null)
 * @method static bool isUpperCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy last(string $stringInput, ?string $encoding = null)
 * @method static int    length(string $stringInput, ?string $encoding = null)
 * @method static string lineWrapAfterWord(string $stringInput, int $limit)
 * @method static Stringy[] lines(string $stringInput, ?string $encoding = null)
 * @method static Stringy longestCommonPrefix(string $stringInput, string $otherStr, ?string $encoding = null)
 * @method static Stringy longestCommonSuffix(string $stringInput, string $otherStr, ?string $encoding = null)
 * @method static Stringy longestCommonSubstring(string $stringInput, string $otherStr, ?string $encoding = null)
 * @method static Stringy lowerCaseFirst(string $stringInput, ?string $encoding = null)
 * @method static bool   offsetExists(string $stringInput, mixed $offset, ?string $encoding = null)
 * @method static string offsetGet(string $stringInput, mixed $offset, ?string $encoding = null)
 * @method static Stringy pad(string $stringInput, int $length, string $padStr = ' ', string $padType = 'right', ?string $encoding = null)
 * @method static Stringy padBoth(string $stringInput, int $length, string $padStr = ' ', ?string $encoding = null)
 * @method static Stringy padLeft(string $stringInput, int $length, string $padStr = ' ', ?string $encoding = null)
 * @method static Stringy padRight(string $stringInput, int $length, string $padStr = ' ', ?string $encoding = null)
 * @method static Stringy prepend(string $stringInput, string $string, ?string $encoding = null)
 * @method static Stringy regexReplace(string $stringInput, string $pattern, string $replacement, string $delimiter = '/')
 * @method static Stringy removeLeft(string $stringInput, string $substring, ?string $encoding = null)
 * @method static Stringy removeRight(string $stringInput, string $substring, ?string $encoding = null)
 * @method static Stringy removeHtml(string $stringInput, ?string $allowableTags = null, ?string $encoding = null)
 * @method static Stringy removeXss(string $stringInput, ?string $encoding = null)
 * @method static Stringy repeat(string $stringInput, int $multiplier, ?string $encoding = null)
 * @method static Stringy replace(string $stringInput, string $search, string $replacement, bool $caseSensitive, ?string $encoding = null)
 * @method static Stringy replaceAll(string $stringInput, array $search, string $replacement, bool $caseSensitive, ?string $encoding = null)
 * @method static Stringy reverse(string $stringInput, ?string $encoding = null)
 * @method static Stringy safeTruncate(string $stringInput, int $length, string $substring = '', ?string $encoding = null)
 * @method static Stringy shuffle(string $stringInput, ?string $encoding = null)
 * @method static Stringy shortenAfterWord(string $stringInput, int $length, string $strAddOn)
 * @method static Stringy slugify(string $stringInput, string $separator = '-', string $language = 'en', array $replacements = [], ?string $encoding = null)
 * @method static Stringy stripeCssMediaQueries(string $stringInput)
 * @method static Stringy stripeEmptyHtmlTags(string $stringInput)
 * @method static Stringy utf8ify(string $stringInput)
 * @method static Stringy snakeize(string $stringInput, ?string $encoding = null)
 * @method static bool   startsWith(string $stringInput, string $substring, bool $caseSensitive = true, ?string $encoding = null)
 * @method static Stringy slice(string $stringInput, int $start, ?int $end = null, ?string $encoding = null)
 * @method static Stringy[]  split(string $stringInput, string $pattern, ?int $limit = null, ?string $encoding = null)
 * @method static Stringy substr(string $stringInput, int $start, ?int $length = null, ?string $encoding = null)
 * @method static Stringy surround(string $stringInput, string $substring, ?string $encoding = null)
 * @method static Stringy swapCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy tidy(string $stringInput, ?string $encoding = null)
 * @method static Stringy titleize(string $stringInput, ?string $encoding = null)
 * @method static Stringy toAscii(string $stringInput)
 * @method static Stringy toBoolean(string $stringInput, ?string $encoding = null)
 * @method static Stringy toString(string $stringInput)
 * @method static Stringy toLowerCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy toSpaces(string $stringInput, int $tabLength = 4, ?string $encoding = null)
 * @method static Stringy toTabs(string $stringInput, int $tabLength = 4, ?string $encoding = null)
 * @method static Stringy toTitleCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy toUpperCase(string $stringInput, ?string $encoding = null)
 * @method static Stringy trim(string $stringInput, ?string $chars = null, ?string $encoding = null)
 * @method static Stringy trimLeft(string $stringInput, ?string $chars = null, ?string $encoding = null)
 * @method static Stringy trimRight(string $stringInput, ?string $chars = null, ?string $encoding = null)
 * @method static Stringy truncate(string $stringInput, int $length, string $substring = '', ?string $encoding = null)
 * @method static Stringy underscored(string $stringInput, ?string $encoding = null)
 * @method static Stringy upperCamelize(string $stringInput, ?string $encoding = null)
 * @method static Stringy upperCaseFirst(string $stringInput, ?string $encoding = null)
 *
 * @deprecated <p>Please use e.g. (new Stringy('foo'))->upperCaseFirst() instead or write your own small wrapper, because I can't protect you from BC from new parameters,
 *                if you use this class, thanks.</p>
 */
class StaticStringy
{
    /**
     * A mapping of method names to the numbers of arguments it accepts. Each
     * should be two more than the equivalent Stringy method. Necessary as
     * static methods place the optional $encoding as the last parameter.
     *
     * @var array<mixed>|null
     */
    protected static $methodArgs = null;

    /**
     * Creates an instance of Stringy and invokes the given method with the
     * rest of the passed arguments. The optional encoding is expected to be
     * the last argument. For example, the following:
     * StaticStringy::slice('fòôbàř', 0, 3, 'UTF-8'); translates to
     * Stringy::create('fòôbàř', 'UTF-8')->slice(0, 3);
     * The result is not cast, so the return value may be of type Stringy,
     * integer, boolean, etc.
     *
     * @param string  $name
     * @param mixed[] $arguments
     *
     * @return Stringy
     */
    public static function __callStatic($name, array $arguments)
    {
        if (!static::$methodArgs) {
            $stringyClass = new \ReflectionClass(Stringy::class);
            $methods = $stringyClass->getMethods(\ReflectionMethod::IS_PUBLIC);

            foreach ($methods as $method) {
                $params = $method->getNumberOfParameters() + 2;
                static::$methodArgs[$method->name] = $params;
            }
        }

        if (!isset(static::$methodArgs[$name])) {
            throw new \BadMethodCallException($name . ' is not a valid method');
        }

        $numArgs = \count($arguments);
        $str = ($numArgs) ? $arguments[0] : '';

        if ($numArgs === static::$methodArgs[$name]) {
            $args = \array_slice($arguments, 1, -1);
            $encoding = $arguments[$numArgs - 1];
        } else {
            $args = \array_slice($arguments, 1);
            $encoding = null;
        }

        $stringy = Stringy::create($str, $encoding);

        return \call_user_func_array([$stringy, $name], $args);
    }

    /**
     * @param string|string[]|Stringy|Stringy[]|null $input
     *
     * @return CollectionStringy|Stringy[]
     *
     * @phpstan-return CollectionStringy<array-key, Stringy>
     */
    public static function collection($input = null): CollectionStringy
    {
        // init
        $newCollection = new CollectionStringy();

        if ($input === null) {
            return $newCollection;
        }

        if (!\is_array($input)) {
            $input = [$input];
        }

        foreach ($input as &$stringOrStringy) {
            if (\is_string($stringOrStringy)) {
                $stringOrStringy = new Stringy($stringOrStringy);
            }
            assert($stringOrStringy instanceof Stringy);

            /** @phpstan-ignore-next-line - FP? */
            $newCollection[] = $stringOrStringy;
        }

        return $newCollection;
    }
}
<?php

declare(strict_types=1);

namespace Stringy;

use Defuse\Crypto\Crypto;
use voku\helper\AntiXSS;
use voku\helper\ASCII;
use voku\helper\EmailCheck;
use voku\helper\URLify;
use voku\helper\UTF8;

/**
 * ## 🇷🇺 Русским гражданам
 * В Украине сейчас идет война. Силами РФ наносятся удары по гражданской инфраструктуре в [Харькове][1], [Киеве][2], [Чернигове][3], [Сумах][4], [Ирпене][5] и десятках других городов. Гибнут люди - и гражданское население, и военные, в том числе российские призывники, которых бросили воевать. Чтобы лишить собственный народ доступа к информации, правительство РФ запретило называть войну войной, закрыло независимые СМИ и принимает сейчас ряд диктаторских законов. Эти законы призваны заткнуть рот всем, кто против войны. За обычный призыв к миру сейчас можно получить несколько лет тюрьмы.
 * Не молчите! Молчание - знак вашего согласия с политикой российского правительства.
 *  **Вы можете сделать выбор НЕ МОЛЧАТЬ.**
 * ---
 * ## 🇺🇸 To people of Russia
 * There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilian infrastructure in [Kharkiv][1], [Kyiv][2], [Chernihiv][3], [Sumy][4], [Irpin][5] and dozens of other cities. People are dying – both civilians and military servicemen, including Russian conscripts who were thrown into the fighting. In order to deprive its own people of access to information, the government of the Russian Federation has forbidden calling a war a war, shut down independent media and is passing a number of dictatorial laws. These laws are meant to silence all those who are against war. You can be jailed for multiple years for simply calling for peace.
 * Do not be silent! Silence is a sign that you accept the Russian government's policy.
 * **You can choose NOT TO BE SILENT.**
 * ---
 * - [1] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/P7K2MSZDGFMIJPDD7CI2GIROJI.jpg "Kharkiv under attack"
 * - [2] https://gdb.voanews.com/01bd0000-0aff-0242-fad0-08d9fc92c5b3_cx0_cy5_cw0_w1023_r1_s.jpg "Kyiv under attack"
 * - [3] https://ichef.bbci.co.uk/news/976/cpsprodpb/163DD/production/_123510119_hi074310744.jpg "Chernihiv under attack"
 * - [4] https://www.youtube.com/watch?v=8K-bkqKKf2A "Sumy under attack"
 * - [5] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/K4MTMLEHTRKGFK3GSKAT4GR3NE.jpg "Irpin under attack"
 *
 * @template-implements \IteratorAggregate<string>
 * @template-implements \ArrayAccess<array-key,string>
 */
class Stringy implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable
{
    /**
     * An instance's string.
     *
     * @var string
     */
    protected $str;

    /**
     * The string's encoding, which should be one of the mbstring module's
     * supported encodings.
     *
     * @var string
     */
    protected $encoding;

    /**
     * @var UTF8
     */
    private $utf8;

    /**
     * @var ASCII
     */
    private $ascii;

    /**
     * Initializes a Stringy object and assigns both str and encoding properties
     * the supplied values. $str is cast to a string prior to assignment, and if
     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
     * an InvalidArgumentException if the first argument is an array or object
     * without a __toString method.
     *
     * @param object|scalar $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
     * @param string        $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
     *
     * @throws \InvalidArgumentException
     *                                   <p>if an array or object without a
     *                                   __toString method is passed as the first argument</p>
     *
     * @psalm-mutation-free
     */
    public function __construct($str = '', ?string $encoding = null)
    {
        /* @phpstan-ignore-next-line | always false in theory */
        if (\is_array($str)) {
            throw new \InvalidArgumentException(
                'Passed value cannot be an array'
            );
        }

        if (
            \is_object($str)
            &&
            !\method_exists($str, '__toString')
        ) {
            throw new \InvalidArgumentException(
                'Passed object must have a __toString method'
            );
        }

        $this->str = (string) $str;

        static $ASCII = null;
        if ($ASCII === null) {
            $ASCII = new ASCII();
        }
        $this->ascii = $ASCII;

        static $UTF8 = null;
        if ($UTF8 === null) {
            $UTF8 = new UTF8();
        }
        $this->utf8 = $UTF8;

        if ($encoding !== 'UTF-8') {
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
        } else {
            $this->encoding = $encoding;
        }
    }

    /**
     * Returns the value in $str.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return string
     *                <p>The current value of the $str property.</p>
     */
    public function __toString()
    {
        return (string) $this->str;
    }

    /**
     * Return part of the string occurring after a specific string.
     *
     * EXAMPLE: <code>
     * s('宮本 茂')->after('本'); // ' 茂'
     * </code>
     *
     * @param string $string <p>The delimiting string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function after(string $string): self
    {
        $strArray = UTF8::str_split_pattern(
            $this->str,
            $string
        );

        unset($strArray[0]);

        return new static(
            \implode(' ', $strArray),
            $this->encoding
        );
    }

    /**
     * Gets the substring after the first occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</b></b>')->afterFirst('b'); // '></b>'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function afterFirst(string $separator): self
    {
        return static::create(
            $this->utf8::str_substr_after_first_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring after the first occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</B></B>')->afterFirstIgnoreCase('b'); // '></B>'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function afterFirstIgnoreCase(string $separator): self
    {
        return static::create(
            $this->utf8::str_isubstr_after_first_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring after the last occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</b></b>')->afterLast('b'); // '>'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function afterLast(string $separator): self
    {
        return static::create(
            $this->utf8::str_substr_after_last_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring after the last occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</B></B>')->afterLastIgnoreCase('b'); // '>'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function afterLastIgnoreCase(string $separator): self
    {
        return static::create(
            $this->utf8::str_isubstr_after_last_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Returns a new string with $suffix appended.
     *
     * EXAMPLE: <code>
     * s('fòô')->append('bàř'); // 'fòôbàř'
     * </code>
     *
     * @param string ...$suffix <p>The string to append.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with appended $suffix.</p>
     */
    public function append(string ...$suffix): self
    {
        if (\count($suffix) <= 1) {
            $suffix = $suffix[0];
        } else {
            $suffix = \implode('', $suffix);
        }

        return static::create($this->str . $suffix, $this->encoding);
    }

    /**
     * Append an password (limited to chars that are good readable).
     *
     * EXAMPLE: <code>
     * s('')->appendPassword(8); // e.g.: '89bcdfgh'
     * </code>
     *
     * @param int $length <p>Length of the random string.</p>
     *
     * @return static
     *                <p>Object with appended password.</p>
     */
    public function appendPassword(int $length): self
    {
        return $this->appendRandomString(
            $length,
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
        );
    }

    /**
     * Append an random string.
     *
     * EXAMPLE: <code>
     * s('')->appendUniqueIdentifier(5, 'ABCDEFGHI'); // e.g.: 'CDEHI'
     * </code>
     *
     * @param int    $length        <p>Length of the random string.</p>
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
     *
     * @return static
     *                <p>Object with appended random string.</p>
     */
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
    {
        $str = $this->utf8::get_random_string($length, $possibleChars);

        return $this->append($str);
    }

    /**
     * Returns a new string with $suffix appended.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param CollectionStringy|static ...$suffix <p>The Stringy objects to append.</p>
     *
     * @phpstan-param CollectionStringy<int,static>|static ...$suffix
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with appended $suffix.</p>
     */
    public function appendStringy(...$suffix): self
    {
        $suffixStr = '';
        foreach ($suffix as $suffixTmp) {
            if ($suffixTmp instanceof CollectionStringy) {
                $suffixStr .= $suffixTmp->implode('');
            } else {
                $suffixStr .= $suffixTmp->toString();
            }
        }

        return static::create($this->str . $suffixStr, $this->encoding);
    }

    /**
     * Append an unique identifier.
     *
     * EXAMPLE: <code>
     * s('')->appendUniqueIdentifier(); // e.g.: '1f3870be274f6c49b3e31a0c6728957f'
     * </code>
     *
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
     *
     * @return static
     *                <p>Object with appended unique identifier as md5-hash.</p>
     */
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
    {
        return $this->append(
            $this->utf8::get_unique_string($entropyExtra, $md5)
        );
    }

    /**
     * Returns the character at $index, with indexes starting at 0.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->at(3); // 'b'
     * </code>
     *
     * @param int $index <p>Position of the character.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>The character at $index.</p>
     */
    public function at(int $index): self
    {
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
    }

    /**
     * Decode the base64 encoded string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return self
     */
    public function base64Decode(): self
    {
        return static::create(
            \base64_decode($this->str, true),
            $this->encoding
        );
    }

    /**
     * Encode the string to base64.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return self
     */
    public function base64Encode(): self
    {
        return static::create(
            \base64_encode($this->str),
            $this->encoding
        );
    }

    /**
     * Creates a hash from the string using the CRYPT_BLOWFISH algorithm.
     *
     * WARNING: Using this algorithm, will result in the ```$this->str```
     *          being truncated to a maximum length of 72 characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param array<array-key, int|string> $options [optional] <p>An array of bcrypt hasing options.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function bcrypt(array $options = []): self
    {
        return new static(
            \password_hash(
                $this->str,
                \PASSWORD_BCRYPT,
                $options
            ),
            $this->encoding
        );
    }

    /**
     * Return part of the string occurring before a specific string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $string <p>The delimiting string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function before(string $string): self
    {
        $strArray = UTF8::str_split_pattern(
            $this->str,
            $string,
            1
        );

        return new static(
            $strArray[0] ?? '',
            $this->encoding
        );
    }

    /**
     * Gets the substring before the first occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</b></b>')->beforeFirst('b'); // '</'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function beforeFirst(string $separator): self
    {
        return static::create(
            $this->utf8::str_substr_before_first_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring before the first occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</B></B>')->beforeFirstIgnoreCase('b'); // '</'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function beforeFirstIgnoreCase(string $separator): self
    {
        return static::create(
            $this->utf8::str_isubstr_before_first_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring before the last occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</b></b>')->beforeLast('b'); // '</b></'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function beforeLast(string $separator): self
    {
        return static::create(
            $this->utf8::str_substr_before_last_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Gets the substring before the last occurrence of a separator.
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * s('</B></B>')->beforeLastIgnoreCase('b'); // '</B></'
     * </code>
     *
     * @param string $separator
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function beforeLastIgnoreCase(string $separator): self
    {
        return static::create(
            $this->utf8::str_isubstr_before_last_separator(
                $this->str,
                $separator,
                $this->encoding
            )
        );
    }

    /**
     * Returns the substring between $start and $end, if found, or an empty
     * string. An optional offset may be supplied from which to begin the
     * search for the start string.
     *
     * EXAMPLE: <code>
     * s('{foo} and {bar}')->between('{', '}'); // 'foo'
     * </code>
     *
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str is a substring between $start and $end.</p>
     */
    public function between(string $start, string $end, ?int $offset = null): self
    {
        $str = $this->utf8::between(
            $this->str,
            $start,
            $end,
            (int) $offset,
            $this->encoding
        );

        return static::create($str, $this->encoding);
    }

    /**
     * Call a user function.
     *
     * EXAMPLE: <code>
     * S::create('foo bar lall')->callUserFunction(static function ($str) {
     *     return UTF8::str_limit($str, 8);
     * })->toString(); // "foo bar…"
     * </code>
     *
     * @param callable $function
     * @param mixed    ...$parameter
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object having a $str changed via $function.</p>
     */
    public function callUserFunction(callable $function, ...$parameter): self
    {
        $str = $function($this->str, ...$parameter);

        return static::create(
            $str,
            $this->encoding
        );
    }

    /**
     * Returns a camelCase version of the string. Trims surrounding spaces,
     * capitalizes letters following digits, spaces, dashes and underscores,
     * and removes spaces, dashes, as well as underscores.
     *
     * EXAMPLE: <code>
     * s('Camel-Case')->camelize(); // 'camelCase'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with $str in camelCase.</p>
     */
    public function camelize(): self
    {
        return static::create(
            $this->utf8::str_camelize($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Returns the string with the first letter of each word capitalized,
     * except for when the word is a name which shouldn't be capitalized.
     *
     * EXAMPLE: <code>
     * s('jaap de hoop scheffer')->capitalizePersonName(); // 'Jaap de Hoop Scheffer'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with $str capitalized.</p>
     */
    public function capitalizePersonalName(): self
    {
        return static::create(
            $this->utf8::str_capitalize_name($this->str),
            $this->encoding
        );
    }

    /**
     * Returns an array consisting of the characters in the string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->chars(); // ['f', 'ò', 'ô', 'b', 'à', 'ř']
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return string[]
     *                  <p>An array of string chars.</p>
     */
    public function chars(): array
    {
        /** @var string[] */
        return $this->utf8::str_split($this->str);
    }

    /**
     * Splits the string into chunks of Stringy objects.
     *
     * EXAMPLE: <code>
     * s('foobar')->chunk(3); // ['foo', 'bar']
     * </code>
     *
     * @param int $length [optional] <p>Max character length of each array element.</p>
     *
     * @psalm-mutation-free
     *
     * @return static[]
     *                  <p>An array of Stringy objects.</p>
     *
     * @phpstan-return array<int,static>
     */
    public function chunk(int $length = 1): array
    {
        if ($length < 1) {
            throw new \InvalidArgumentException('The chunk length must be greater than zero.');
        }

        if ($this->str === '') {
            return [];
        }

        $chunks = $this->utf8::str_split($this->str, $length);

        foreach ($chunks as &$value) {
            $value = static::create($value, $this->encoding);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var static[] $chunks */
        $chunks = $chunks;

        return $chunks;
    }

    /**
     * Splits the string into chunks of Stringy objects collection.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $length [optional] <p>Max character length of each array element.</p>
     *
     * @psalm-mutation-free
     *
     * @return CollectionStringy|static[]
     *                                    <p>An collection of Stringy objects.</p>
     *
     * @phpstan-return CollectionStringy<int,static>
     */
    public function chunkCollection(int $length = 1): CollectionStringy
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
         */
        return CollectionStringy::create(
            $this->chunk($length)
        );
    }

    /**
     * Trims the string and replaces consecutive whitespace characters with a
     * single space. This includes tabs and newline characters, as well as
     * multibyte whitespace such as the thin space and ideographic space.
     *
     * EXAMPLE: <code>
     * s('   Ο     συγγραφέας  ')->collapseWhitespace(); // 'Ο συγγραφέας'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
     */
    public function collapseWhitespace(): self
    {
        return static::create(
            $this->utf8::collapse_whitespace($this->str),
            $this->encoding
        );
    }

    /**
     * Returns true if the string contains $needle, false otherwise. By default
     * the comparison is case-sensitive, but can be made insensitive by setting
     * $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('Ο συγγραφέας είπε')->contains('συγγραφέας'); // true
     * </code>
     *
     * @param string $needle        <p>Substring to look for.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains $needle.</p>
     */
    public function contains(string $needle, bool $caseSensitive = true): bool
    {
        return $this->utf8::str_contains(
            $this->str,
            $needle,
            $caseSensitive
        );
    }

    /**
     * Returns true if the string contains all $needles, false otherwise. By
     * default the comparison is case-sensitive, but can be made insensitive by
     * setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('foo & bar')->containsAll(['foo', 'bar']); // true
     * </code>
     *
     * @param string[] $needles       <p>SubStrings to look for.</p>
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains $needle.</p>
     */
    public function containsAll(array $needles, bool $caseSensitive = true): bool
    {
        return $this->utf8::str_contains_all(
            $this->str,
            $needles,
            $caseSensitive
        );
    }

    /**
     * Returns true if the string contains any $needles, false otherwise. By
     * default the comparison is case-sensitive, but can be made insensitive by
     * setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('str contains foo')->containsAny(['foo', 'bar']); // true
     * </code>
     *
     * @param string[] $needles       <p>SubStrings to look for.</p>
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains $needle.</p>
     */
    public function containsAny(array $needles, bool $caseSensitive = true): bool
    {
        return $this->utf8::str_contains_any(
            $this->str,
            $needles,
            $caseSensitive
        );
    }

    /**
     * Checks if string starts with "BOM" (Byte Order Mark Character) character.
     *
     * EXAMPLE: <code>s("\xef\xbb\xbf foobar")->containsBom(); // true</code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <strong>true</strong> if the string has BOM at the start,<br>
     *              <strong>false</strong> otherwise
     */
    public function containsBom(): bool
    {
        return $this->utf8::string_has_bom($this->str);
    }

    /**
     * Returns the length of the string, implementing the countable interface.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return int
     *             <p>The number of characters in the string, given the encoding.</p>
     */
    public function count(): int
    {
        return $this->length();
    }

    /**
     * Returns the number of occurrences of $substring in the given string.
     * By default, the comparison is case-sensitive, but can be made insensitive
     * by setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('Ο συγγραφέας είπε')->countSubstr('α'); // 2
     * </code>
     *
     * @param string $substring     <p>The substring to search for.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return int
     */
    public function countSubstr(string $substring, bool $caseSensitive = true): int
    {
        return $this->utf8::substr_count_simple(
            $this->str,
            $substring,
            $caseSensitive,
            $this->encoding
        );
    }

    /**
     * Calculates the crc32 polynomial of a string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return int
     */
    public function crc32(): int
    {
        return \crc32($this->str);
    }

    /**
     * Creates a Stringy object and assigns both str and encoding properties
     * the supplied values. $str is cast to a string prior to assignment, and if
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
     * then returns the initialized object. Throws an InvalidArgumentException
     * if the first argument is an array or object without a __toString method.
     *
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
     *
     * @throws \InvalidArgumentException
     *                                   <p>if an array or object without a
     *                                   __toString method is passed as the first argument</p>
     *
     * @return static
     *                <p>A Stringy object.</p>
     * @phpstan-pure
     */
    public static function create($str = '', ?string $encoding = null): self
    {
        return new static($str, $encoding);
    }

    /**
     * One-way string encryption (hashing).
     *
     * Hash the string using the standard Unix DES-based algorithm or an
     * alternative algorithm that may be available on the system.
     *
     * PS: if you need encrypt / decrypt, please use ```static::encrypt($password)```
     *     and ```static::decrypt($password)```
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $salt <p>A salt string to base the hashing on.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function crypt(string $salt): self
    {
        return new static(
            \crypt(
                $this->str,
                $salt
            ),
            $this->encoding
        );
    }

    /**
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
     * inserted before uppercase characters (with the exception of the first
     * character of the string), and in place of spaces as well as underscores.
     *
     * EXAMPLE: <code>
     * s('fooBar')->dasherize(); // 'foo-bar'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a dasherized $str</p>
     */
    public function dasherize(): self
    {
        return static::create(
            $this->utf8::str_dasherize($this->str),
            $this->encoding
        );
    }

    /**
     * Decrypt the string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $password The key for decrypting
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function decrypt(string $password): self
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
         */
        return new static(
            Crypto::decryptWithPassword($this->str, $password),
            $this->encoding
        );
    }

    /**
     * Returns a lowercase and trimmed string separated by the given delimiter.
     * Delimiters are inserted before uppercase characters (with the exception
     * of the first character of the string), and in place of spaces, dashes,
     * and underscores. Alpha delimiters are not converted to lowercase.
     *
     * EXAMPLE: <code>
     * s('fooBar')->delimit('::'); // 'foo::bar'
     * </code>
     *
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a delimited $str.</p>
     */
    public function delimit(string $delimiter): self
    {
        return static::create(
            $this->utf8::str_delimit($this->str, $delimiter),
            $this->encoding
        );
    }

    /**
     * Encode the given string into the given $encoding + set the internal character encoding.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $new_encoding         <p>The desired character encoding.</p>
     * @param bool   $auto_detect_encoding [optional] <p>Auto-detect the current string-encoding</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function encode(string $new_encoding, bool $auto_detect_encoding = false): self
    {
        if ($auto_detect_encoding) {
            $str = $this->utf8::encode(
                $new_encoding,
                $this->str
            );
        } else {
            $str = $this->utf8::encode(
                $new_encoding,
                $this->str,
                false,
                $this->encoding
            );
        }

        return new static($str, $new_encoding);
    }

    /**
     * Encrypt the string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $password <p>The key for encrypting</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function encrypt(string $password): self
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
         */
        return new static(
            Crypto::encryptWithPassword($this->str, $password),
            $this->encoding
        );
    }

    /**
     * Returns true if the string ends with $substring, false otherwise. By
     * default, the comparison is case-sensitive, but can be made insensitive
     * by setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->endsWith('bàř', true); // true
     * </code>
     *
     * @param string $substring     <p>The substring to look for.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str ends with $substring.</p>
     */
    public function endsWith(string $substring, bool $caseSensitive = true): bool
    {
        if ($caseSensitive) {
            return $this->utf8::str_ends_with($this->str, $substring);
        }

        return $this->utf8::str_iends_with($this->str, $substring);
    }

    /**
     * Returns true if the string ends with any of $substrings, false otherwise.
     * By default, the comparison is case-sensitive, but can be made insensitive
     * by setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->endsWithAny(['bàř', 'baz'], true); // true
     * </code>
     *
     * @param string[] $substrings    <p>Substrings to look for.</p>
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str ends with $substring.</p>
     */
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
    {
        if ($caseSensitive) {
            return $this->utf8::str_ends_with_any($this->str, $substrings);
        }

        return $this->utf8::str_iends_with_any($this->str, $substrings);
    }

    /**
     * Ensures that the string begins with $substring. If it doesn't, it's
     * prepended.
     *
     * EXAMPLE: <code>
     * s('foobar')->ensureLeft('http://'); // 'http://foobar'
     * </code>
     *
     * @param string $substring <p>The substring to add if not present.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str prefixed by the $substring.</p>
     */
    public function ensureLeft(string $substring): self
    {
        return static::create(
            $this->utf8::str_ensure_left($this->str, $substring),
            $this->encoding
        );
    }

    /**
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
     *
     * EXAMPLE: <code>
     * s('foobar')->ensureRight('.com'); // 'foobar.com'
     * </code>
     *
     * @param string $substring <p>The substring to add if not present.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str suffixed by the $substring.</p>
     */
    public function ensureRight(string $substring): self
    {
        return static::create(
            $this->utf8::str_ensure_right($this->str, $substring),
            $this->encoding
        );
    }

    /**
     * Create a escape html version of the string via "htmlspecialchars()".
     *
     * EXAMPLE: <code>
     * s('<∂∆ onerror="alert(xss)">')->escape(); // '&lt;∂∆ onerror=&quot;alert(xss)&quot;&gt;'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function escape(): self
    {
        return static::create(
            $this->utf8::htmlspecialchars(
                $this->str,
                \ENT_QUOTES | \ENT_SUBSTITUTE,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Split a string by a string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $delimiter <p>The boundary string</p>
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
     *                          collection.</p>
     *
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
     *   element containing the rest of string.
     *   - If the limit parameter is negative, all components except the last -limit are returned.
     *   - If the limit parameter is zero, then this is treated as 1
     *
     * @psalm-mutation-free
     *
     * @return array<int,static>
     */
    public function explode(string $delimiter, int $limit = \PHP_INT_MAX): array
    {
        if ($this->str === '') {
            return [];
        }

        /** @phpstan-ignore-next-line - FP -> non-empty-string is already checked */
        $strings = \explode($delimiter, $this->str, $limit);
        /** @phpstan-ignore-next-line - if "$delimiter" is an empty string, then "explode()" will return "false" */
        if ($strings === false) {
            $strings = [];
        }

        return \array_map(
            function ($str) {
                return new static($str, $this->encoding);
            },
            $strings
        );
    }

    /**
     * Split a string by a string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $delimiter <p>The boundary string</p>
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
     *                          collection.</p>
     *
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
     *   element containing the rest of string.
     *   - If the limit parameter is negative, all components except the last -limit are returned.
     *   - If the limit parameter is zero, then this is treated as 1
     *
     * @psalm-mutation-free
     *
     * @return CollectionStringy|static[]
     *                                    <p>An collection of Stringy objects.</p>
     *
     * @phpstan-return CollectionStringy<int,static>
     */
    public function explodeCollection(string $delimiter, int $limit = \PHP_INT_MAX): CollectionStringy
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
         */
        return CollectionStringy::create(
            $this->explode($delimiter, $limit)
        );
    }

    /**
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
     *
     * EXAMPLE: <code>
     * $sentence = 'This is only a Fork of Stringy, take a look at the new features.';
     * s($sentence)->extractText('Stringy'); // '...Fork of Stringy...'
     * </code>
     *
     * @param string   $search
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function extractText(string $search = '', ?int $length = null, string $replacerForSkippedText = '…'): self
    {
        return static::create(
            $this->utf8::extract_text(
                $this->str,
                $search,
                $length,
                $replacerForSkippedText,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns the first $n characters of the string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->first(3); // 'fòô'
     * </code>
     *
     * @param int $n <p>Number of characters to retrieve from the start.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the first $n chars.</p>
     */
    public function first(int $n): self
    {
        return static::create(
            $this->utf8::first_char($this->str, $n, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Return a formatted string via sprintf + named parameters via array syntax.
     *
     * <p>
     * <br>
     * It will use "sprintf()" so you can use e.g.:
     * <br>
     * <br><pre>s('There are %d monkeys in the %s')->format(5, 'tree');</pre>
     * <br>
     * <br><pre>s('There are %2$d monkeys in the %1$s')->format('tree', 5);</pre>
     * <br>
     * <br>
     * But you can also use named parameter via array syntax e.g.:
     * <br>
     * <br><pre>s('There are %:count monkeys in the %:location')->format(['count' => 5, 'location' => 'tree');</pre>
     * </p>
     *
     * EXAMPLE: <code>
     * $input = 'one: %2$d, %1$s: 2, %:text_three: %3$d';
     * s($input)->format(['text_three' => '%4$s'], 'two', 1, 3, 'three'); // 'One: 1, two: 2, three: 3'
     * </code>
     *
     * @param mixed ...$args [optional]
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>A Stringy object produced according to the formatting string
     *                format.</p>
     */
    public function format(...$args): self
    {
        // init
        $str = $this->str;

        if (\strpos($this->str, '%:') !== false) {
            $offset = null;
            $replacement = null;
            /** @noinspection AlterInForeachInspection */
            foreach ($args as $key => &$arg) {
                if (!\is_array($arg)) {
                    continue;
                }

                foreach ($arg as $name => $param) {
                    $name = (string) $name;

                    if (\strpos($name, '%:') !== 0) {
                        $nameTmp = '%:' . $name;
                    } else {
                        $nameTmp = $name;
                    }

                    if ($offset === null) {
                        $offset = \strpos($str, $nameTmp);
                    } else {
                        $offset = \strpos($str, $nameTmp, (int) $offset + \strlen((string) $replacement));
                    }
                    if ($offset === false) {
                        continue;
                    }

                    unset($arg[$name]);

                    $str = \substr_replace($str, (string) $param, (int) $offset, \strlen($nameTmp));
                }

                unset($args[$key]);
            }
        }

        $str = \str_replace('%:', '%%:', $str);

        return static::create(
            \sprintf($str, ...$args),
            $this->encoding
        );
    }

    /**
     * Returns the encoding used by the Stringy object.
     *
     * EXAMPLE: <code>
     * s('fòôbàř', 'UTF-8')->getEncoding(); // 'UTF-8'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return string
     *                <p>The current value of the $encoding property.</p>
     */
    public function getEncoding(): string
    {
        return $this->encoding;
    }

    /**
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
     * interface. The ArrayIterator's constructor is passed an array of chars
     * in the multibyte string. This enables the use of foreach with instances
     * of Stringy\Stringy.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return \ArrayIterator
     *                        <p>An iterator for the characters in the string.</p>
     *
     * @phpstan-return \ArrayIterator<array-key,string>
     */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator($this->chars());
    }

    /**
     * Wrap the string after an exact number of characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int    $width <p>Number of characters at which to wrap.</p>
     * @param string $break [optional] <p>Character used to break the string. | Default: "\n"</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function hardWrap($width, $break = "\n"): self
    {
        return $this->lineWrap($width, $break, false);
    }

    /**
     * Returns true if the string contains a lower case char, false otherwise
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->hasLowerCase(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not the string contains a lower case character.</p>
     */
    public function hasLowerCase(): bool
    {
        return $this->utf8::has_lowercase($this->str);
    }

    /**
     * Returns true if the string contains an upper case char, false otherwise.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->hasUpperCase(); // false
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not the string contains an upper case character.</p>
     */
    public function hasUpperCase(): bool
    {
        return $this->utf8::has_uppercase($this->str);
    }

    /**
     * Generate a hash value (message digest).
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @see https://php.net/manual/en/function.hash.php
     *
     * @param string $algorithm
     *                          <p>Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..)</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function hash($algorithm): self
    {
        return static::create(\hash($algorithm, $this->str), $this->encoding);
    }

    /**
     * Decode the string from hex.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function hexDecode(): self
    {
        $string = \preg_replace_callback(
            '/\\\\x([0-9A-Fa-f]+)/',
            function (array $matched) {
                return (string) $this->utf8::hex_to_chr($matched[1]);
            },
            $this->str
        );

        return static::create(
            $string,
            $this->encoding
        );
    }

    /**
     * Encode string to hex.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function hexEncode(): self
    {
        $string = \array_reduce(
            $this->chars(),
            function (string $str, string $char) {
                return $str . $this->utf8::chr_to_hex($char);
            },
            ''
        );

        return static::create(
            $string,
            $this->encoding
        );
    }

    /**
     * Convert all HTML entities to their applicable characters.
     *
     * EXAMPLE: <code>
     * s('&amp;')->htmlDecode(); // '&'
     * </code>
     *
     * @param int $flags [optional] <p>
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
     *                   which document type to use. The default is ENT_COMPAT.
     *                   <table>
     *                   Available <i>flags</i> constants
     *                   <tr valign="top">
     *                   <td>Constant Name</td>
     *                   <td>Description</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_COMPAT</b></td>
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_QUOTES</b></td>
     *                   <td>Will convert both double and single quotes.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_NOQUOTES</b></td>
     *                   <td>Will leave both double and single quotes unconverted.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_HTML401</b></td>
     *                   <td>
     *                   Handle code as HTML 4.01.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_XML1</b></td>
     *                   <td>
     *                   Handle code as XML 1.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_XHTML</b></td>
     *                   <td>
     *                   Handle code as XHTML.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_HTML5</b></td>
     *                   <td>
     *                   Handle code as HTML 5.
     *                   </td>
     *                   </tr>
     *                   </table>
     *                   </p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after being html decoded.</p>
     */
    public function htmlDecode(int $flags = \ENT_COMPAT): self
    {
        return static::create(
            $this->utf8::html_entity_decode(
                $this->str,
                $flags,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Convert all applicable characters to HTML entities.
     *
     * EXAMPLE: <code>
     * s('&')->htmlEncode(); // '&amp;'
     * </code>
     *
     * @param int $flags [optional] <p>
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
     *                   which document type to use. The default is ENT_COMPAT.
     *                   <table>
     *                   Available <i>flags</i> constants
     *                   <tr valign="top">
     *                   <td>Constant Name</td>
     *                   <td>Description</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_COMPAT</b></td>
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_QUOTES</b></td>
     *                   <td>Will convert both double and single quotes.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_NOQUOTES</b></td>
     *                   <td>Will leave both double and single quotes unconverted.</td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_HTML401</b></td>
     *                   <td>
     *                   Handle code as HTML 4.01.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_XML1</b></td>
     *                   <td>
     *                   Handle code as XML 1.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_XHTML</b></td>
     *                   <td>
     *                   Handle code as XHTML.
     *                   </td>
     *                   </tr>
     *                   <tr valign="top">
     *                   <td><b>ENT_HTML5</b></td>
     *                   <td>
     *                   Handle code as HTML 5.
     *                   </td>
     *                   </tr>
     *                   </table>
     *                   </p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after being html encoded.</p>
     */
    public function htmlEncode(int $flags = \ENT_COMPAT): self
    {
        return static::create(
            $this->utf8::htmlentities(
                $this->str,
                $flags,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Capitalizes the first word of the string, replaces underscores with
     * spaces, and strips '_id'.
     *
     * EXAMPLE: <code>
     * s('author_id')->humanize(); // 'Author'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a humanized $str.</p>
     */
    public function humanize(): self
    {
        return static::create(
            $this->utf8::str_humanize($this->str),
            $this->encoding
        );
    }

    /**
     * Determine if the current string exists in another string. By
     * default, the comparison is case-sensitive, but can be made insensitive
     * by setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $str           <p>The string to compare against.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function in(string $str, bool $caseSensitive = true): bool
    {
        if ($caseSensitive) {
            return \strpos($str, $this->str) !== false;
        }

        return \stripos($str, $this->str) !== false;
    }

    /**
     * Returns the index of the first occurrence of $needle in the string,
     * and false if not found. Accepts an optional offset from which to begin
     * the search.
     *
     * EXAMPLE: <code>
     * s('string')->indexOf('ing'); // 3
     * </code>
     *
     * @param string $needle <p>Substring to look for.</p>
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
     */
    public function indexOf(string $needle, int $offset = 0)
    {
        return $this->utf8::strpos(
            $this->str,
            $needle,
            $offset,
            $this->encoding
        );
    }

    /**
     * Returns the index of the first occurrence of $needle in the string,
     * and false if not found. Accepts an optional offset from which to begin
     * the search.
     *
     * EXAMPLE: <code>
     * s('string')->indexOfIgnoreCase('ING'); // 3
     * </code>
     *
     * @param string $needle <p>Substring to look for.</p>
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
     */
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
    {
        return $this->utf8::stripos(
            $this->str,
            $needle,
            $offset,
            $this->encoding
        );
    }

    /**
     * Returns the index of the last occurrence of $needle in the string,
     * and false if not found. Accepts an optional offset from which to begin
     * the search. Offsets may be negative to count from the last character
     * in the string.
     *
     * EXAMPLE: <code>
     * s('foobarfoo')->indexOfLast('foo'); // 10
     * </code>
     *
     * @param string $needle <p>Substring to look for.</p>
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
     */
    public function indexOfLast(string $needle, int $offset = 0)
    {
        return $this->utf8::strrpos(
            $this->str,
            $needle,
            $offset,
            $this->encoding
        );
    }

    /**
     * Returns the index of the last occurrence of $needle in the string,
     * and false if not found. Accepts an optional offset from which to begin
     * the search. Offsets may be negative to count from the last character
     * in the string.
     *
     * EXAMPLE: <code>
     * s('fooBarFoo')->indexOfLastIgnoreCase('foo'); // 10
     * </code>
     *
     * @param string $needle <p>Substring to look for.</p>
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
     */
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
    {
        return $this->utf8::strripos(
            $this->str,
            $needle,
            $offset,
            $this->encoding
        );
    }

    /**
     * Inserts $substring into the string at the $index provided.
     *
     * EXAMPLE: <code>
     * s('fòôbř')->insert('à', 4); // 'fòôbàř'
     * </code>
     *
     * @param string $substring <p>String to be inserted.</p>
     * @param int    $index     <p>The index at which to insert the substring.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the insertion.</p>
     */
    public function insert(string $substring, int $index): self
    {
        return static::create(
            $this->utf8::str_insert(
                $this->str,
                $substring,
                $index,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns true if the string contains the $pattern, otherwise false.
     *
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
     * expression wildcards.
     *
     * EXAMPLE: <code>
     * s('Foo\\Bar\\Lall')->is('*\\Bar\\*'); // true
     * </code>
     *
     * @credit Originally from Laravel, thanks Taylor.
     *
     * @param string $pattern <p>The string or pattern to match against.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not we match the provided pattern.</p>
     */
    public function is(string $pattern): bool
    {
        if ($this->toString() === $pattern) {
            return true;
        }

        $quotedPattern = \preg_quote($pattern, '/');
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);

        return $this->matchesPattern('^' . $replaceWildCards . '\z');
    }

    /**
     * Returns true if the string contains only alphabetic chars, false otherwise.
     *
     * EXAMPLE: <code>
     * s('丹尼爾')->isAlpha(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only alphabetic chars.</p>
     */
    public function isAlpha(): bool
    {
        return $this->utf8::is_alpha($this->str);
    }

    /**
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
     *
     * EXAMPLE: <code>
     * s('دانيال1')->isAlphanumeric(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
     */
    public function isAlphanumeric(): bool
    {
        return $this->utf8::is_alphanumeric($this->str);
    }

    /**
     * Checks if a string is 7 bit ASCII.
     *
     * EXAMPLE: <code>s('白')->isAscii; // false</code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>
     *              <strong>true</strong> if it is ASCII<br>
     *              <strong>false</strong> otherwise
     *              </p>
     *
     * @noinspection GetSetMethodCorrectnessInspection
     */
    public function isAscii(): bool
    {
        return $this->utf8::is_ascii($this->str);
    }

    /**
     * Returns true if the string is base64 encoded, false otherwise.
     *
     * EXAMPLE: <code>
     * s('Zm9vYmFy')->isBase64(); // true
     * </code>
     *
     * @param bool $emptyStringIsValid
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is base64 encoded.</p>
     */
    public function isBase64($emptyStringIsValid = true): bool
    {
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
    }

    /**
     * Check if the input is binary... (is look like a hack).
     *
     * EXAMPLE: <code>s(01)->isBinary(); // true</code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isBinary(): bool
    {
        return $this->utf8::is_binary($this->str);
    }

    /**
     * Returns true if the string contains only whitespace chars, false otherwise.
     *
     * EXAMPLE: <code>
     * s("\n\t  \v\f")->isBlank(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only whitespace characters.</p>
     */
    public function isBlank(): bool
    {
        return $this->utf8::is_blank($this->str);
    }

    /**
     * Checks if the given string is equal to any "Byte Order Mark".
     *
     * WARNING: Use "s::string_has_bom()" if you will check BOM in a string.
     *
     * EXAMPLE: <code>s->("\xef\xbb\xbf")->isBom(); // true</code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p><strong>true</strong> if the $utf8_chr is Byte Order Mark, <strong>false</strong> otherwise.</p>
     */
    public function isBom(): bool
    {
        return $this->utf8::is_bom($this->str);
    }

    /**
     * Returns true if the string contains a valid E-Mail address, false otherwise.
     *
     * EXAMPLE: <code>
     * s('lars@moelleken.org')->isEmail(); // true
     * </code>
     *
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
     */
    public function isEmail(
        bool $useExampleDomainCheck = false,
        bool $useTypoInDomainCheck = false,
        bool $useTemporaryDomainCheck = false,
        bool $useDnsCheck = false
    ): bool {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the email-check class
         */
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
    }

    /**
     * Determine whether the string is considered to be empty.
     *
     * A variable is considered empty if it does not exist or if its value equals FALSE.
     *
     * EXAMPLE: <code>
     * s('')->isEmpty(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is empty().</p>
     */
    public function isEmpty(): bool
    {
        return $this->utf8::is_empty($this->str);
    }

    /**
     * Determine whether the string is equals to $str.
     * Alias for isEqualsCaseSensitive()
     *
     * EXAMPLE: <code>
     * s('foo')->isEquals('foo'); // true
     * </code>
     *
     * @param string|Stringy ...$str
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isEquals(...$str): bool
    {
        return $this->isEqualsCaseSensitive(...$str);
    }

    /**
     * Determine whether the string is equals to $str.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is equals.</p>
     */
    public function isEqualsCaseInsensitive(...$str): bool
    {
        $strUpper = $this->toUpperCase()->str;

        foreach ($str as $strTmp) {
            /**
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
             */
            if ($strTmp instanceof self) {
                if ($strUpper !== $strTmp->toUpperCase()->str) {
                    return false;
                }
            } elseif (\is_scalar($strTmp)) {
                if ($strUpper !== $this->utf8::strtoupper((string) $strTmp, $this->encoding)) {
                    return false;
                }
            } else {
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
            }
        }

        return true;
    }

    /**
     * Determine whether the string is equals to $str.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is equals.</p>
     */
    public function isEqualsCaseSensitive(...$str): bool
    {
        foreach ($str as $strTmp) {
            /**
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
             */
            if ($strTmp instanceof self) {
                if ($this->str !== $strTmp->str) {
                    return false;
                }
            } elseif (\is_scalar($strTmp)) {
                if ($this->str !== (string) $strTmp) {
                    return false;
                }
            } else {
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
            }
        }

        return true;
    }

    /**
     * Returns true if the string contains only hexadecimal chars, false otherwise.
     *
     * EXAMPLE: <code>
     * s('A102F')->isHexadecimal(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
     */
    public function isHexadecimal(): bool
    {
        return $this->utf8::is_hexadecimal($this->str);
    }

    /**
     * Returns true if the string contains HTML-Tags, false otherwise.
     *
     * EXAMPLE: <code>
     * s('<h1>foo</h1>')->isHtml(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains HTML-Tags.</p>
     */
    public function isHtml(): bool
    {
        return $this->utf8::is_html($this->str);
    }

    /**
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
     * in that an empty string is not considered valid JSON.
     *
     * EXAMPLE: <code>
     * s('{"foo":"bar"}')->isJson(); // true
     * </code>
     *
     * @param bool $onlyArrayOrObjectResultsAreValid
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is JSON.</p>
     */
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff?
         */
        return $this->utf8::is_json(
            $this->str,
            $onlyArrayOrObjectResultsAreValid
        );
    }

    /**
     * Returns true if the string contains only lower case chars, false otherwise.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->isLowerCase(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only lower case characters.</p>
     */
    public function isLowerCase(): bool
    {
        return $this->utf8::is_lowercase($this->str);
    }

    /**
     * Determine whether the string is considered to be NOT empty.
     *
     * A variable is considered NOT empty if it does exist or if its value equals TRUE.
     *
     * EXAMPLE: <code>
     * s('')->isNotEmpty(); // false
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is empty().</p>
     */
    public function isNotEmpty(): bool
    {
        return !$this->utf8::is_empty($this->str);
    }

    /**
     * Determine if the string is composed of numeric characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isNumeric(): bool
    {
        return \is_numeric($this->str);
    }

    /**
     * Determine if the string is composed of printable (non-invisible) characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isPrintable(): bool
    {
        return $this->utf8::is_printable($this->str);
    }

    /**
     * Determine if the string is composed of punctuation characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isPunctuation(): bool
    {
        return $this->utf8::is_punctuation($this->str);
    }

    /**
     * Returns true if the string is serialized, false otherwise.
     *
     * EXAMPLE: <code>
     * s('a:1:{s:3:"foo";s:3:"bar";}')->isSerialized(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str is serialized.</p>
     */
    public function isSerialized(): bool
    {
        return $this->utf8::is_serialized($this->str);
    }

    /**
     * Check if two strings are similar.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $str                     <p>The string to compare against.</p>
     * @param float  $minPercentForSimilarity [optional] <p>The percentage of needed similarity. | Default: 80%</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isSimilar(string $str, float $minPercentForSimilarity = 80.0): bool
    {
        return $this->similarity($str) >= $minPercentForSimilarity;
    }

    /**
     * Returns true if the string contains only lower case chars, false
     * otherwise.
     *
     * EXAMPLE: <code>
     * s('FÒÔBÀŘ')->isUpperCase(); // true
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only lower case characters.</p>
     */
    public function isUpperCase(): bool
    {
        return $this->utf8::is_uppercase($this->str);
    }

    /**
     * /**
     * Check if $url is an correct url.
     *
     * @param bool $disallow_localhost
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isUrl(bool $disallow_localhost = false): bool
    {
        return $this->utf8::is_url($this->str, $disallow_localhost);
    }

    /**
     * Check if the string is UTF-16.
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <strong>false</strong> if is't not UTF-16,<br>
     *                   <strong>1</strong> for UTF-16LE,<br>
     *                   <strong>2</strong> for UTF-16BE
     */
    public function isUtf16()
    {
        return $this->utf8::is_utf16($this->str);
    }

    /**
     * Check if the string is UTF-32.
     *
     * @psalm-mutation-free
     *
     * @return false|int
     *                   <strong>false</strong> if is't not UTF-32,<br>
     *                   <strong>1</strong> for UTF-32LE,<br>
     *                   <strong>2</strong> for UTF-32BE
     */
    public function isUtf32()
    {
        return $this->utf8::is_utf32($this->str);
    }

    /**
     * Checks whether the passed input contains only byte sequences that appear valid UTF-8.
     *
     * EXAMPLE: <code>
     * s('Iñtërnâtiônàlizætiøn')->isUtf8(); // true
     * //
     * s("Iñtërnâtiônàlizætiøn\xA0\xA1")->isUtf8(); // false
     * </code>
     *
     * @param bool $strict <p>Check also if the string is not UTF-16 or UTF-32.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function isUtf8(bool $strict = false): bool
    {
        return $this->utf8::is_utf8($this->str, $strict);
    }

    /**
     * Returns true if the string contains only whitespace chars, false otherwise.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str contains only whitespace characters.</p>
     */
    public function isWhitespace(): bool
    {
        return $this->isBlank();
    }

    /**
     * Returns value which can be serialized by json_encode().
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @noinspection ReturnTypeCanBeDeclaredInspection
     *
     * @psalm-mutation-free
     *
     * @return string The current value of the $str property
     */
    #[\ReturnTypeWillChange]
    public function jsonSerialize()
    {
        return (string) $this;
    }

    /**
     * Convert the string to kebab-case.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function kebabCase(): self
    {
        $words = \array_map(
            static function (self $word) {
                return $word->toLowerCase();
            },
            $this->words('', true)
        );

        return new static(\implode('-', $words), $this->encoding);
    }

    /**
     * Returns the last $n characters of the string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->last(3); // 'bàř'
     * </code>
     *
     * @param int $n <p>Number of characters to retrieve from the end.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the last $n chars.</p>
     */
    public function last(int $n): self
    {
        return static::create(
            $this->utf8::str_last_char(
                $this->str,
                $n,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $needle       <p>The string to look for.</p>
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function lastSubstringOf(string $needle, bool $beforeNeedle = false): self
    {
        return static::create(
            $this->utf8::str_substr_last(
                $this->str,
                $needle,
                $beforeNeedle,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $needle       <p>The string to look for.</p>
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function lastSubstringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
    {
        return static::create(
            $this->utf8::str_isubstr_last(
                $this->str,
                $needle,
                $beforeNeedle,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns the length of the string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->length(); // 6
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return int
     *             <p>The number of characters in $str given the encoding.</p>
     */
    public function length(): int
    {
        return (int) $this->utf8::strlen($this->str, $this->encoding);
    }

    /**
     * Line-Wrap the string after $limit, but also after the next word.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int         $limit           [optional] <p>The column width.</p>
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
     * @param bool        $add_final_break [optional] <p>
     *                                     If this flag is true, then the method will add a $break at the end
     *                                     of the result string.
     *                                     </p>
     * @param string|null $delimiter       [optional] <p>
     *                                     You can change the default behavior, where we split the string by newline.
     *                                     </p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function lineWrap(
        int $limit,
        string $break = "\n",
        bool $add_final_break = true,
        ?string $delimiter = null
    ): self {
        return static::create(
            $this->utf8::wordwrap_per_line(
                $this->str,
                $limit,
                $break,
                true,
                $add_final_break,
                $delimiter
            ),
            $this->encoding
        );
    }

    /**
     * Line-Wrap the string after $limit, but also after the next word.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int         $limit           [optional] <p>The column width.</p>
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
     * @param bool        $add_final_break [optional] <p>
     *                                     If this flag is true, then the method will add a $break at the end
     *                                     of the result string.
     *                                     </p>
     * @param string|null $delimiter       [optional] <p>
     *                                     You can change the default behavior, where we split the string by newline.
     *                                     </p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function lineWrapAfterWord(
        int $limit,
        string $break = "\n",
        bool $add_final_break = true,
        ?string $delimiter = null
    ): self {
        return static::create(
            $this->utf8::wordwrap_per_line(
                $this->str,
                $limit,
                $break,
                false,
                $add_final_break,
                $delimiter
            ),
            $this->encoding
        );
    }

    /**
     * Splits on newlines and carriage returns, returning an array of Stringy
     * objects corresponding to the lines in the string.
     *
     * EXAMPLE: <code>
     * s("fòô\r\nbàř\n")->lines(); // ['fòô', 'bàř', '']
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static[]
     *                  <p>An array of Stringy objects.</p>
     *
     * @phpstan-return array<int,static>
     */
    public function lines(): array
    {
        if ($this->str === '') {
            return [static::create('')];
        }

        $strings = $this->utf8::str_to_lines($this->str);
        /** @noinspection AlterInForeachInspection */
        foreach ($strings as &$str) {
            $str = static::create($str, $this->encoding);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var static[] $strings */
        $strings = $strings;

        return $strings;
    }

    /**
     * Splits on newlines and carriage returns, returning an array of Stringy
     * objects corresponding to the lines in the string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return CollectionStringy|static[]
     *                                    <p>An collection of Stringy objects.</p>
     *
     * @phpstan-return CollectionStringy<int,static>
     */
    public function linesCollection(): CollectionStringy
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
         */
        return CollectionStringy::create(
            $this->lines()
        );
    }

    /**
     * Returns the longest common prefix between the string and $otherStr.
     *
     * EXAMPLE: <code>
     * s('foobar')->longestCommonPrefix('foobaz'); // 'fooba'
     * </code>
     *
     * @param string $otherStr <p>Second string for comparison.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the longest common prefix.</p>
     */
    public function longestCommonPrefix(string $otherStr): self
    {
        return static::create(
            $this->utf8::str_longest_common_prefix(
                $this->str,
                $otherStr,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns the longest common substring between the string and $otherStr.
     * In the case of ties, it returns that which occurs first.
     *
     * EXAMPLE: <code>
     * s('foobar')->longestCommonSubstring('boofar'); // 'oo'
     * </code>
     *
     * @param string $otherStr <p>Second string for comparison.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the longest common substring.</p>
     */
    public function longestCommonSubstring(string $otherStr): self
    {
        return static::create(
            $this->utf8::str_longest_common_substring(
                $this->str,
                $otherStr,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns the longest common suffix between the string and $otherStr.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->longestCommonSuffix('fòrbàř'); // 'bàř'
     * </code>
     *
     * @param string $otherStr <p>Second string for comparison.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the longest common suffix.</p>
     */
    public function longestCommonSuffix(string $otherStr): self
    {
        return static::create(
            $this->utf8::str_longest_common_suffix(
                $this->str,
                $otherStr,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Converts the first character of the string to lower case.
     *
     * EXAMPLE: <code>
     * s('Σ Foo')->lowerCaseFirst(); // 'σ Foo'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the first character of $str being lower case.</p>
     */
    public function lowerCaseFirst(): self
    {
        return static::create(
            $this->utf8::lcfirst($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Determine if the string matches another string regardless of case.
     * Alias for isEqualsCaseInsensitive()
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @param string|Stringy ...$str
     *                               <p>The string to compare against.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function matchCaseInsensitive(...$str): bool
    {
        return $this->isEqualsCaseInsensitive(...$str);
    }

    /**
     * Determine if the string matches another string.
     * Alias for isEqualsCaseSensitive()
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @param string|Stringy ...$str
     *                               <p>The string to compare against.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     */
    public function matchCaseSensitive(...$str): bool
    {
        return $this->isEqualsCaseSensitive(...$str);
    }

    /**
     * Create a md5 hash from the current string.
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function md5(): self
    {
        return static::create($this->hash('md5'), $this->encoding);
    }

    /**
     * Replace all breaks [<br> | \r\n | \r | \n | ...] into "<br>".
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @return static
     */
    public function newLineToHtmlBreak(): self
    {
        return $this->removeHtmlBreak('<br>');
    }

    /**
     * Get every nth character of the string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $step   <p>The number of characters to step.</p>
     * @param int $offset [optional] <p>The string offset to start at.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function nth(int $step, int $offset = 0): self
    {
        $length = $step - 1;
        $substring = $this->substr($offset)->toString();

        if ($substring === '') {
            return new static('', $this->encoding);
        }

        \preg_match_all(
            "/(?:^|(?:.|\p{L}|\w){" . $length . "})(.|\p{L}|\w)/u",
            $substring,
            $matches
        );

        return new static(\implode('', $matches[1] ?? []), $this->encoding);
    }

    /**
     * Returns the integer value of the current string.
     *
     * EXAMPLE: <code>
     * s('foo1 ba2r')->extractIntegers(); // '12'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function extractIntegers(): self
    {
        if ($this->str === '') {
            return new static('', $this->encoding);
        }

        \preg_match_all('/(?<integers>\d+)/', $this->str, $matches);

        return static::create(
            \implode('', $matches['integers'] ?? []),
            $this->encoding
        );
    }

    /**
     * Returns the special chars of the current string.
     *
     * EXAMPLE: <code>
     * s('foo1 ba2!r')->extractSpecialCharacters(); // '!'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function extractSpecialCharacters(): self
    {
        if ($this->str === '') {
            return new static('', $this->encoding);
        }

        // no letter, no digit, no space
        \preg_match_all('/((?![\p{L}0-9\s]+).)/u', $this->str, $matches);

        return static::create(
            \implode('', $matches[0] ?? []),
            $this->encoding
        );
    }

    /**
     * Returns whether or not a character exists at an index. Offsets may be
     * negative to count from the last character in the string. Implements
     * part of the ArrayAccess interface.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $offset <p>The index to check.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not the index exists.</p>
     */
    public function offsetExists($offset): bool
    {
        return $this->utf8::str_offset_exists(
            $this->str,
            $offset,
            $this->encoding
        );
    }

    /**
     * Returns the character at the given index. Offsets may be negative to
     * count from the last character in the string. Implements part of the
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
     * does not exist.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
     *
     * @throws \OutOfBoundsException
     *                               <p>If the positive or negative offset does not exist.</p>
     *
     * @return string
     *                <p>The character at the specified index.</p>
     *
     * @psalm-mutation-free
     */
    public function offsetGet($offset): string
    {
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
    }

    /**
     * Implements part of the ArrayAccess interface, but throws an exception
     * when called. This maintains the immutability of Stringy objects.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int   $offset <p>The index of the character.</p>
     * @param mixed $value  <p>Value to set.</p>
     *
     * @throws \Exception
     *                    <p>When called.</p>
     *
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($offset, $value)
    {
        // Stringy is immutable, cannot directly set char
        throw new \Exception('Stringy object is immutable, cannot modify char');
    }

    /**
     * Implements part of the ArrayAccess interface, but throws an exception
     * when called. This maintains the immutability of Stringy objects.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $offset <p>The index of the character.</p>
     *
     * @throws \Exception
     *                    <p>When called.</p>
     *
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetUnset($offset)
    {
        // Don't allow directly modifying the string
        throw new \Exception('Stringy object is immutable, cannot unset char');
    }

    /**
     * Pads the string to a given length with $padStr. If length is less than
     * or equal to the length of the string, no padding takes places. The
     * default string used for padding is a space, and the default type (one of
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
     * if $padType isn't one of those 3 values.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->pad(9, '-/', 'left'); // '-/-fòôbàř'
     * </code>
     *
     * @param int    $length  <p>Desired string length after padding.</p>
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
     *
     * @throws \InvalidArgumentException
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
     *
     * @return static
     *                <p>Object with a padded $str.</p>
     *
     * @psalm-mutation-free
     */
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
    {
        return static::create(
            $this->utf8::str_pad(
                $this->str,
                $length,
                $padStr,
                $padType,
                $this->encoding
            )
        );
    }

    /**
     * Returns a new string of a given length such that both sides of the
     * string are padded. Alias for pad() with a $padType of 'both'.
     *
     * EXAMPLE: <code>
     * s('foo bar')->padBoth(9, ' '); // ' foo bar '
     * </code>
     *
     * @param int    $length <p>Desired string length after padding.</p>
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>String with padding applied.</p>
     */
    public function padBoth(int $length, string $padStr = ' '): self
    {
        return static::create(
            $this->utf8::str_pad_both(
                $this->str,
                $length,
                $padStr,
                $this->encoding
            )
        );
    }

    /**
     * Returns a new string of a given length such that the beginning of the
     * string is padded. Alias for pad() with a $padType of 'left'.
     *
     * EXAMPLE: <code>
     * s('foo bar')->padLeft(9, ' '); // '  foo bar'
     * </code>
     *
     * @param int    $length <p>Desired string length after padding.</p>
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>String with left padding.</p>
     */
    public function padLeft(int $length, string $padStr = ' '): self
    {
        return static::create(
            $this->utf8::str_pad_left(
                $this->str,
                $length,
                $padStr,
                $this->encoding
            )
        );
    }

    /**
     * Returns a new string of a given length such that the end of the string
     * is padded. Alias for pad() with a $padType of 'right'.
     *
     * EXAMPLE: <code>
     * s('foo bar')->padRight(10, '_*'); // 'foo bar_*_'
     * </code>
     *
     * @param int    $length <p>Desired string length after padding.</p>
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>String with right padding.</p>
     */
    public function padRight(int $length, string $padStr = ' '): self
    {
        return static::create(
            $this->utf8::str_pad_right(
                $this->str,
                $length,
                $padStr,
                $this->encoding
            )
        );
    }

    /**
     * Convert the string to PascalCase.
     * Alias for studlyCase()
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function pascalCase(): self
    {
        return $this->studlyCase();
    }

    /**
     * Returns a new string starting with $prefix.
     *
     * EXAMPLE: <code>
     * s('bàř')->prepend('fòô'); // 'fòôbàř'
     * </code>
     *
     * @param string ...$prefix <p>The string to append.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with appended $prefix.</p>
     */
    public function prepend(string ...$prefix): self
    {
        if (\count($prefix) <= 1) {
            $prefix = $prefix[0];
        } else {
            $prefix = \implode('', $prefix);
        }

        return static::create($prefix . $this->str, $this->encoding);
    }

    /**
     * Returns a new string starting with $prefix.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param CollectionStringy|static ...$prefix <p>The Stringy objects to append.</p>
     *
     * @phpstan-param CollectionStringy<int,static>|static ...$prefix
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with appended $prefix.</p>
     */
    public function prependStringy(...$prefix): self
    {
        $prefixStr = '';
        foreach ($prefix as $prefixTmp) {
            if ($prefixTmp instanceof CollectionStringy) {
                $prefixStr .= $prefixTmp->implode('');
            } else {
                $prefixStr .= $prefixTmp->toString();
            }
        }

        return static::create($prefixStr . $this->str, $this->encoding);
    }

    /**
     * Replaces all occurrences of $pattern in $str by $replacement.
     *
     * EXAMPLE: <code>
     * s('fòô ')->regexReplace('f[òô]+\s', 'bàř'); // 'bàř'
     * s('fò')->regexReplace('(ò)', '\\1ô'); // 'fòô'
     * </code>
     *
     * @param string $pattern     <p>The regular expression pattern.</p>
     * @param string $replacement <p>The string to replace with.</p>
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the result2ing $str after the replacements.</p>
     */
    public function regexReplace(
        string $pattern,
        string $replacement,
        string $options = '',
        string $delimiter = '/'
    ): self {
        return static::create(
            $this->utf8::regex_replace(
                $this->str,
                $pattern,
                $replacement,
                $options,
                $delimiter
            ),
            $this->encoding
        );
    }

    /**
     * Remove html via "strip_tags()" from the string.
     *
     * EXAMPLE: <code>
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtml('<br><br/>'); // 'řàb òf\', ô<br/>foo lall'
     * </code>
     *
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
     *                              not be stripped. Default: null
     *                              </p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function removeHtml(string $allowableTags = ''): self
    {
        return static::create(
            $this->utf8::remove_html($this->str, $allowableTags),
            $this->encoding
        );
    }

    /**
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
     *
     * EXAMPLE: <code>
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtmlBreak(''); // 'řàb <ô>òf\', ô< foo <a href="#">lall</a>'
     * </code>
     *
     * @param string $replacement [optional] <p>Default is a empty string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function removeHtmlBreak(string $replacement = ''): self
    {
        return static::create(
            $this->utf8::remove_html_breaks($this->str, $replacement),
            $this->encoding
        );
    }

    /**
     * Returns a new string with the prefix $substring removed, if present.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->removeLeft('fòô'); // 'bàř'
     * </code>
     *
     * @param string $substring <p>The prefix to remove.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object having a $str without the prefix $substring.</p>
     */
    public function removeLeft(string $substring): self
    {
        return static::create(
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Returns a new string with the suffix $substring removed, if present.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->removeRight('bàř'); // 'fòô'
     * </code>
     *
     * @param string $substring <p>The suffix to remove.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object having a $str without the suffix $substring.</p>
     */
    public function removeRight(string $substring): self
    {
        return static::create(
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Try to remove all XSS-attacks from the string.
     *
     * EXAMPLE: <code>
     * s('<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>')->removeXss(); // '<IMG >'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function removeXss(): self
    {
        /**
         * @var AntiXSS|null
         *
         * @psalm-suppress ImpureStaticVariable
         */
        static $antiXss = null;

        if ($antiXss === null) {
            $antiXss = new AntiXSS();
        }

        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the anti-xss class
         */
        $str = $antiXss->xss_clean($this->str);

        return static::create($str, $this->encoding);
    }

    /**
     * Returns a repeated string given a multiplier.
     *
     * EXAMPLE: <code>
     * s('α')->repeat(3); // 'ααα'
     * </code>
     *
     * @param int $multiplier <p>The number of times to repeat the string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a repeated str.</p>
     */
    public function repeat(int $multiplier): self
    {
        return static::create(
            \str_repeat($this->str, $multiplier),
            $this->encoding
        );
    }

    /**
     * Replaces all occurrences of $search in $str by $replacement.
     *
     * EXAMPLE: <code>
     * s('fòô bàř fòô bàř')->replace('fòô ', ''); // 'bàř bàř'
     * </code>
     *
     * @param string $search        <p>The needle to search for.</p>
     * @param string $replacement   <p>The string to replace with.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
    {
        if ($search === '' && $replacement === '') {
            return static::create($this->str, $this->encoding);
        }

        if ($this->str === '' && $search === '') {
            return static::create($replacement, $this->encoding);
        }

        if ($caseSensitive) {
            return static::create(
                \str_replace($search, $replacement, $this->str),
                $this->encoding
            );
        }

        return static::create(
            $this->utf8::str_ireplace($search, $replacement, $this->str),
            $this->encoding
        );
    }

    /**
     * Replaces all occurrences of $search in $str by $replacement.
     *
     * EXAMPLE: <code>
     * s('fòô bàř lall bàř')->replaceAll(['fòÔ ', 'lall'], '', false); // 'bàř bàř'
     * </code>
     *
     * @param string[]        $search        <p>The elements to search for.</p>
     * @param string|string[] $replacement   <p>The string to replace with.</p>
     * @param bool            $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
    {
        if ($caseSensitive) {
            return static::create(
                \str_replace($search, $replacement, $this->str),
                $this->encoding
            );
        }

        return static::create(
            $this->utf8::str_ireplace($search, $replacement, $this->str),
            $this->encoding
        );
    }

    /**
     * Replaces all occurrences of $search from the beginning of string with $replacement.
     *
     * EXAMPLE: <code>
     * s('fòô bàř fòô bàř')->replaceBeginning('fòô', ''); // ' bàř bàř'
     * </code>
     *
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replaceBeginning(string $search, string $replacement): self
    {
        return static::create(
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
            $this->encoding
        );
    }

    /**
     * Replaces all occurrences of $search from the ending of string with $replacement.
     *
     * EXAMPLE: <code>
     * s('fòô bàř fòô bàř')->replaceEnding('bàř', ''); // 'fòô bàř fòô '
     * </code>
     *
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replaceEnding(string $search, string $replacement): self
    {
        return static::create(
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
            $this->encoding
        );
    }

    /**
     * Replaces first occurrences of $search from the beginning of string with $replacement.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replaceFirst(string $search, string $replacement): self
    {
        return static::create(
            $this->utf8::str_replace_first($search, $replacement, $this->str),
            $this->encoding
        );
    }

    /**
     * Replaces last occurrences of $search from the ending of string with $replacement.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after the replacements.</p>
     */
    public function replaceLast(string $search, string $replacement): self
    {
        return static::create(
            $this->utf8::str_replace_last($search, $replacement, $this->str),
            $this->encoding
        );
    }

    /**
     * Returns a reversed string. A multibyte version of strrev().
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->reverse(); // 'řàbôòf'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a reversed $str.</p>
     */
    public function reverse(): self
    {
        return static::create($this->utf8::strrev($this->str), $this->encoding);
    }

    /**
     * Truncates the string to a given length, while ensuring that it does not
     * split words. If $substring is provided, and truncating occurs, the
     * string is further truncated so that the substring may be appended without
     * exceeding the desired length.
     *
     * EXAMPLE: <code>
     * s('What are your plans today?')->safeTruncate(22, '...'); // 'What are your plans...'
     * </code>
     *
     * @param int    $length                          <p>Desired length of the truncated string.</p>
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
     * @param bool   $ignoreDoNotSplitWordsForOneWord
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after truncating.</p>
     */
    public function safeTruncate(
        int $length,
        string $substring = '',
        bool $ignoreDoNotSplitWordsForOneWord = true
    ): self {
        return static::create(
            $this->utf8::str_truncate_safe(
                $this->str,
                $length,
                $substring,
                $this->encoding,
                $ignoreDoNotSplitWordsForOneWord
            ),
            $this->encoding
        );
    }

    /**
     * Set the internal character encoding.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $new_encoding <p>The desired character encoding.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function setInternalEncoding(string $new_encoding): self
    {
        return new static($this->str, $new_encoding);
    }

    /**
     * Create a sha1 hash from the current string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function sha1(): self
    {
        return static::create($this->hash('sha1'), $this->encoding);
    }

    /**
     * Create a sha256 hash from the current string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function sha256(): self
    {
        return static::create($this->hash('sha256'), $this->encoding);
    }

    /**
     * Create a sha512 hash from the current string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function sha512(): self
    {
        return static::create($this->hash('sha512'), $this->encoding);
    }

    /**
     * Shorten the string after $length, but also after the next word.
     *
     * EXAMPLE: <code>
     * s('this is a test')->shortenAfterWord(2, '...'); // 'this...'
     * </code>
     *
     * @param int    $length   <p>The given length.</p>
     * @param string $strAddOn [optional] <p>Default: '…'</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
    {
        return static::create(
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
            $this->encoding
        );
    }

    /**
     * A multibyte string shuffle function. It returns a string with its
     * characters in random order.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->shuffle(); // 'àôřbòf'
     * </code>
     *
     * @return static
     *                <p>Object with a shuffled $str.</p>
     */
    public function shuffle(): self
    {
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
    }

    /**
     * Calculate the similarity between two strings.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $str <p>The delimiting string.</p>
     *
     * @psalm-mutation-free
     *
     * @return float
     */
    public function similarity(string $str): float
    {
        \similar_text($this->str, $str, $percent);

        return $percent;
    }

    /**
     * Returns the substring beginning at $start, and up to, but not including
     * the index specified by $end. If $end is omitted, the function extracts
     * the remaining string. If $end is negative, it is computed from the end
     * of the string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->slice(3, -1); // 'bà'
     * </code>
     *
     * @param int $start <p>Initial index from which to begin extraction.</p>
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the extracted substring.</p>
     */
    public function slice(int $start, ?int $end = null): self
    {
        return static::create(
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Converts the string into an URL slug. This includes replacing non-ASCII
     * characters with their closest ASCII equivalents, removing remaining
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
     * $separator. The separator defaults to a single dash, and the string
     * is also converted to lowercase. The language of the source string can
     * also be supplied for language-specific transliteration.
     *
     * EXAMPLE: <code>
     * s('Using strings like fòô bàř')->slugify(); // 'using-strings-like-foo-bar'
     * </code>
     *
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
     * @param string                $language              [optional] <p>Language of the source string.</p>
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
     * @param bool                  $replace_extra_symbols [optional]  <p>Add some more replacements e.g. "£" with "
     *                                                     pound ".</p>
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
     * @param bool                  $use_transliterate     [optional]  <p>Use ASCII::to_transliterate() for unknown
     *                                                     chars.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has been converted to an URL slug.</p>
     *
     * @phpstan-param ASCII::*_LANGUAGE_CODE $language
     *
     * @noinspection PhpTooManyParametersInspection
     */
    public function slugify(
        string $separator = '-',
        string $language = 'en',
        array $replacements = [],
        bool $replace_extra_symbols = true,
        bool $use_str_to_lower = true,
        bool $use_transliterate = false
    ): self {
        return static::create(
            $this->ascii::to_slugify(
                $this->str,
                $separator,
                $language,
                $replacements,
                $replace_extra_symbols,
                $use_str_to_lower,
                $use_transliterate
            ),
            $this->encoding
        );
    }

    /**
     * Convert the string to snake_case.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function snakeCase(): self
    {
        $words = \array_map(
            static function (self $word) {
                return $word->toLowerCase();
            },
            $this->words('', true)
        );

        return new static(\implode('_', $words), $this->encoding);
    }

    /**
     * Convert a string to snake_case.
     *
     * EXAMPLE: <code>
     * s('foo1 Bar')->snakeize(); // 'foo_1_bar'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with $str in snake_case.</p>
     */
    public function snakeize(): self
    {
        return static::create(
            $this->utf8::str_snakeize($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Wrap the string after the first whitespace character after a given number
     * of characters.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int    $width <p>Number of characters at which to wrap.</p>
     * @param string $break [optional] <p>Character used to break the string. | Default "\n"</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function softWrap(int $width, string $break = "\n"): self
    {
        return $this->lineWrapAfterWord($width, $break, false);
    }

    /**
     * Splits the string with the provided regular expression, returning an
     * array of Stringy objects. An optional integer $limit will truncate the
     * results.
     *
     * EXAMPLE: <code>
     * s('foo,bar,baz')->split(',', 2); // ['foo', 'bar']
     * </code>
     *
     * @param string $pattern <p>The regex with which to split the string.</p>
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
     *                        limit</p>
     *
     * @psalm-mutation-free
     *
     * @return static[]
     *                  <p>An array of Stringy objects.</p>
     *
     * @phpstan-return array<int,static>
     */
    public function split(string $pattern, ?int $limit = null): array
    {
        if ($this->str === '') {
            return [];
        }

        if ($limit === null) {
            $limit = -1;
        }

        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
        foreach ($array as &$value) {
            $value = static::create($value, $this->encoding);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var static[] $array */
        $array = $array;

        return $array;
    }

    /**
     * Splits the string with the provided regular expression, returning an
     * collection of Stringy objects. An optional integer $limit will truncate the
     * results.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $pattern <p>The regex with which to split the string.</p>
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
     *                        limit</p>
     *
     * @psalm-mutation-free
     *
     * @return CollectionStringy|static[]
     *                                    <p>An collection of Stringy objects.</p>
     *
     * @phpstan-return CollectionStringy<int,static>
     */
    public function splitCollection(string $pattern, ?int $limit = null): CollectionStringy
    {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
         */
        return CollectionStringy::create(
            $this->split($pattern, $limit)
        );
    }

    /**
     * Returns true if the string begins with $substring, false otherwise. By
     * default, the comparison is case-sensitive, but can be made insensitive
     * by setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('FÒÔbàřbaz')->startsWith('fòôbàř', false); // true
     * </code>
     *
     * @param string $substring     <p>The substring to look for.</p>
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str starts with $substring.</p>
     */
    public function startsWith(string $substring, bool $caseSensitive = true): bool
    {
        if ($caseSensitive) {
            return $this->utf8::str_starts_with($this->str, $substring);
        }

        return $this->utf8::str_istarts_with($this->str, $substring);
    }

    /**
     * Returns true if the string begins with any of $substrings, false otherwise.
     * By default the comparison is case-sensitive, but can be made insensitive by
     * setting $caseSensitive to false.
     *
     * EXAMPLE: <code>
     * s('FÒÔbàřbaz')->startsWithAny(['fòô', 'bàř'], false); // true
     * </code>
     *
     * @param string[] $substrings    <p>Substrings to look for.</p>
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str starts with $substring.</p>
     */
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
    {
        if ($caseSensitive) {
            return $this->utf8::str_starts_with_any($this->str, $substrings);
        }

        return $this->utf8::str_istarts_with_any($this->str, $substrings);
    }

    /**
     * Remove one or more strings from the string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string|string[] $search One or more strings to be removed
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function strip($search): self
    {
        if (\is_array($search)) {
            return $this->replaceAll($search, '');
        }

        return $this->replace($search, '');
    }

    /**
     * Strip all whitespace characters. This includes tabs and newline characters,
     * as well as multibyte whitespace such as the thin space and ideographic space.
     *
     * EXAMPLE: <code>
     * s('   Ο     συγγραφέας  ')->stripWhitespace(); // 'Οσυγγραφέας'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function stripWhitespace(): self
    {
        return static::create(
            $this->utf8::strip_whitespace($this->str),
            $this->encoding
        );
    }

    /**
     * Remove css media-queries.
     *
     * EXAMPLE: <code>
     * s('test @media (min-width:660px){ .des-cla #mv-tiles{width:480px} } test ')->stripeCssMediaQueries(); // 'test  test '
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function stripeCssMediaQueries(): self
    {
        return static::create(
            $this->utf8::css_stripe_media_queries($this->str),
            $this->encoding
        );
    }

    /**
     * Remove empty html-tag.
     *
     * EXAMPLE: <code>
     * s('foo<h1></h1>bar')->stripeEmptyHtmlTags(); // 'foobar'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function stripeEmptyHtmlTags(): self
    {
        return static::create(
            $this->utf8::html_stripe_empty_tags($this->str),
            $this->encoding
        );
    }

    /**
     * Convert the string to StudlyCase.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function studlyCase(): self
    {
        $words = \array_map(
            static function (self $word) {
                return $word->substr(0, 1)
                    ->toUpperCase()
                    ->appendStringy($word->substr(1));
            },
            $this->words('', true)
        );

        return new static(\implode('', $words), $this->encoding);
    }

    /**
     * Returns the substring beginning at $start with the specified $length.
     * It differs from the $this->utf8::substr() function in that providing a $length of
     * null will return the rest of the string, rather than an empty string.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param int $start  <p>Position of the first character to use.</p>
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with its $str being the substring.</p>
     */
    public function substr(int $start, ?int $length = null): self
    {
        return static::create(
            $this->utf8::substr(
                $this->str,
                $start,
                $length,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Return part of the string.
     * Alias for substr()
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->substring(2, 3); // 'ôbà'
     * </code>
     *
     * @param int $start  <p>Starting position of the substring.</p>
     * @param int $length [optional] <p>Length of substring.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function substring(int $start, ?int $length = null): self
    {
        if ($length === null) {
            return $this->substr($start);
        }

        return $this->substr($start, $length);
    }

    /**
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $needle       <p>The string to look for.</p>
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function substringOf(string $needle, bool $beforeNeedle = false): self
    {
        return static::create(
            $this->utf8::str_substr_first(
                $this->str,
                $needle,
                $beforeNeedle,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
     * If no match is found returns new empty Stringy object.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $needle       <p>The string to look for.</p>
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function substringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
    {
        return static::create(
            $this->utf8::str_isubstr_first(
                $this->str,
                $needle,
                $beforeNeedle,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Surrounds $str with the given substring.
     *
     * EXAMPLE: <code>
     * s(' ͜ ')->surround('ʘ'); // 'ʘ ͜ ʘ'
     * </code>
     *
     * @param string $substring <p>The substring to add to both sides.</P>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str had the substring both prepended and appended.</p>
     */
    public function surround(string $substring): self
    {
        return static::create(
            $substring . $this->str . $substring,
            $this->encoding
        );
    }

    /**
     * Returns a case swapped version of the string.
     *
     * EXAMPLE: <code>
     * s('Ντανιλ')->swapCase(); // 'νΤΑΝΙΛ'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has each character's case swapped.</P>
     */
    public function swapCase(): self
    {
        return static::create(
            $this->utf8::swapCase($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Returns a string with smart quotes, ellipsis characters, and dashes from
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
     * equivalents.
     *
     * EXAMPLE: <code>
     * s('“I see…”')->tidy(); // '"I see..."'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has those characters removed.</p>
     */
    public function tidy(): self
    {
        return static::create(
            $this->ascii::normalize_msword($this->str),
            $this->encoding
        );
    }

    /**
     * Returns a trimmed string with the first letter of each word capitalized.
     * Also accepts an array, $ignore, allowing you to list words not to be
     * capitalized.
     *
     * EXAMPLE: <code>
     * $ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the'];
     * s('i like to watch television')->titleize($ignore); // 'I Like to Watch Television'
     * </code>
     *
     * @param string[]|null $ignore            [optional] <p>An array of words not to capitalize or null.
     *                                         Default: null</p>
     * @param string|null   $word_define_chars [optional] <p>An string of chars that will be used as whitespace
     *                                         separator === words.</p>
     * @param string|null   $language          [optional] <p>Language of the source string.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a titleized $str.</p>
     */
    public function titleize(
        ?array $ignore = null,
        ?string $word_define_chars = null,
        ?string $language = null
    ): self {
        return static::create(
            $this->utf8::str_titleize(
                $this->str,
                $ignore,
                $this->encoding,
                false,
                $language,
                false,
                true,
                $word_define_chars
            ),
            $this->encoding
        );
    }

    /**
     * Returns a trimmed string in proper title case: Also accepts an array, $ignore, allowing you to list words not to
     * be capitalized.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * Adapted from John Gruber's script.
     *
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
     *
     * @param string[] $ignore <p>An array of words not to capitalize.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a titleized $str</p>
     */
    public function titleizeForHumans(array $ignore = []): self
    {
        return static::create(
            $this->utf8::str_titleize_for_humans(
                $this->str,
                $ignore,
                $this->encoding
            ),
            $this->encoding
        );
    }

    /**
     * Returns an ASCII version of the string. A set of non-ASCII characters are
     * replaced with their closest ASCII counterparts, and the rest are removed
     * by default. The language or locale of the source string can be supplied
     * for language-specific transliteration in any of the following formats:
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
     * to "aeoeue" rather than "aou" as in other languages.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->toAscii(); // 'foobar'
     * </code>
     *
     * @param string $language          [optional] <p>Language of the source string.</p>
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
     *                                  unsupported characters.</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str contains only ASCII characters.</p>
     *
     * @phpstan-param ASCII::*_LANGUAGE_CODE $language
     */
    public function toAscii(string $language = 'en', bool $removeUnsupported = true): self
    {
        return static::create(
            $this->ascii::to_ascii(
                $this->str,
                $language,
                $removeUnsupported
            ),
            $this->encoding
        );
    }

    /**
     * Returns a boolean representation of the given logical string value.
     * For example, <strong>'true', '1', 'on' and 'yes'</strong> will return true. <strong>'false', '0',
     * 'off', and 'no'</strong> will return false. In all instances, case is ignored.
     * For other numeric strings, their sign will determine the return value.
     * In addition, blank strings consisting of only whitespace will return
     * false. For all other strings, the return value is a result of a
     * boolean cast.
     *
     * EXAMPLE: <code>
     * s('OFF')->toBoolean(); // false
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>A boolean value for the string.</p>
     */
    public function toBoolean(): bool
    {
        /**
         * @psalm-suppress ArgumentTypeCoercion -> maybe the string looks like an int ;)
         * @phpstan-ignore-next-line
         */
        return $this->utf8::to_boolean($this->str);
    }

    /**
     * Converts all characters in the string to lowercase.
     *
     * EXAMPLE: <code>
     * s('FÒÔBÀŘ')->toLowerCase(); // 'fòôbàř'
     * </code>
     *
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with all characters of $str being lowercase.</p>
     */
    public function toLowerCase($tryToKeepStringLength = false, $lang = null): self
    {
        return static::create(
            $this->utf8::strtolower(
                $this->str,
                $this->encoding,
                false,
                $lang,
                $tryToKeepStringLength
            ),
            $this->encoding
        );
    }

    /**
     * Converts each tab in the string to some number of spaces, as defined by
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
     *
     * EXAMPLE: <code>
     * s(' String speech = "Hi"')->toSpaces(); // '    String speech = "Hi"'
     * </code>
     *
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has had tabs switched to spaces.</p>
     */
    public function toSpaces(int $tabLength = 4): self
    {
        if ($tabLength === 4) {
            $tab = '    ';
        } elseif ($tabLength === 2) {
            $tab = '  ';
        } else {
            $tab = \str_repeat(' ', $tabLength);
        }

        return static::create(
            \str_replace("\t", $tab, $this->str),
            $this->encoding
        );
    }

    /**
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
     * string.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->toString(); // 'fòôbàř'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return string
     */
    public function toString(): string
    {
        return (string) $this->str;
    }

    /**
     * Converts each occurrence of some consecutive number of spaces, as
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
     * are converted to a tab.
     *
     * EXAMPLE: <code>
     * s('    fòô    bàř')->toTabs(); // '   fòô bàř'
     * </code>
     *
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has had spaces switched to tabs.</p>
     */
    public function toTabs(int $tabLength = 4): self
    {
        if ($tabLength === 4) {
            $tab = '    ';
        } elseif ($tabLength === 2) {
            $tab = '  ';
        } else {
            $tab = \str_repeat(' ', $tabLength);
        }

        return static::create(
            \str_replace($tab, "\t", $this->str),
            $this->encoding
        );
    }

    /**
     * Converts the first character of each word in the string to uppercase
     * and all other chars to lowercase.
     *
     * EXAMPLE: <code>
     * s('fòô bàř')->toTitleCase(); // 'Fòô Bàř'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with all characters of $str being title-cased.</p>
     */
    public function toTitleCase(): self
    {
        return static::create(
            $this->utf8::titlecase($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Returns an ASCII version of the string. A set of non-ASCII characters are
     * replaced with their closest ASCII counterparts, and the rest are removed
     * unless instructed otherwise.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
     *                        performance | Default: false</p>
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str contains only ASCII characters.</p>
     */
    public function toTransliterate(bool $strict = false, string $unknown = '?'): self
    {
        return static::create(
            $this->ascii::to_transliterate($this->str, $unknown, $strict),
            $this->encoding
        );
    }

    /**
     * Converts all characters in the string to uppercase.
     *
     * EXAMPLE: <code>
     * s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ'
     * </code>
     *
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with all characters of $str being uppercase.</p>
     */
    public function toUpperCase($tryToKeepStringLength = false, $lang = null): self
    {
        return static::create(
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
            $this->encoding
        );
    }

    /**
     * Returns a string with whitespace removed from the start and end of the
     * string. Supports the removal of unicode whitespace. Accepts an optional
     * string of characters to strip instead of the defaults.
     *
     * EXAMPLE: <code>
     * s('  fòôbàř  ')->trim(); // 'fòôbàř'
     * </code>
     *
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a trimmed $str.</p>
     */
    public function trim(?string $chars = null): self
    {
        return static::create(
            $this->utf8::trim($this->str, $chars),
            $this->encoding
        );
    }

    /**
     * Returns a string with whitespace removed from the start of the string.
     * Supports the removal of unicode whitespace. Accepts an optional
     * string of characters to strip instead of the defaults.
     *
     * EXAMPLE: <code>
     * s('  fòôbàř  ')->trimLeft(); // 'fòôbàř  '
     * </code>
     *
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a trimmed $str.</p>
     */
    public function trimLeft(?string $chars = null): self
    {
        return static::create(
            $this->utf8::ltrim($this->str, $chars),
            $this->encoding
        );
    }

    /**
     * Returns a string with whitespace removed from the end of the string.
     * Supports the removal of unicode whitespace. Accepts an optional
     * string of characters to strip instead of the defaults.
     *
     * EXAMPLE: <code>
     * s('  fòôbàř  ')->trimRight(); // '  fòôbàř'
     * </code>
     *
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with a trimmed $str.</p>
     */
    public function trimRight(?string $chars = null): self
    {
        return static::create(
            $this->utf8::rtrim($this->str, $chars),
            $this->encoding
        );
    }

    /**
     * Truncates the string to a given length. If $substring is provided, and
     * truncating occurs, the string is further truncated so that the substring
     * may be appended without exceeding the desired length.
     *
     * EXAMPLE: <code>
     * s('What are your plans today?')->truncate(19, '...'); // 'What are your pl...'
     * </code>
     *
     * @param int    $length    <p>Desired length of the truncated string.</p>
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the resulting $str after truncating.</p>
     */
    public function truncate(int $length, string $substring = ''): self
    {
        return static::create(
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Returns a lowercase and trimmed string separated by underscores.
     * Underscores are inserted before uppercase characters (with the exception
     * of the first character of the string), and in place of spaces as well as
     * dashes.
     *
     * EXAMPLE: <code>
     * s('TestUCase')->underscored(); // 'test_u_case'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with an underscored $str.</p>
     */
    public function underscored(): self
    {
        return $this->delimit('_');
    }

    /**
     * Returns an UpperCamelCase version of the supplied string. It trims
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
     * and underscores, and removes spaces, dashes, underscores.
     *
     * EXAMPLE: <code>
     * s('Upper Camel-Case')->upperCamelize(); // 'UpperCamelCase'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with $str in UpperCamelCase.</p>
     */
    public function upperCamelize(): self
    {
        return static::create(
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
            $this->encoding
        );
    }

    /**
     * Converts the first character of the supplied string to upper case.
     *
     * EXAMPLE: <code>
     * s('σ foo')->upperCaseFirst(); // 'Σ foo'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object with the first character of $str being upper case.</p>
     */
    public function upperCaseFirst(): self
    {
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
    }

    /**
     * Simple url-decoding.
     *
     * e.g:
     * 'test+test' => 'test test'
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlDecode(): self
    {
        return static::create(\urldecode($this->str));
    }

    /**
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
     *
     * e.g:
     * 'test+test'                     => 'test test'
     * 'D&#252;sseldorf'               => 'Düsseldorf'
     * 'D%FCsseldorf'                  => 'Düsseldorf'
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
     * 'DÃ¼sseldorf'                   => 'Düsseldorf'
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlDecodeMulti(): self
    {
        return static::create($this->utf8::urldecode($this->str));
    }

    /**
     * Simple url-decoding.
     *
     * e.g:
     * 'test+test' => 'test+test
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlDecodeRaw(): self
    {
        return static::create(\rawurldecode($this->str));
    }

    /**
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
     *
     * e.g:
     * 'test+test'                     => 'test+test'
     * 'D&#252;sseldorf'               => 'Düsseldorf'
     * 'D%FCsseldorf'                  => 'Düsseldorf'
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
     * 'DÃ¼sseldorf'                   => 'Düsseldorf'
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlDecodeRawMulti(): self
    {
        return static::create($this->utf8::rawurldecode($this->str));
    }

    /**
     * Simple url-encoding.
     *
     * e.g:
     * 'test test' => 'test+test'
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlEncode(): self
    {
        return static::create(\urlencode($this->str));
    }

    /**
     * Simple url-encoding.
     *
     * e.g:
     * 'test test' => 'test%20test'
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function urlEncodeRaw(): self
    {
        return static::create(\rawurlencode($this->str));
    }

    /**
     * Converts the string into an URL slug. This includes replacing non-ASCII
     * characters with their closest ASCII equivalents, removing remaining
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
     * $separator. The separator defaults to a single dash, and the string
     * is also converted to lowercase.
     *
     * EXAMPLE: <code>
     * s('Using strings like fòô bàř - 1$')->urlify(); // 'using-strings-like-foo-bar-1-dollar'
     * </code>
     *
     * @param string                $separator    [optional] <p>The string used to replace whitespace. Default: '-'</p>
     * @param string                $language     [optional] <p>The language for the url. Default: 'en'</p>
     * @param array<string, string> $replacements [optional] <p>A map of replaceable strings.</p>
     * @param bool                  $strToLower   [optional] <p>string to lower. Default: true</p>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str has been converted to an URL slug.</p>
     *
     * @psalm-suppress ImpureMethodCall :/
     */
    public function urlify(
        string $separator = '-',
        string $language = 'en',
        array $replacements = [],
        bool $strToLower = true
    ): self {
        // init
        $str = $this->str;

        foreach ($replacements as $from => $to) {
            $str = \str_replace($from, $to, $str);
        }

        return static::create(
            URLify::slug(
                $str,
                $language,
                $separator,
                $strToLower
            ),
            $this->encoding
        );
    }

    /**
     * Converts the string into an valid UTF-8 string.
     *
     * EXAMPLE: <code>
     * s('DÃ¼sseldorf')->utf8ify(); // 'Düsseldorf'
     * </code>
     *
     * @psalm-mutation-free
     *
     * @return static
     */
    public function utf8ify(): self
    {
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
    }

    /**
     * Convert a string into an array of words.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
     *
     * @psalm-mutation-free
     *
     * @return static[]
     *
     * @phpstan-return array<int,static>
     */
    public function words(
        string $char_list = '',
        bool $remove_empty_values = false,
        ?int $remove_short_values = null
    ): array {
        if ($remove_short_values === null) {
            $strings = $this->utf8::str_to_words(
                $this->str,
                $char_list,
                $remove_empty_values
            );
        } else {
            $strings = $this->utf8::str_to_words(
                $this->str,
                $char_list,
                $remove_empty_values,
                $remove_short_values
            );
        }

        /** @noinspection AlterInForeachInspection */
        foreach ($strings as &$string) {
            $string = static::create($string);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var static[] $strings */
        $strings = $strings;

        return $strings;
    }

    /**
     * Convert a string into an collection of words.
     *
     * EXAMPLE: <code>
     * S::create('中文空白 oöäü#s')->wordsCollection('#', true)->toStrings(); // ['中文空白', 'oöäü#s']
     * </code>
     *
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
     *
     * @psalm-mutation-free
     *
     * @return CollectionStringy|static[]
     *                                    <p>An collection of Stringy objects.</p>
     *
     * @phpstan-return CollectionStringy<int,static>
     */
    public function wordsCollection(
        string $char_list = '',
        bool $remove_empty_values = false,
        ?int $remove_short_values = null
    ): CollectionStringy {
        /**
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
         */
        return CollectionStringy::create(
            $this->words(
                $char_list,
                $remove_empty_values,
                $remove_short_values
            )
        );
    }

    /**
     * Surrounds $str with the given substring.
     *
     * EXAMPLE: <code>
     * </code>
     *
     * @param string $substring <p>The substring to add to both sides.</P>
     *
     * @psalm-mutation-free
     *
     * @return static
     *                <p>Object whose $str had the substring both prepended and appended.</p>
     */
    public function wrap(string $substring): self
    {
        return $this->surround($substring);
    }

    /**
     * Returns the replacements for the toAscii() method.
     *
     * @psalm-mutation-free
     *
     * @return array<string, array<int, string>>
     *                                           <p>An array of replacements.</p>
     *
     * @deprecated   this is only here for backward-compatibly reasons
     */
    protected function charsArray(): array
    {
        return $this->ascii::charsArrayWithMultiLanguageValues();
    }

    /**
     * Returns true if $str matches the supplied pattern, false otherwise.
     *
     * @param string $pattern <p>Regex pattern to match against.</p>
     *
     * @psalm-mutation-free
     *
     * @return bool
     *              <p>Whether or not $str matches the pattern.</p>
     */
    protected function matchesPattern(string $pattern): bool
    {
        return $this->utf8::str_matches_pattern($this->str, $pattern);
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Abstract command builder.
 *
 * @SuppressWarnings(PHPMD.NumberOfChildren)
 *
 * @deprecated This class is deprecated since 1.5 and where removed in 2.0. Use the trait CommandBuilderTrait.
 */
abstract class AbstractCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Add command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class AddCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'add';
    }

    /**
     * Add the dry run option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function dryRun()
    {
        $this->arguments[] = '--dry-run';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the patch option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function patch()
    {
        $this->arguments[] = '--patch';
        return $this;
    }

    /**
     * Add the update option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function update()
    {
        $this->arguments[] = '--update';
        return $this;
    }

    /**
     * Add the all option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the no-all option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function noAll()
    {
        $this->arguments[] = '--no-all';
        return $this;
    }

    /**
     * Add the intent-to-add option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function intentToAdd()
    {
        $this->arguments[] = '--intent-to-add';
        return $this;
    }

    /**
     * Add the refresh option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function refresh()
    {
        $this->arguments[] = '--refresh';
        return $this;
    }

    /**
     * Add the ignore-errors option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function ignoreErrors()
    {
        $this->arguments[] = '--ignore-errors';
        return $this;
    }

    /**
     * Add the ignore-missing option to the command line.
     *
     * @return AddCommandBuilder
     */
    public function ignoreMissing()
    {
        $this->arguments[] = '--ignore-missing';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $pathspec Optional path spec to add to the command line.
     *
     * @param null|string $_        More arguments to append to the command.
     *
     * @return mixed
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathspec = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathspec) {
                $this->arguments[] = $pathspec;
            }
        }
        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Branch command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class BranchCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const WHEN_ALWAYS = 'always';

    public const WHEN_NEVER = 'never';

    public const WHEN_AUTO = 'auto';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'branch';
    }

    /**
     * Add the D option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function delete()
    {
        $this->arguments[] = '-D';
        return $this;
    }

    /**
     * Add the create-reflog option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function createReflog()
    {
        $this->arguments[] = '--create-reflog';
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the M option to the command line.
     *
     * @param bool|string $oldName Optionally pass the old name.
     *
     * @return BranchCommandBuilder
     */
    public function move($oldName = false)
    {
        $this->arguments[] = '-M';
        if ($oldName) {
            $this->arguments[] = $oldName;
        }
        return $this;
    }

    /**
     * Add the color option to the command line.
     *
     * @param string $when When to use colors.
     *
     * @return BranchCommandBuilder
     *
     * @see BranchCommandBuilder::WHEN_ALWAYS
     * @see BranchCommandBuilder::WHEN_NEVER
     * @see BranchCommandBuilder::WHEN_AUTO.
     */
    public function color($when)
    {
        $this->arguments[] = '--color=' . $when;
        return $this;
    }

    /**
     * Add the no-color option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function noColor()
    {
        $this->arguments[] = '--no-color';
        return $this;
    }

    /**
     * Add the column option to the command line.
     *
     * @param bool|string $options Optional options to use.
     *
     * @return BranchCommandBuilder
     */
    public function column($options = false)
    {
        $this->arguments[] = '--column' . ($options ? '=' . $options : '');
        return $this;
    }

    /**
     * Add the no-column option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function noColumn()
    {
        $this->arguments[] = '--no-column';
        return $this;
    }

    /**
     * Add the remotes option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function remotes()
    {
        $this->arguments[] = '--remotes';
        return $this;
    }

    /**
     * Add the all option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the list option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function listBranches()
    {
        $this->arguments[] = '--list';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the abbrev option to the command line.
     *
     * @param int $length The length after which to cut.
     *
     * @return BranchCommandBuilder
     */
    public function abbrev($length)
    {
        $this->arguments[] = '--abbrev=' . $length;
        return $this;
    }

    /**
     * Add the no-abbrev option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function noAbbrev()
    {
        $this->arguments[] = '--no-abbrev';
        return $this;
    }

    /**
     * Add the track option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function track()
    {
        $this->arguments[] = '--track';
        return $this;
    }

    /**
     * Add the no-track option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function noTrack()
    {
        $this->arguments[] = '--no-track';
        return $this;
    }

    /**
     * Add the set-upstream option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function setUpstream()
    {
        $this->arguments[] = '--set-upstream';
        return $this;
    }

    /**
     * Add the set-upstream-to option to the command line.
     *
     * @param string $upstream The upstream branch name.
     *
     * @return BranchCommandBuilder
     */
    public function setUpstreamTo($upstream)
    {
        $this->arguments[] = '--set-upstream-to=' . $upstream;
        return $this;
    }

    /**
     * Add the unset-upstream option to the command line.
     *
     * @return BranchCommandBuilder
     */
    public function unsetUpstream()
    {
        $this->arguments[] = '--unset-upstream';
        return $this;
    }

    /**
     * Add the contains option to the command line.
     *
     * @param string $commit The commit hash.
     *
     * @return BranchCommandBuilder
     */
    public function contains($commit)
    {
        $this->arguments[] = '--contains';
        $this->arguments[] = $commit;
        return $this;
    }

    /**
     * Add the merged option to the command line.
     *
     * @param string $commit The commit hash.
     *
     * @return BranchCommandBuilder
     */
    public function merged($commit)
    {
        $this->arguments[] = '--merged';
        $this->arguments[] = $commit;
        return $this;
    }

    /**
     * Add the no-merged option to the command line.
     *
     * @param string $commit The commit hash.
     *
     * @return BranchCommandBuilder
     */
    public function noMerged($commit)
    {
        $this->arguments[] = '--no-merged';
        $this->arguments[] = $commit;
        return $this;
    }

    /**
     * Execute the command and return the result.
     *
     * @param null|string $branchName Optionally the branch name on which to work on.
     *
     * @return string
     */
    public function execute($branchName = null)
    {
        if ($branchName) {
            $this->arguments[] = $branchName;
        }
        return (string) $this->run();
    }

    /**
     * Retrieve the branch names.
     *
     * @return list<string>
     */
    public function getNames()
    {
        $branches = $this->execute();
        $branches = \explode("\n", $branches);
        $branches = \array_map(
            function ($branch) {
                return \trim(\ltrim($branch, '*'));
            },
            $branches
        );
        $branches = \array_filter($branches);

        return \array_values($branches);
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Checkout command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class CheckoutCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'checkout';
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the ours option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function ours()
    {
        $this->arguments[] = '--ours';
        return $this;
    }

    /**
     * Add the theirs option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function theirs()
    {
        $this->arguments[] = '--theirs';
        return $this;
    }

    /**
     * Add the b option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function create()
    {
        $this->arguments[] = '-b';
        return $this;
    }

    /**
     * Add the B option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function overwrite()
    {
        $this->arguments[] = '-B';
        return $this;
    }

    /**
     * Add the track option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function track()
    {
        $this->arguments[] = '--track';
        return $this;
    }

    /**
     * Add the no-track option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function noTrack()
    {
        $this->arguments[] = '--no-track';
        return $this;
    }

    /**
     * Add the l option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function reflog()
    {
        $this->arguments[] = '-l';
        return $this;
    }

    /**
     * Add the orphan option to the command line.
     *
     * @param null|string $newBranch The name of the new orphan branch.
     *
     * @return CheckoutCommandBuilder
     */
    public function orphan($newBranch = null)
    {
        $this->arguments[] = '--orphan';
        if ($newBranch) {
            $this->arguments[] = $newBranch;
        }
        return $this;
    }

    /**
     * Add the ignore-skip-worktree-bits option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function ignoreSkipWorktreeBits()
    {
        $this->arguments[] = '--ignore-skip-worktree-bits';
        return $this;
    }

    /**
     * Add the merge option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function merge()
    {
        $this->arguments[] = '--merge';
        return $this;
    }

    /**
     * Add the conflict option to the command line.
     *
     * @param string $style The conflicht handler style.
     *
     * @return CheckoutCommandBuilder
     */
    public function conflict($style)
    {
        $this->arguments[] = '--conflict=' . $style;
        return $this;
    }

    /**
     * Add the patch option to the command line.
     *
     * @return CheckoutCommandBuilder
     */
    public function patch()
    {
        $this->arguments[] = '--patch';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $branchOrTreeIsh Name of the branch or tree.
     *
     * @param null        $path            Path to which check out.
     *
     * @param null|string $_               More optional arguments to append to the command.
     *
     * @return mixed
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($branchOrTreeIsh = null, $path = null, $_ = null)
    {
        /** @var list<string> $paths */
        $paths = \func_get_args();
        if ($branchOrTreeIsh) {
            \array_shift($paths);
            $this->arguments[] = $branchOrTreeIsh;
        }

        if (\count($paths)) {
            $this->arguments[] = '--';
            foreach ($paths as $path) {
                $this->arguments[] = $path;
            }
        }

        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Clone command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class CloneCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'clone';
    }

    /**
     * Add the local option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function local()
    {
        $this->arguments[] = '--local';
        return $this;
    }

    /**
     * Add the no-hardlinks option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function noHardlinks()
    {
        $this->arguments[] = '--no-hardlinks';
        return $this;
    }

    /**
     * Add the shared option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function shared()
    {
        $this->arguments[] = '--shared';
        return $this;
    }

    /**
     * Add the reference option to the command line.
     *
     * @param string $repository The repository name.
     *
     * @return CloneCommandBuilder
     */
    public function reference($repository)
    {
        $this->arguments[] = '--reference';
        $this->arguments[] = $repository;
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the progress option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function progress()
    {
        $this->arguments[] = '--progress';
        return $this;
    }

    /**
     * Add the no-checkout option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function noCheckout()
    {
        $this->arguments[] = '--no-checkout';
        return $this;
    }

    /**
     * Add the bare option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function bare()
    {
        $this->arguments[] = '--bare';
        return $this;
    }

    /**
     * Add the mirror option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function mirror()
    {
        $this->arguments[] = '--mirror';
        return $this;
    }

    /**
     * Add the origin option to the command line.
     *
     * @param string $name The name of the origin.
     *
     * @return CloneCommandBuilder
     */
    public function origin($name)
    {
        $this->arguments[] = '--origin';
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the branch option to the command line.
     *
     * @param string $name The branch name.
     *
     * @return CloneCommandBuilder
     */
    public function branch($name)
    {
        $this->arguments[] = '--branch';
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the upload-pack option to the command line.
     *
     * @param string $uploadPack The upload pack.
     *
     * @return CloneCommandBuilder
     */
    public function uploadPack($uploadPack)
    {
        $this->arguments[] = '--upload-pack';
        $this->arguments[] = $uploadPack;
        return $this;
    }

    /**
     * Add the template option to the command line.
     *
     * @param string $templateDirectory The template directory.
     *
     * @return CloneCommandBuilder
     */
    public function template($templateDirectory)
    {
        $this->arguments[] = '--template=' . $templateDirectory;
        return $this;
    }

    /**
     * Add the config option to the command line.
     *
     * @param string $key   The config key.
     *
     * @param string $value The config value.
     *
     * @return CloneCommandBuilder
     */
    public function config($key, $value)
    {
        $this->arguments[] = '--config';
        $this->arguments[] = $key . '=' . $value;
        return $this;
    }

    /**
     * Add the depth option to the command line.
     *
     * @param string $depth The depth.arguments[] = rn CloneCommandBuildr.
     *
     * @return CloneCommandBuilder
     */
    public function depth($depth)
    {
        $this->arguments[] = '--depth';
        $this->arguments[] = $depth;
        return $this;
    }

    /**
     * Add the no-single-branch option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function noSingleBranch()
    {
        $this->arguments[] = '--no-single-branch';
        return $this;
    }

    /**
     * Add the single-branch option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function singleBranch()
    {
        $this->arguments[] = '--single-branch';
        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @return CloneCommandBuilder
     */
    public function recursive()
    {
        $this->arguments[] = '--recursive';
        return $this;
    }

    /**
     * Add the separate-git-dir option to the command line.
     *
     * @param string $gitDir The git dir to use.
     *
     * @return CloneCommandBuilder
     */
    public function separateGitDir($gitDir)
    {
        $this->arguments[] = '--separate-git-dir=' . $gitDir;
        return $this;
    }

    /**
     * Execute the command and return the result.
     *
     * @param string $repositoryUrl The url of the repository.
     *
     * @return mixed
     */
    public function execute($repositoryUrl)
    {
        $this->arguments[] = $repositoryUrl;
        $this->arguments[] = $this->repository->getRepositoryPath();
        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @copyright  2014 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Command builder interface.
 */
interface CommandBuilderInterface
{
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

use Bit3\GitPhp\GitException;
use Bit3\GitPhp\GitRepository;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Process;

/**
 * Abstract command builder.
 *
 * @SuppressWarnings(PHPMD.NumberOfChildren)
 */
trait CommandBuilderTrait
{
    /**
     * The path to the git repository.
     *
     * @var GitRepository
     */
    public $repository;

    /**
     * The directory in their the process called.
     *
     * @var string
     */
    protected $workingDirectory;

    /**
     * The arguments for the command line process.
     *
     * @var array
     */
    protected $arguments = [];

    /**
     * The process output.
     *
     * @var null|string
     */
    protected $output;

    /**
     * Flag if we want to dry run.
     *
     * @var bool
     */
    protected $dryRun = false;

    /** @var array<string, string> */
    protected $environment = [];

    /**
     * Constructor.
     *
     * @param GitRepository $repository The git repository to work on.
     */
    public function __construct(GitRepository $repository)
    {
        $this->repository       = $repository;
        $this->workingDirectory = $repository->getRepositoryPath();
        $config                 = $repository->getConfig();
        $this->arguments[]      = $config->getGitExecutablePath();
        if ($value = $config->getCommitterName()) {
            $this->environment['GIT_COMMITTER_NAME'] = $value;
        }
        if ($value = $config->getCommitterEMail()) {
            $this->environment['GIT_COMMITTER_EMAIL'] = $value;
        }

        $this->initializeProcessBuilder();
    }

    /**
     * Enable dry run. If dry run is enabled, the execute() method return the executed command.
     *
     * @return self
     */
    public function enableDryRun()
    {
        $this->dryRun = true;
        return $this;
    }

    /**
     * Initialize the process builder.
     *
     * @return void
     */
    abstract protected function initializeProcessBuilder();

    /**
     * Retrieve the output text.
     *
     * @return null|string
     */
    public function getOutput()
    {
        return $this->output;
    }

    /**
     * Build the the command line process.
     *
     * @return Process
     *
     * @throws LogicException In case no arguments have been provided.
     */
    protected function buildProcess()
    {
        if (!\count($this->arguments)) {
            throw new LogicException('You must add command arguments before the process can build.');
        }

        $process = new Process(
            $this->arguments,
            $this->workingDirectory,
            $this->environment
        );

        return $process;
    }

    /**
     * Execute the command.
     *
     * @return mixed Depend on the command.
     *
     * @throws GitException When the command is executed the second time or could not be executed.
     */
    protected function run()
    {
        $process = $this->buildProcess();

        if ($this->output !== null) {
            throw new GitException(
                'Command cannot be executed twice',
                $process->getWorkingDirectory() ?? '?',
                $process->getCommandLine(),
                $this->output,
                ''
            );
        }

        $this->repository->getConfig()->getLogger()->debug(
            \sprintf('[ccabs-repository-git] exec [%s] %s', $this->workingDirectory, $process->getCommandLine())
        );

        if ($this->dryRun) {
            return $process->getCommandLine();
        }

        $process->run();
        $this->output = $process->getOutput();
        $this->output = \rtrim($this->output, "\r\n");

        if (!$process->isSuccessful()) {
            throw GitException::createFromProcess('Could not execute git command', $process);
        }

        return $this->output;
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Commit command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 * @SuppressWarnings(PHPMD.TooManyMethods)
 */
class CommitCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const CLEANUP_STRIP = 'strip';

    public const CLEANUP_WHITESPACE = 'whitespace';

    public const CLEANUP_VERBATIM = 'verbatim';

    public const CLEANUP_DEFAULT = 'default';

    public const UNTRACKED_FILES_NO = 'no';

    public const UNTRACKED_FILES_NORMAL = 'normal';

    public const UNTRACKED_FILES_ALL = 'all';

    /**
     * Flag determining if gpg signing is desired.
     *
     * @var bool
     */
    protected $gpgSignIsset = false;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'commit';
    }

    /**
     * Add the  option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the patch option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function patch()
    {
        $this->arguments[] = '--patch';
        return $this;
    }

    /**
     * Add the reuse-message option to the command line.
     *
     * @param string $commit The commit from which the message should be reused.
     *
     * @return CommitCommandBuilder
     */
    public function reuseMessage($commit)
    {
        $this->arguments[] = '--reuse-message=' . $commit;
        return $this;
    }

    /**
     * Add the fixup option to the command line.
     *
     * @param string $commit The commit to fixup.
     *
     * @return CommitCommandBuilder
     */
    public function fixup($commit)
    {
        $this->arguments[] = '--fixup=' . $commit;
        return $this;
    }

    /**
     * Add the squash option to the command line.
     *
     * @param string $commit The commit to squash.
     *
     * @return CommitCommandBuilder
     */
    public function squash($commit)
    {
        $this->arguments[] = '--squash=' . $commit;
        return $this;
    }

    /**
     * Add the reset-author option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function resetAuthor()
    {
        $this->arguments[] = '--reset-author';
        return $this;
    }

    /**
     * Add the short option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function short()
    {
        $this->arguments[] = '--short';
        return $this;
    }

    /**
     * Add the branch option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function branch()
    {
        $this->arguments[] = '--branch';
        return $this;
    }

    /**
     * Add the porcelain option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function porcelain()
    {
        $this->arguments[] = '--porcelain';
        return $this;
    }

    /**
     * Add the long option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function long()
    {
        $this->arguments[] = '--long';
        return $this;
    }

    /**
     * Add the null option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function null()
    {
        $this->arguments[] = '--null';
        return $this;
    }

    /**
     * Add the file option to the command line.
     *
     * @param string $file The file.
     *
     * @return CommitCommandBuilder
     */
    public function file($file)
    {
        $this->arguments[] = '--file=' . $file;
        return $this;
    }

    /**
     * Add the author option to the command line.
     *
     * @param string $author The author to use.
     *
     * @return CommitCommandBuilder
     */
    public function author($author)
    {
        $this->arguments[] = '--author=' . $author;
        return $this;
    }

    /**
     * Add the date option to the command line.
     *
     * @param \DateTime|string $date The timestamp to use for the commit (if string: Y-m-d H:i:s).
     *
     * @return CommitCommandBuilder
     */
    public function date($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--date=' . $date;
        return $this;
    }

    /**
     * Add the message option to the command line.
     *
     * @param string $message The message to use.
     *
     * @return CommitCommandBuilder
     */
    public function message($message)
    {
        $this->arguments[] = '--message=' . $message;
        return $this;
    }

    /**
     * Add the template option to the command line.
     *
     * @param string $file The template file.
     *
     * @return CommitCommandBuilder
     */
    public function template($file)
    {
        $this->arguments[] = '--template=' . $file;
        return $this;
    }

    /**
     * Add the signoff option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function signoff()
    {
        $this->arguments[] = '--signoff';
        return $this;
    }

    /**
     * Add the no-verify option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function noVerity()
    {
        $this->arguments[] = '--no-verify';
        return $this;
    }

    /**
     * Add the allow-empty option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function allowEmpty()
    {
        $this->arguments[] = '--allow-empty';
        return $this;
    }

    /**
     * Add the allow-empty-message option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function allowEmptyMessage()
    {
        $this->arguments[] = '--allow-empty-message';
        return $this;
    }

    /**
     * Add the cleanup option to the command line.
     *
     * @param string $mode The cleanup mode.
     *
     * @return CommitCommandBuilder
     */
    public function cleanup($mode)
    {
        $this->arguments[] = '--cleanup=' . $mode;
        return $this;
    }

    /**
     * Add the amend option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function amend()
    {
        $this->arguments[] = '--amend';
        return $this;
    }

    /**
     * Add the no-post-rewrite option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function noPostRewrite()
    {
        $this->arguments[] = '--no-post-rewrite';
        return $this;
    }

    /**
     * Add the include option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function includ()
    {
        $this->arguments[] = '--include';
        return $this;
    }

    /**
     * Add the only option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function only()
    {
        $this->arguments[] = '--only';
        return $this;
    }

    /**
     * Add the untracked-files option to the command line.
     *
     * @param null|string $mode How to handle untracked files.
     *
     * @return CommitCommandBuilder
     */
    public function untrackedFiles($mode = null)
    {
        $this->arguments[] = '--untracked-files' . ($mode ? '=' . $mode : '');
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the dry-run option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function dryRun()
    {
        $this->arguments[] = '--dry-run';
        return $this;
    }

    /**
     * Add the status option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function status()
    {
        $this->arguments[] = '--status';
        return $this;
    }

    /**
     * Add the no-status option to the command line.
     *
     * @return CommitCommandBuilder
     */
    public function noStatus()
    {
        $this->arguments[] = '--no-status';
        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @param null|string $keyId Optional id of the GPG key to use.
     *
     * @return CommitCommandBuilder
     */
    public function gpgSign($keyId = null)
    {
        $this->gpgSignIsset = true;
        $this->arguments[]  = '--gpg-sign' . ($keyId ? '=' . $keyId : '');
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null        $pathspec Path to commit.
     *
     * @param null|string $_        More optional pathes to commit.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathspec = null, $_ = null)
    {
        // prevent launching the editor
        $this->arguments[] = '--no-edit';

        if (!$this->gpgSignIsset && $this->repository->getConfig()->isSignCommitsEnabled()) {
            $this->gpgSign($this->repository->getConfig()->getSignCommitUser());
        }

        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathspec) {
                $this->arguments[] = $pathspec;
            }
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Matthew Gamble <git@matthewgamble.net>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Config command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class ConfigCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'config';
    }

    /**
     * Specify a single config file that should be looked at.
     * Has special support for the global, system and local flags.
     *
     * @param string $file The config file to use.
     *
     * @return ConfigCommandBuilder
     */
    public function file($file)
    {
        if (\in_array($file, ['global', 'system', 'local'])) {
            $this->arguments[] = '--' . $file;
        } else {
            $this->arguments[] = '--file';
            $this->arguments[] = $file;
        }
        return $this;
    }

    /**
     * Add the blob option to the command line.
     *
     * See "SPECIFYING REVISIONS" section in gitrevisions(7) for a list of ways to spell blob names.
     *
     * @param string $blobId The blob id to use.
     *
     * @return ConfigCommandBuilder
     */
    public function blob($blobId)
    {
        $this->arguments[] = '--blob ' . $blobId;
        return $this;
    }

    /**
     * Add a type option to the command line.
     *
     * @param string $type The type name.
     *
     * @return ConfigCommandBuilder
     *
     * @throws \InvalidArgumentException When an invalid type name is encountered.
     */
    public function type($type)
    {
        if (\in_array($type, ['bool', 'int', 'bool-or-int', 'path'])) {
            $this->arguments[] = '--' . $type;
        } else {
            throw new \InvalidArgumentException('Invalid configuration type supplied.');
        }
        return $this;
    }

    /**
     * Add the add option and associated parameters to the command line.
     *
     * @param string $name  The config value name.
     *
     * @param string $value The value to use.
     *
     * @return ConfigCommandBuilder
     */
    public function add($name, $value)
    {
        $this->arguments[] = '--add';
        $this->arguments[] = $name;
        $this->arguments[] = $value;
        return $this;
    }

    /**
     * Add the replace-all option and associated parameters to the command line.
     *
     * @param string      $name       The config value name.
     *
     * @param string      $value      The value to use.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function replaceAll($name, $value, $valueRegex = null)
    {
        $this->arguments[] = '--replace-all';
        $this->arguments[] = $name;
        $this->arguments[] = $value;
        if ($valueRegex !== null) {
            $this->arguments[] = $valueRegex;
        }
        return $this;
    }

    /**
     * Adds the NUL byte termination option to the command line.
     *
     * @return ConfigCommandBuilder
     */
    public function terminateWithNUL()
    {
        $this->arguments[] = '--null';
        return $this;
    }

    /**
     * Add the get option and associated parameters to the command line.
     *
     * @param string      $name       The config value name.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function get($name, $valueRegex = null)
    {
        $this->arguments[] = '--get';
        $this->addNameAndPattern($name, $valueRegex);
        return $this;
    }

    /**
     * Add the get-all option and associated parameters to the command line.
     *
     * @param string      $name       The config value name.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function getAll($name, $valueRegex = null)
    {
        $this->arguments[] = '--get-all';
        $this->addNameAndPattern($name, $valueRegex);
        return $this;
    }

    /**
     * Add the get-regexp option and associated parameters to the command line.
     *
     * @param string      $nameRegex  The config name regex.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function getRegexp($nameRegex, $valueRegex = null)
    {
        $this->arguments[] = '--get-regexp';
        $this->addNameAndPattern($nameRegex, $valueRegex);
        return $this;
    }

    /**
     * Add the get-urlmatch option and associated parameters to the command line.
     *
     * @param string $name The config name.
     *
     * @param string $url  The url to match.
     *
     * @return ConfigCommandBuilder
     */
    public function getUrlmatch($name, $url)
    {
        $this->arguments[] = '--get-urlmatch';
        $this->addNameAndPattern($name, $url);
        return $this;
    }

    /**
     * Add the unset option and associated parameters to the command line.
     *
     * @param string      $name       The name of the config value to unset.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function unsetOpt($name, $valueRegex = null)
    {
        $this->arguments[] = '--unset';
        $this->addNameAndPattern($name, $valueRegex);
        return $this;
    }

    /**
     * Add the unset-all option and associated parameters to the command line.
     *
     * @param string      $name       The name of the config value to unset.
     *
     * @param null|string $valueRegex The value regex to use.
     *
     * @return ConfigCommandBuilder
     */
    public function unsetAll($name, $valueRegex = null)
    {
        $this->arguments[] = '--unset-all';
        $this->addNameAndPattern($name, $valueRegex);
        return $this;
    }

    /**
     * Add the passed name and the passed pattern if not null.
     *
     * @param string      $name    The name to add.
     *
     * @param null|string $pattern The pattern to add (if not null).
     *
     * @return void
     */
    private function addNameAndPattern($name, $pattern)
    {
        $this->arguments[] = $name;
        if ($pattern !== null) {
            $this->arguments[] = $pattern;
        }
    }

    /**
     * Add the rename-section option and associated parameters to the command line.
     *
     * @param string $oldName The old section name.
     *
     * @param string $newName The new section name.
     *
     * @return ConfigCommandBuilder
     */
    public function renameSection($oldName, $newName)
    {
        $this->arguments[] = '--rename-section';
        $this->arguments[] = $oldName;
        $this->arguments[] = $newName;
        return $this;
    }

    /**
     * Add the remove-section option to the command line.
     *
     * @param string $name The section name.
     *
     * @return ConfigCommandBuilder
     */
    public function removeSection($name)
    {
        $this->arguments[] = '--remove-section';
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the list option to the command line.
     *
     * @return ConfigCommandBuilder
     */
    public function listOpt()
    {
        $this->arguments[] = '--list';
        return $this;
    }

    /**
     * Add the get-color option and associated parameters to the command line.
     *
     * @param string      $name    The name of the color to retrieve.
     *
     * @param null|string $default The default value to return.
     *
     * @return ConfigCommandBuilder
     */
    public function getColor($name, $default = null)
    {
        $this->arguments[] = '--get-color';
        $this->arguments[] = $name;
        if ($default !== null) {
            $this->arguments[] = $default;
        }
        return $this;
    }

    /**
     * Add the get-colorbool option and associated parameters to the command line.
     *
     * @param string    $name        The name of the color to check.
     *
     * @param bool|null $stdoutIsTty Flag if stdout is a tty.
     *
     * @return ConfigCommandBuilder
     */
    public function getColorBool($name, $stdoutIsTty = null)
    {
        $this->arguments[] = '--get-colorbool';
        $this->arguments[] = $name;
        if (\is_bool($stdoutIsTty)) {
            $this->arguments[] = $stdoutIsTty ? 'true' : 'false';
        }
        return $this;
    }

    /**
     * Add the includes or no-includes option to the command line.
     *
     * @param bool $allow Flag if include.* directives in config files shall be respected when looking up values.
     *
     * @return ConfigCommandBuilder
     */
    public function includes($allow = true)
    {
        $this->arguments[] = $allow ? '--includes' : '--no-includes';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $name       Pass name of setting here to perform a basic get or set operation.
     *
     * @param null|string $value      Pass a value for the setting to turn this into a set command.
     *
     * @param null|string $valueRegex Pass a regex to limit changing of a multi-value setting to certain settings.
     *
     * @return mixed
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($name = null, $value = null, $valueRegex = null)
    {
        if ($name !== null) {
            $this->arguments[] = $name;
            if ($value !== null) {
                $this->arguments[] = $value;
                if ($valueRegex !== null) {
                    $this->arguments[] = $valueRegex;
                }
            }
        }
        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Describe command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class DescribeCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'describe';
    }

    /**
     * Add the dirty option to the command line.
     *
     * @param bool|string $mark The mark to use.
     *
     * @return DescribeCommandBuilder
     */
    public function dirty($mark = false)
    {
        $this->arguments[] = '--dirty';
        if ($mark) {
            $this->arguments[] = $mark;
        }
        return $this;
    }

    /**
     * Add the all option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function tags()
    {
        $this->arguments[] = '--tags';
        return $this;
    }

    /**
     * Add the contains option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function contains()
    {
        $this->arguments[] = '--contains';
        return $this;
    }

    /**
     * Add the abbrev option to the command line.
     *
     * @param int $n Chars after which to abbreviate.
     *
     * @return DescribeCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     */
    public function abbrev($n)
    {
        $this->arguments[] = '--abbrev=' . $n;
        return $this;
    }

    /**
     * Add the candidates option to the command line.
     *
     * @param int $n Amount of candidates.
     *
     * @return DescribeCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     */
    public function candidates($n)
    {
        $this->arguments[] = '--candidates=' . $n;
        return $this;
    }

    /**
     * Add the exact-match option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function exactMatch()
    {
        $this->arguments[] = '--exact-match';
        return $this;
    }

    /**
     * Add the debug option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function debug()
    {
        $this->arguments[] = '--debug';
        return $this;
    }

    /**
     * Add the long option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function long()
    {
        $this->arguments[] = '--long';
        return $this;
    }

    /**
     * Add the match option to the command line.
     *
     * @param string $pattern The pattern to use for filtering.
     *
     * @return DescribeCommandBuilder
     */
    public function match($pattern)
    {
        $this->arguments[] = '--match';
        $this->arguments[] = $pattern;
        return $this;
    }

    /**
     * Add the always option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function always()
    {
        $this->arguments[] = '--always';
        return $this;
    }

    /**
     * Add the first-parent option to the command line.
     *
     * @return DescribeCommandBuilder
     */
    public function firstParent()
    {
        $this->arguments[] = '--first-parent';
        return $this;
    }

    /**
     * Execute the command and return the result.
     *
     * @param string $commit The commit to describe (defaults to HEAD).
     *
     * @return string
     */
    public function execute($commit = 'HEAD')
    {
        $this->arguments[] = $commit;
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Fetch command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class FetchCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const RECURSE_SUBMODULES_YES = 'yes';

    public const RECURSE_SUBMODULES_ON_DEMAND = 'on-demand';

    public const RECURSE_SUBMODULES_NO = 'no';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'fetch';
    }

    /**
     * Add the all option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the append option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function append()
    {
        $this->arguments[] = '--append';
        return $this;
    }

    /**
     * Add the depth option to the command line.
     *
     * @param int $depth The commit depth to use.
     *
     * @return FetchCommandBuilder
     */
    public function depth($depth)
    {
        $this->arguments[] = '--depth=' . $depth;
        return $this;
    }

    /**
     * Add the unshallow option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function unshallow()
    {
        $this->arguments[] = '--unshallow';
        return $this;
    }

    /**
     * Add the update-shallow option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function updateShallow()
    {
        $this->arguments[] = '--update-shallow';
        return $this;
    }

    /**
     * Add the dry-run option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function dryRun()
    {
        $this->arguments[] = '--dry-run';
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the keep option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function keep()
    {
        $this->arguments[] = '--keep';
        return $this;
    }

    /**
     * Add the multiple option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function multiple()
    {
        $this->arguments[] = '--multiple';
        return $this;
    }

    /**
     * Add the prune option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function prune()
    {
        $this->arguments[] = '--prune';
        return $this;
    }

    /**
     * Add the no-tags option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function noTags()
    {
        $this->arguments[] = '--no-tags';
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function tags()
    {
        $this->arguments[] = '--tags';
        return $this;
    }

    /**
     * Add the recurse-submodules option to the command line.
     *
     * @param bool|string $recurse The value.
     *
     * @return FetchCommandBuilder
     */
    public function recurseSubmodules($recurse = false)
    {
        $this->arguments[] = '--recurse-submodules' . ($recurse ? '=' . $recurse : '');
        return $this;
    }

    /**
     * Add the no-recurse-submodules option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function noRecurseSubmodules()
    {
        $this->arguments[] = '--no-recurse-submodules';
        return $this;
    }

    /**
     * Add the submodule-prefix option to the command line.
     *
     * @param string $path The path.
     *
     * @return FetchCommandBuilder
     */
    public function submodulePrefix($path)
    {
        $this->arguments[] = '--submodule-prefix=' . $path;
        return $this;
    }

    /**
     * Add the recurse-submodules-default option to the command line.
     *
     * @param string $recurse The value.
     *
     * @return FetchCommandBuilder
     */
    public function recurseSubmodulesDefault($recurse)
    {
        $this->arguments[] = '--recurse-submodules-default=' . $recurse;
        return $this;
    }

    /**
     * Add the update-head-ok option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function updateHeadOk()
    {
        $this->arguments[] = '--update-head-ok';
        return $this;
    }

    /**
     * Add the upload-pack option to the command line.
     *
     * @param string $uploadPack The pack.
     *
     * @return FetchCommandBuilder
     */
    public function uploadPack($uploadPack)
    {
        $this->arguments[] = '--upload-pack';
        $this->arguments[] = $uploadPack;
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return FetchCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param string      $repository Name of the remote to use (Defaults to origin).
     *
     * @param null|string $refspec    Refspec to fetch.
     *
     * @param null|string $_          More optional refspecs to commit.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($repository = 'origin', $refspec = null, $_ = null)
    {
        $this->arguments[] = $repository;

        /** @var list<string> $refspecs */
        $refspecs = \func_get_args();
        \array_shift($refspecs);
        foreach ($refspecs as $refspec) {
            $this->arguments[] = $refspec;
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Init command builder.
 */
class InitCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const SHARE_FALSE = 'false';

    public const SHARE_TRUE = 'true';

    public const SHARE_UMASK = 'umask';

    public const SHARE_GROUP = 'group';

    public const SHARE_ALL = 'all';

    public const SHARE_WORLD = 'world';

    public const SHARE_EVERYBODY = 'everybody';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'init';
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return InitCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the bare option to the command line.
     *
     * @return InitCommandBuilder
     */
    public function bare()
    {
        $this->arguments[] = '--bare';
        return $this;
    }

    /**
     * Add the template option to the command line.
     *
     * @param string $templateDirectory Path to the template directory.
     *
     * @return InitCommandBuilder
     */
    public function template($templateDirectory)
    {
        $this->arguments[] = '--template=' . $templateDirectory;
        return $this;
    }

    /**
     * Add the separate-git-dir option to the command line.
     *
     * @param string $gitDir Path to the .git dir.
     *
     * @return InitCommandBuilder
     */
    public function separateGitDir($gitDir)
    {
        $this->arguments[] = '--separate-git-dir=' . $gitDir;
        return $this;
    }

    /**
     * Add the shared option to the command line.
     *
     * @param string $share The share value.
     *
     * @return InitCommandBuilder
     */
    public function shared($share)
    {
        $this->arguments[] = '--shared=' . $share;
        return $this;
    }

    /**
     * Execute the command and return the output.
     *
     * @return string
     */
    public function execute()
    {
        $this->arguments[] = $this->repository->getRepositoryPath();
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Log command builder.
 *
 * @SuppressWarnings(PHPMD.ExcessiveClassLength)
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 * @SuppressWarnings(PHPMD.TooManyMethods)
 */
class LogCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const DECORATE_SHORT = 'short';

    public const DECORATE_FULL = 'full';

    public const DECORATE_NO = 'no';

    public const WALK_SORTED = 'sorted';

    public const WALK_UNSORTED = 'unsorted';

    public const DATE_RELATIVE = 'relative';

    public const DATE_LOCAL = 'local';

    public const DATE_DEFAULT = 'default';

    public const DATE_ISO = 'iso';

    public const DATE_RFC = 'rfc';

    public const DATE_SHORT = 'short';

    public const DATE_RAW = 'raw';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'log';
    }

    /**
     * Add the follow option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function follow()
    {
        $this->arguments[] = '--follow';
        return $this;
    }

    /**
     * Add the no-decorate option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noDecorate()
    {
        $this->arguments[] = '--no-decorate';
        return $this;
    }

    /**
     * Add the decorate option to the command line.
     *
     * @param string $decorate The decorator value to use.
     *
     * @return LogCommandBuilder
     */
    public function decorate($decorate)
    {
        $this->arguments[] = '--decorate' . ($decorate ? '=' . $decorate : '');
        return $this;
    }

    /**
     * Add the source option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function source()
    {
        $this->arguments[] = '--source';
        return $this;
    }

    /**
     * Add the use-mailmap option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function useMailmap()
    {
        $this->arguments[] = '--use-mailmap';
        return $this;
    }

    /**
     * Add the full-diff option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function fullDiff()
    {
        $this->arguments[] = '--full-diff';
        return $this;
    }

    /**
     * Add the log-size option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function logSize()
    {
        $this->arguments[] = '--log-size';
        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @param string $revisionRange The revision range.
     *
     * @return LogCommandBuilder
     */
    public function revisionRange($revisionRange)
    {
        $this->arguments[] = $revisionRange;
        return $this;
    }

    /**
     * Add the max-count option to the command line.
     *
     * @param int $number Amount of log entries.
     *
     * @return LogCommandBuilder
     */
    public function maxCount($number)
    {
        $this->arguments[] = '--max-count=' . $number;
        return $this;
    }

    /**
     * Add the skip option to the command line.
     *
     * @param int $number Amount of entries to skip.
     *
     * @return LogCommandBuilder
     */
    public function skip($number)
    {
        $this->arguments[] = '--skip=' . $number;
        return $this;
    }

    /**
     * Add the since option to the command line.
     *
     * @param \DateTime|string $date The date from which on the commits shall be listed.
     *
     * @return LogCommandBuilder
     */
    public function since($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--since=' . $date;
        return $this;
    }

    /**
     * Add the after option to the command line.
     *
     * @param \DateTime|string $date The date after which the commits shall be listed.
     *
     * @return LogCommandBuilder
     */
    public function after($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--after=' . $date;
        return $this;
    }

    /**
     * Add the until option to the command line.
     *
     * @param \DateTime|string $date The date until which the commits shall be listed.
     *
     * @return LogCommandBuilder
     */
    public function until($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--until=' . $date;
        return $this;
    }

    /**
     * Add the before option to the command line.
     *
     * @param \DateTime|string $date The date before which the commits shall be listed.
     *
     * @return LogCommandBuilder
     */
    public function before($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--before=' . $date;
        return $this;
    }

    /**
     * Add the author option to the command line.
     *
     * @param string $pattern The pattern the author has to match.
     *
     * @return LogCommandBuilder
     */
    public function author($pattern)
    {
        $this->arguments[] = '--author=' . $pattern;
        return $this;
    }

    /**
     * Add the grep-reflog option to the command line.
     *
     * @param string $pattern The pattern to grep the ref log with.
     *
     * @return LogCommandBuilder
     */
    public function grepReflog($pattern)
    {
        $this->arguments[] = '--grep-reflog=' . $pattern;
        return $this;
    }

    /**
     * Add the grep option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return LogCommandBuilder
     */
    public function grep($pattern)
    {
        $this->arguments[] = '--grep=' . $pattern;
        return $this;
    }

    /**
     * Add the all-match option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function allMatch()
    {
        $this->arguments[] = '--all-match';
        return $this;
    }

    /**
     * Add the regexp-ignore-case option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function regexpIgnoreCase()
    {
        $this->arguments[] = '--regexp-ignore-case';
        return $this;
    }

    /**
     * Add the basicRegexp option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function basicRegexp()
    {
        $this->arguments[] = '--basicRegexp';
        return $this;
    }

    /**
     * Add the extended-regexp option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function extendedRegexp()
    {
        $this->arguments[] = '--extended-regexp';
        return $this;
    }

    /**
     * Add the fixed-strings option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function fixedStrings()
    {
        $this->arguments[] = '--fixed-strings';
        return $this;
    }

    /**
     * Add the perl-regexp option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function perlRegexp()
    {
        $this->arguments[] = '--perl-regexp';
        return $this;
    }

    /**
     * Add the remove-empty option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function removeEmpty()
    {
        $this->arguments[] = '--remove-empty';
        return $this;
    }

    /**
     * Add the merges option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function merges()
    {
        $this->arguments[] = '--merges';
        return $this;
    }

    /**
     * Add the no-merges option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noMerges()
    {
        $this->arguments[] = '--no-merges';
        return $this;
    }

    /**
     * Add the min-parents option to the command line.
     *
     * @param int $number The minimum amount of parents.
     *
     * @return LogCommandBuilder
     */
    public function minParents($number)
    {
        $this->arguments[] = '--min-parents=' . $number;
        return $this;
    }

    /**
     * Add the max-parents option to the command line.
     *
     * @param int $number The maximum amount of parents.
     *
     * @return LogCommandBuilder
     */
    public function maxParents($number)
    {
        $this->arguments[] = '--max-parents=' . $number;
        return $this;
    }

    /**
     * Add the no-min-parents option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noMinParents()
    {
        $this->arguments[] = '--no-min-parents';
        return $this;
    }

    /**
     * Add the no-max-parents option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noMaxParents()
    {
        $this->arguments[] = '--no-max-parents';
        return $this;
    }

    /**
     * Add the first-parent option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function firstParent()
    {
        $this->arguments[] = '--first-parent';
        return $this;
    }

    /**
     * Add the not option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function not()
    {
        $this->arguments[] = '--not';
        return $this;
    }

    /**
     * Add the all option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the branches option to the command line.
     *
     * @param null|string $pattern The pattern to filter branches with.
     *
     * @return LogCommandBuilder
     */
    public function branches($pattern = null)
    {
        $this->arguments[] = '--branches' . ($pattern ? '=' . $pattern : '');
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @param null|string $pattern The pattern to filter the tags with.
     *
     * @return LogCommandBuilder
     */
    public function tags($pattern = null)
    {
        $this->arguments[] = '--tags' . ($pattern ? '=' . $pattern : '');
        return $this;
    }

    /**
     * Add the remotes option to the command line.
     *
     * @param null|string $pattern The pattern to filter the remotes with.
     *
     * @return LogCommandBuilder
     */
    public function remotes($pattern = null)
    {
        $this->arguments[] = '--remotes' . ($pattern ? '=' . $pattern : '');
        return $this;
    }

    /**
     * Add the glob option to the command line.
     *
     * @param string $pattern The glob pattern.
     *
     * @return LogCommandBuilder
     */
    public function glob($pattern)
    {
        $this->arguments[] = '--glob=' . $pattern;
        return $this;
    }

    /**
     * Add the exclude option to the command line.
     *
     * @param string $pattern The pattern to exclude.
     *
     * @return LogCommandBuilder
     */
    public function exclude($pattern)
    {
        $this->arguments[] = '--exclude=' . $pattern;
        return $this;
    }

    /**
     * Add the ignore-missing option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function ignoreMissing()
    {
        $this->arguments[] = '--ignore-missing';
        return $this;
    }

    /**
     * Add the bisect option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function bisect()
    {
        $this->arguments[] = '--bisect';
        return $this;
    }

    /**
     * Add the cherry-mark option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function cherryMark()
    {
        $this->arguments[] = '--cherry-mark';
        return $this;
    }

    /**
     * Add the cherry-pick option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function cherryPick()
    {
        $this->arguments[] = '--cherry-pick';
        return $this;
    }

    /**
     * Add the left-only option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function leftOnly()
    {
        $this->arguments[] = '--left-only';
        return $this;
    }

    /**
     * Add the right-only option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function rightOnly()
    {
        $this->arguments[] = '--right-only';
        return $this;
    }

    /**
     * Add the cherry option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function cherry()
    {
        $this->arguments[] = '--cherry';
        return $this;
    }

    /**
     * Add the walk-reflogs option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function walkReflogs()
    {
        $this->arguments[] = '--walk-reflogs';
        return $this;
    }

    /**
     * Add the merge option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function merge()
    {
        $this->arguments[] = '--merge';
        return $this;
    }

    /**
     * Add the boundary option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function boundary()
    {
        $this->arguments[] = '--boundary';
        return $this;
    }

    /**
     * Add the simplify-by-decoration option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function simplifyByDecoration()
    {
        $this->arguments[] = '--simplify-by-decoration';
        return $this;
    }

    /**
     * Add the full-history option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function fullHistory()
    {
        $this->arguments[] = '--full-history';
        return $this;
    }

    /**
     * Add the dense option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function dense()
    {
        $this->arguments[] = '--dense';
        return $this;
    }

    /**
     * Add the sparse option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function sparse()
    {
        $this->arguments[] = '--sparse';
        return $this;
    }

    /**
     * Add the simplify-merges option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function simplifyMerges()
    {
        $this->arguments[] = '--simplify-merges';
        return $this;
    }

    /**
     * Add the ancestry-path option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function ancestryPath()
    {
        $this->arguments[] = '--ancestry-path';
        return $this;
    }

    /**
     * Add the date-order option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function dateOrder()
    {
        $this->arguments[] = '--date-order';
        return $this;
    }

    /**
     * Add the author-date-order option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function authorDateOrder()
    {
        $this->arguments[] = '--author-date-order';
        return $this;
    }

    /**
     * Add the topo-order option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function topoOrder()
    {
        $this->arguments[] = '--topo-order';
        return $this;
    }

    /**
     * Add the reverse option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function reverse()
    {
        $this->arguments[] = '--reverse';
        return $this;
    }

    /**
     * Add the objects option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function objects()
    {
        $this->arguments[] = '--objects';
        return $this;
    }

    /**
     * Add the objects-edge option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function objectsEdge()
    {
        $this->arguments[] = '--objects-edge';
        return $this;
    }

    /**
     * Add the unpacked option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function unpacked()
    {
        $this->arguments[] = '--unpacked';
        return $this;
    }

    /**
     * Add the no-walk option to the command line.
     *
     * @param null|string $walk The value.
     *
     * @return LogCommandBuilder
     */
    public function noWalk($walk = null)
    {
        $this->arguments[] = '--no-walk' . ($walk ? '=' . $walk : '');
        return $this;
    }

    /**
     * Add the do-walk option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function doWalk()
    {
        $this->arguments[] = '--do-walk';
        return $this;
    }

    /**
     * Add the pretty option to the command line.
     *
     * @param null|string $format The format.
     *
     * @return LogCommandBuilder
     */
    public function pretty($format = null)
    {
        $this->arguments[] = '--pretty' . ($format ? '=' . $format : '');
        return $this;
    }

    /**
     * Add the format option to the command line.
     *
     * @param string $format The format.
     *
     * @return LogCommandBuilder
     */
    public function format($format)
    {
        $this->arguments[] = '--format=' . $format;
        return $this;
    }

    /**
     * Add the abbrev-commit option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function abbrevCommit()
    {
        $this->arguments[] = '--abbrev-commit';
        return $this;
    }

    /**
     * Add the no-abbrev-commit option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noAbbrevCommit()
    {
        $this->arguments[] = '--no-abbrev-commit';
        return $this;
    }

    /**
     * Add the oneline option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function oneline()
    {
        $this->arguments[] = '--oneline';
        return $this;
    }

    /**
     * Add the encoding option to the command line.
     *
     * @param string $encoding The encoding.
     *
     * @return LogCommandBuilder
     */
    public function encoding($encoding)
    {
        $this->arguments[] = '--encoding=' . $encoding;
        return $this;
    }

    /**
     * Add the notes option to the command line.
     *
     * @param null|string $ref The ref name.
     *
     * @return LogCommandBuilder
     */
    public function notes($ref = null)
    {
        $this->arguments[] = '--notes' . ($ref ? '=' . $ref : '');
        return $this;
    }

    /**
     * Add the no-notes option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function noNotes()
    {
        $this->arguments[] = '--no-notes';
        return $this;
    }

    /**
     * Add the show-notes option to the command line.
     *
     * @param null|string $ref The name of the ref.
     *
     * @return LogCommandBuilder
     */
    public function showNotes($ref = null)
    {
        $this->arguments[] = '--show-notes' . ($ref ? '=' . $ref : '');
        return $this;
    }

    /**
     * Add the show-signature option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function showSignature()
    {
        $this->arguments[] = '--show-signature';
        return $this;
    }

    /**
     * Add the relative-date option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function relativeDate()
    {
        $this->arguments[] = '--relative-date';
        return $this;
    }

    /**
     * Add the date option to the command line.
     *
     * @param string $format The date format.
     *
     * @return LogCommandBuilder
     */
    public function date($format)
    {
        $this->arguments[] = '--date=' . $format;
        return $this;
    }

    /**
     * Add the parents option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function parents()
    {
        $this->arguments[] = '--parents';
        return $this;
    }

    /**
     * Add the children option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function children()
    {
        $this->arguments[] = '--children';
        return $this;
    }

    /**
     * Add the left-right option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function leftRight()
    {
        $this->arguments[] = '--left-right';
        return $this;
    }

    /**
     * Add the graph option to the command line.
     *
     * @return LogCommandBuilder
     */
    public function graph()
    {
        $this->arguments[] = '--graph';
        return $this;
    }

    /**
     * Add the c option to the command line.
     *
     * @return LogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function c()
    {
        $this->arguments[] = '-c';
        return $this;
    }

    /**
     * Add the cc option to the command line.
     *
     * @return LogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function cc()
    {
        $this->arguments[] = '--cc';
        return $this;
    }

    /**
     * Add the m option to the command line.
     *
     * @return LogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function m()
    {
        $this->arguments[] = '-m';
        return $this;
    }

    /**
     * Add the r option to the command line.
     *
     * @return LogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function r()
    {
        $this->arguments[] = '-r';
        return $this;
    }

    /**
     * Add the t option to the command line.
     *
     * @return LogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function t()
    {
        $this->arguments[] = '-t';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $pathspec Path spec to log.
     *
     * @param null|string $_        More optional pathspecs to log.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathspec = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathspec) {
                $this->arguments[] = $pathspec;
            }
        }
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Ls remote command builder.
 */
class LsRemoteCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'ls-remote';
    }

    /**
     * Add the heads option to the command line.
     *
     * @return LsRemoteCommandBuilder
     */
    public function heads()
    {
        $this->arguments[] = '--heads';
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @return LsRemoteCommandBuilder
     */
    public function tags()
    {
        $this->arguments[] = '--tags';
        return $this;
    }

    /**
     * Add the upload-pack option to the command line.
     *
     * @param string $exec The value.
     *
     * @return LsRemoteCommandBuilder
     */
    public function uploadPack($exec)
    {
        $this->arguments[] = '--upload-pack';
        $this->arguments[] = $exec;
        return $this;
    }

    /**
     * Add the exit-code option to the command line.
     *
     * @return LsRemoteCommandBuilder
     */
    public function exitCode()
    {
        $this->arguments[] = '--exit-code';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param string      $remote  Name of the remote.
     *
     * @param null|string $refSpec Ref spec to list.
     *
     * @param null|string $_       More optional ref specs to log.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($remote, $refSpec = null, $_ = null)
    {
        $this->arguments[] = $remote;

        /** @var list<string> $refSpec */
        $refSpec = \func_get_args();
        \array_shift($refSpec);
        foreach ($refSpec as $ref) {
            $this->arguments[] = $ref;
        }

        return (string) $this->run();
    }

    /**
     * Return a list of remote names.
     *
     * @param string      $remote  Name of the remote.
     *
     * @param null|string $refSpec Ref spec to list.
     *
     * @param null|string $_       More optional ref specs to log.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function getRefs($remote, $refSpec = null, $_ = null)
    {
        $output = (string) \call_user_func_array([$this, 'execute'], \func_get_args());
        $output = \explode("\n", $output);
        $output = \array_map('trim', $output);
        $output = \array_filter($output);

        $refs = [];

        foreach ($output as $line) {
            $line = \preg_split('~\s+~', $line);

            if ('^{}' != \substr($line[1], -3)) {
                $refs[$line[1]] = $line[0];
            }
        }

        return $refs;
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Aaron Rubin <aaron@arkitech.net>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Merge command builder.
 */
class MergeCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'merge';
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return MergeCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the strategy option to the command line with the given strategy.
     *
     * @param string $strategy Strategy to use when merging.
     *
     * @return MergeCommandBuilder
     */
    public function strategy($strategy)
    {
        $this->arguments[] = '--strategy=' . $strategy;
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $branchOrTreeIsh Name of the branch or tree.
     *
     * @param null        $path            Path to which check out.
     *
     * @param null|string $_               More optional arguments to append to the command.
     *
     * @return mixed
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($branchOrTreeIsh = null, $path = null, $_ = null)
    {
        /** @var list<string> $paths */
        $paths = \func_get_args();
        if ($branchOrTreeIsh) {
            \array_shift($paths);
            $this->arguments[] = $branchOrTreeIsh;
        }

        if (\count($paths)) {
            $this->arguments[] = '--';
            foreach ($paths as $path) {
                $this->arguments[] = $path;
            }
        }

        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Ahmad Marzouq <ahmad.marzouq@eagles-web.com>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @author     Idris Dose <idrisdev@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Pull command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class PullCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'pull';
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return PullCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return PullCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the recurse-submodules option to the command line.
     *
     * @param string $recurse The value.
     *
     * @return PullCommandBuilder
     */
    public function recurseSubmodules($recurse)
    {
        $this->arguments[] = '--recurse-submodules=' . $recurse;
        return $this;
    }


    /**
     * Build the command and execute it.
     *
     * @param string      $repository Name of the remote to pull from.
     *
     * @param null|string $refspec    Ref spec to pull.
     *
     * @param null|string $_          More optional ref specs to pull.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($repository = 'origin', $refspec = null, $_ = null)
    {
        $this->arguments[] = $repository;

        /** @var list<string> $refspecs */
        $refspecs = \func_get_args();
        \array_shift($refspecs);
        foreach ($refspecs as $refspec) {
            $this->arguments[] = $refspec;
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Push command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class PushCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const RECURSE_SUBMODULES_CHECK = 'check';

    public const RECURSE_SUBMODULES_ON_DEMAND = 'on-demand';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'push';
    }

    /**
     * Add the all option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the prune option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function prune()
    {
        $this->arguments[] = '--prune';
        return $this;
    }

    /**
     * Add the mirror option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function mirror()
    {
        $this->arguments[] = '--mirror';
        return $this;
    }

    /**
     * Add the dry-run option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function dryRun()
    {
        $this->arguments[] = '--dry-run';
        return $this;
    }

    /**
     * Add the porcelain option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function porcelain()
    {
        $this->arguments[] = '--porcelain';
        return $this;
    }

    /**
     * Add the delete option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function delete()
    {
        $this->arguments[] = '--delete';
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function tags()
    {
        $this->arguments[] = '--tags';
        return $this;
    }

    /**
     * Add the follow-tags option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function followTags()
    {
        $this->arguments[] = '--follow-tags';
        return $this;
    }

    /**
     * Add the receive-pack option to the command line.
     *
     * @param string $gitReceivePack The value.
     *
     * @return PushCommandBuilder
     */
    public function receivePack($gitReceivePack)
    {
        $this->arguments[] = '--receive-pack=' . $gitReceivePack;
        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @param null|string $refname The ref name.
     * @param null|string $expect  The expect value.
     *
     * @return PushCommandBuilder
     */
    public function forceWithLease($refname, $expect = null)
    {
        $this->arguments[] = '--force-with-lease' . ($refname ? ('=' . $refname . ($expect ? ':' . $expect : '')) : '');
        return $this;
    }

    /**
     * Add the no-force-with-lease option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function noForceWithLease()
    {
        $this->arguments[] = '--no-force-with-lease';
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the repo option to the command line.
     *
     * @param string $repository The repository name.
     *
     * @return PushCommandBuilder
     */
    public function repo($repository)
    {
        $this->arguments[] = '--repo=' . $repository;
        return $this;
    }

    /**
     * Add the set-upstream option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function setUpstream()
    {
        $this->arguments[] = '--set-upstream';
        return $this;
    }

    /**
     * Add the thin option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function thin()
    {
        $this->arguments[] = '--thin';
        return $this;
    }

    /**
     * Add the no-thin option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function noThin()
    {
        $this->arguments[] = '--no-thin';
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the verbose option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the recurse-submodules option to the command line.
     *
     * @param string $recurse The value.
     *
     * @return PushCommandBuilder
     */
    public function recurseSubmodules($recurse)
    {
        $this->arguments[] = '--recurse-submodules=' . $recurse;
        return $this;
    }

    /**
     * Add the verify option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function verify()
    {
        $this->arguments[] = '--verify';
        return $this;
    }

    /**
     * Add the no-verify option to the command line.
     *
     * @return PushCommandBuilder
     */
    public function noVerify()
    {
        $this->arguments[] = '--no-verify';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param string      $repository Name of the remote to push to.
     *
     * @param null|string $refspec    Ref spec to push.
     *
     * @param null|string $_          More optional ref specs to push.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($repository, $refspec = null, $_ = null)
    {
        $this->arguments[] = $repository;

        /** @var list<string> $refspecs */
        $refspecs = \func_get_args();
        \array_shift($refspecs);
        foreach ($refspecs as $refspec) {
            $this->arguments[] = $refspec;
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Remote command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class RemoteCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'remote';
    }

    /**
     * Add the  option to the command line.
     *
     * @return RemoteCommandBuilder
     */
    public function verbose()
    {
        $this->arguments[] = '--verbose';
        return $this;
    }

    /**
     * Add the add option to the command line.
     *
     * @param string $name Name of the new remote to add.
     *
     * @param string $url  URL to the new remote.
     *
     * @return RemoteCommandBuilder
     */
    public function add($name, $url)
    {
        $this->arguments[] = 'add';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        return $this;
    }

    /**
     * Add the rename option to the command line.
     *
     * @param string      $new The new name.
     *
     * @param null|string $old The old name.
     *
     * @return RemoteCommandBuilder
     */
    public function rename($new, $old = null)
    {
        $this->arguments[] = 'rename';
        if ($old) {
            $this->arguments[] = $old;
        }
        $this->arguments[] = $new;
        return $this;
    }

    /**
     * Add the remove option to the command line.
     *
     * @param string $name The name of the remote to remove.
     *
     * @return RemoteCommandBuilder
     */
    public function remove($name)
    {
        $this->arguments[] = 'remove';
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the set-head option to the command line.
     *
     * @param string $name   The name of the head.
     *
     * @param string $branch The name of the branch.
     *
     * @return RemoteCommandBuilder
     */
    public function setHead($name, $branch)
    {
        $this->arguments[] = 'set-head';
        $this->arguments[] = $name;
        $this->arguments[] = $branch;
        return $this;
    }

    /**
     * Add the set-head option to the command line.
     *
     * @param string $name The name of the head.
     *
     * @return RemoteCommandBuilder
     */
    public function setHeadAuto($name)
    {
        $this->arguments[] = 'set-head';
        $this->arguments[] = $name;
        $this->arguments[] = '--auto';
        return $this;
    }

    /**
     * Add the set-head option to the command line.
     *
     * @param string $name The name of the head.
     *
     * @return RemoteCommandBuilder
     */
    public function setHeadDelete($name)
    {
        $this->arguments[] = 'set-head';
        $this->arguments[] = $name;
        $this->arguments[] = '--delete';
        return $this;
    }

    /**
     * Add the set-branches option to the command line.
     *
     * @param string $name   Name of the remote.
     *
     * @param string $branch Name of the branch.
     *
     * @param bool   $add    Flag if the name should be added.
     *
     * @return RemoteCommandBuilder
     */
    public function setBranches($name, $branch, $add = false)
    {
        $this->arguments[] = 'set-branches';
        if ($add) {
            $this->arguments[] = '--add';
        }
        $this->arguments[] = $name;
        $this->arguments[] = $branch;
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string      $name   Name of the remote.
     *
     * @param string      $url    The URL.
     *
     * @param null|string $oldUrl The old URL.
     *
     * @return RemoteCommandBuilder
     */
    public function setUrl($name, $url, $oldUrl = null)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        if ($oldUrl) {
            $this->arguments[] = $oldUrl;
        }
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string      $name   Name of the remote.
     *
     * @param string      $url    The URL.
     *
     * @param null|string $oldUrl The old URL.
     *
     * @return RemoteCommandBuilder
     */
    public function setPushUrl($name, $url, $oldUrl = null)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = $name;
        $this->arguments[] = '--push';
        $this->arguments[] = $url;
        if ($oldUrl) {
            $this->arguments[] = $oldUrl;
        }
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string $name Name of the remote.
     *
     * @param string $url  The URL.
     *
     * @return RemoteCommandBuilder
     */
    public function addUrl($name, $url)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = '--add';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string $name Name of the remote.
     *
     * @param string $url  The URL.
     *
     * @return RemoteCommandBuilder
     */
    public function addPushUrl($name, $url)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = '--add';
        $this->arguments[] = '--push';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string $name Name of the remote.
     *
     * @param string $url  The URL.
     *
     * @return RemoteCommandBuilder
     */
    public function deleteUrl($name, $url)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = '--delete';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        return $this;
    }

    /**
     * Add the set-url option to the command line.
     *
     * @param string $name Name of the remote.
     *
     * @param string $url  The URL.
     *
     * @return RemoteCommandBuilder
     */
    public function deletePushUrl($name, $url)
    {
        $this->arguments[] = 'set-url';
        $this->arguments[] = '--delete';
        $this->arguments[] = '--push';
        $this->arguments[] = $name;
        $this->arguments[] = $url;
        return $this;
    }

    /**
     * Add the show option to the command line.
     *
     * @param string $name Name of the remote.
     *
     * @return RemoteCommandBuilder
     */
    public function show($name)
    {
        $this->arguments[] = 'show';
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the prune option to the command line.
     *
     * @param string $name   Name of the remote.
     *
     * @param bool   $dryRun Flag if a dry run shall be done.
     *
     * @return RemoteCommandBuilder
     */
    public function prune($name, $dryRun = false)
    {
        $this->arguments[] = 'prune';
        if ($dryRun) {
            $this->arguments[] = '--dry-run';
        }
        $this->arguments[] = $name;
        return $this;
    }

    /**
     * Add the update option to the command line.
     *
     * @param string $groupOrRemote Name of the remote or a remote group.
     *
     * @param bool   $prune         Flag if the remote shall be pruned.
     *
     * @return RemoteCommandBuilder
     */
    public function update($groupOrRemote, $prune = false)
    {
        $this->arguments[] = 'update';
        if ($prune) {
            $this->arguments[] = '--prune';
        }
        $this->arguments[] = $groupOrRemote;
        return $this;
    }

    /**
     * Execute the command and return the output.
     *
     * @return string
     */
    public function execute()
    {
        return (string) $this->run();
    }

    /**
     * Return a list of remote names.
     *
     * @return array
     */
    public function getNames()
    {
        $remotes = $this->execute();
        $remotes = \explode("\n", $remotes);
        $remotes = \array_map('trim', $remotes);
        $remotes = \array_filter($remotes);

        return $remotes;
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Reset command builder.
 */
class ResetCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'reset';
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the patch option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function patch()
    {
        $this->arguments[] = '--patch';
        return $this;
    }

    /**
     * Add the soft option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function soft()
    {
        $this->arguments[] = '--soft';
        return $this;
    }

    /**
     * Add the mixed option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function mixed()
    {
        $this->arguments[] = '--mixed';
        return $this;
    }

    /**
     * Add the hard option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function hard()
    {
        $this->arguments[] = '--hard';
        return $this;
    }

    /**
     * Add the merge option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function merge()
    {
        $this->arguments[] = '--merge';
        return $this;
    }

    /**
     * Add the keep option to the command line.
     *
     * @return ResetCommandBuilder
     */
    public function keep()
    {
        $this->arguments[] = '--keep';
        return $this;
    }

    /**
     * Add the commit to the command line.
     *
     * @param string $commit A commit hash.
     *
     * @return ResetCommandBuilder
     */
    public function commit($commit)
    {
        $this->arguments[] = $commit;
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $path Path to reset.
     *
     * @param null|string $_    More optional pathes to reset.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($path = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathSpec) {
                $this->arguments[] = $pathSpec;
            }
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Radek Crlik <nix0@centrum.cz>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Rev-parse command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 * @SuppressWarnings(PHPMD.TooManyMethods)
 */
class RevParseCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const ABBREV_REF_STRICT = 'strict';

    public const ABBREV_REF_LOOSE = 'loose';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'rev-parse';
    }

    /**
     * Add the parseopt option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function parseopt()
    {
        $this->arguments[] = '--parseopt';
        return $this;
    }

    /**
     * Add the keep-dashdash option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function keepDashDash()
    {
        $this->arguments[] = '--keep-dashdash';
        return $this;
    }

    /**
     * Add the stop-at-non-option option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function stopAtNonOption()
    {
        $this->arguments[] = '--stop-at-non-option';
        return $this;
    }

    /**
     * Add the stuck-long option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function stuckLong()
    {
        $this->arguments[] = '--stuck-long';
        return $this;
    }

    /**
     * Add the sq-quote option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function sqQuote()
    {
        $this->arguments[] = '--sq-quote';
        return $this;
    }

    /**
     * Add the revs-only option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function revsOnly()
    {
        $this->arguments[] = '--revs-only';
        return $this;
    }

    /**
     * Add the no-revs option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function noRevs()
    {
        $this->arguments[] = '--no-revs';
        return $this;
    }

    /**
     * Add the flags option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function flags()
    {
        $this->arguments[] = '--flags';
        return $this;
    }

    /**
     * Add the no-flags option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function noFlags()
    {
        $this->arguments[] = '--no-flags';
        return $this;
    }

    /**
     * Add the default option to the command line.
     *
     * @param string $arg Name of the default rev.
     *
     * @return RevParseCommandBuilder
     */
    public function defaultRev($arg)
    {
        $this->arguments[] = '--default';
        $this->arguments[] = $arg;
        return $this;
    }

    /**
     * Add the prefix option to the command line.
     *
     * @param string $arg The prefix.
     *
     * @return RevParseCommandBuilder
     */
    public function prefix($arg)
    {
        $this->arguments[] = '--prefix';
        $this->arguments[] = $arg;
        return $this;
    }

    /**
     * Add the verify option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function verify()
    {
        $this->arguments[] = '--verify';
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Add the sq option to the command line.
     *
     * @return RevParseCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function sq()
    {
        $this->arguments[] = '--sq';
        return $this;
    }

    /**
     * Add the not option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function not()
    {
        $this->arguments[] = '--not';
        return $this;
    }

    /**
     * Add the abbref-ref option to the command line.
     *
     * @param null|string $abbrev The value.
     *
     * @return RevParseCommandBuilder
     */
    public function abbrevRef($abbrev = null)
    {
        $this->arguments[] = '--abbrev-ref' . ($abbrev ? '=' . $abbrev : '');
        return $this;
    }

    /**
     * Add the short option to the command line.
     *
     * @param null|int $number The amount.
     *
     * @return RevParseCommandBuilder
     */
    public function short($number = null)
    {
        $this->arguments[] = '--short' . ($number ? '=' . $number : '');
        return $this;
    }

    /**
     * Add the symbolic option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function symbolic()
    {
        $this->arguments[] = '--symbolic';
        return $this;
    }

    /**
     * Add the symbolic-full-name option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function symbolicFullName()
    {
        $this->arguments[] = '--symbolic-full-name';
        return $this;
    }

    /**
     * Add the all option to the command line.
     *
     * @return RevParseCommandBuilder
     */
    public function all()
    {
        $this->arguments[] = '--all';
        return $this;
    }

    /**
     * Add the branches option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return RevParseCommandBuilder
     */
    public function branches($pattern)
    {
        $this->arguments[] = '--branches=' . $pattern;
        return $this;
    }

    /**
     * Add the tags option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return RevParseCommandBuilder
     */
    public function tags($pattern)
    {
        $this->arguments[] = '--tags=' . $pattern;
        return $this;
    }

    /**
     * Add the remotes option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return RevParseCommandBuilder
     */
    public function remotes($pattern)
    {
        $this->arguments[] = '--remotes=' . $pattern;
        return $this;
    }

    /**
     * Add the glob option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return RevParseCommandBuilder
     */
    public function glob($pattern)
    {
        $this->arguments[] = '--glob=' . $pattern;
        return $this;
    }

    /**
     * Add the exclude option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return RevParseCommandBuilder
     */
    public function exclude($pattern)
    {
        $this->arguments[] = '--exclude=' . $pattern;
        return $this;
    }

    /**
     * Add the disambiguate option to the command line.
     *
     * @param string $prefix The prefix.
     *
     * @return RevParseCommandBuilder
     */
    public function disambiguate($prefix)
    {
        $this->arguments[] = '--disambiguate=' . $prefix;
        return $this;
    }

    /**
     * Add the since option to the command line.
     *
     * @param \DateTime|string $date The date.
     *
     * @return RevParseCommandBuilder
     */
    public function since($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--since=' . $date;
        return $this;
    }

    /**
     * Add the after option to the command line.
     *
     * @param \DateTime|string $date The date.
     *
     * @return RevParseCommandBuilder
     */
    public function after($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--after=' . $date;
        return $this;
    }

    /**
     * Add the until option to the command line.
     *
     * @param \DateTime|string $date The date.
     *
     * @return RevParseCommandBuilder
     */
    public function until($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--until=' . $date;
        return $this;
    }

    /**
     * Add the before option to the command line.
     *
     * @param \DateTime|string $date The date.
     *
     * @return RevParseCommandBuilder
     */
    public function before($date)
    {
        if ($date instanceof \DateTime) {
            $date = $date->format('Y-m-d H:i:s');
        }
        $this->arguments[] = '--before=' . $date;
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $arg Optional additional argument.
     *
     * @param null|string $_   More optional arguments.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($arg = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        foreach ($args as $arg) {
            $this->arguments[] = $arg;
        }
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Rm command builder.
 */
class RmCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'rm';
    }

    /**
     * Add the force option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the dry-run option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function dryRun()
    {
        $this->arguments[] = '--dry-run';
        return $this;
    }

    /**
     * Add the recursive option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function recursive()
    {
        $this->arguments[] = '-r';
        return $this;
    }

    /**
     * Add the cached option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function cached()
    {
        $this->arguments[] = '--cached';
        return $this;
    }

    /**
     * Add the ignore-unmatch option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function ignoreUnmatch()
    {
        $this->arguments[] = '--ignore-unmatch';
        return $this;
    }

    /**
     * Add the quiet option to the command line.
     *
     * @return RmCommandBuilder
     */
    public function quiet()
    {
        $this->arguments[] = '--quiet';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $pathspec Path spec.
     *
     * @param null|string $_        More optional path specs.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathspec = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathspec) {
                $this->arguments[] = $pathspec;
            }
        }
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * ShortLog command builder.
 */
class ShortLogCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'shortlog';
    }

    /**
     * Add the  option to the command line.
     *
     * @return ShortLogCommandBuilder
     */
    public function numbered()
    {
        $this->arguments[] = '--numbered';

        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @return ShortLogCommandBuilder
     */
    public function summary()
    {
        $this->arguments[] = '--summary';

        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @return ShortLogCommandBuilder
     */
    public function email()
    {
        $this->arguments[] = '--email';

        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @param string $format The format.
     *
     * @return ShortLogCommandBuilder
     */
    public function format($format)
    {
        $this->arguments[] = '--format=' . $format;

        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @param string $revisionRange The revision range.
     *
     * @return ShortLogCommandBuilder
     */
    public function revisionRange($revisionRange)
    {
        $this->arguments[] = $revisionRange;

        return $this;
    }

    /**
     * Linewrap the output by wrapping each line at width.
     *
     * The first line of each entry is indented by indent1 spaces, and the second and subsequent lines are indented by
     * indent2 spaces.
     *
     * Width, indent1, and indent2 default to 76, 6 and 9 respectively.
     *
     * If width is 0 (zero) then indent the lines of the output without wrapping them.
     *
     * @param int      $width   The width or 0 to disable indenting.
     *
     * @param null|int $indent1 The amount of spaces the first line of each entry is indented by.
     *
     * @param null|int $indent2 The amount of spaces subsequent lines of each entry are indented by.
     *
     * @return ShortLogCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function w($width, $indent1 = null, $indent2 = null)
    {
        if ($indent1) {
            $width .= ',' . $indent1;

            if ($indent2) {
                $width .= ',' . $indent2;
            }
        }

        $this->arguments[] = '-w' . $width;

        return $this;
    }

    /**
     * Execute the command and return the result.
     *
     * @param null|string $pathSpec Optional path spec.
     *
     * @param null|string $_        Optional list of more path specs.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathSpec = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathSpec) {
                $this->arguments[] = $pathSpec;
            }
        }

        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Show command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class ShowCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'show';
    }

    /**
     * Add the  option to the command line.
     *
     * @param null|string $format The format.
     *
     * @return ShowCommandBuilder
     */
    public function pretty($format = null)
    {
        $this->arguments[] = '--pretty' . ($format ? '=' . $format : '');
        return $this;
    }

    /**
     * Add the format option to the command line.
     *
     * @param string $format The format.
     *
     * @return ShowCommandBuilder
     */
    public function format($format)
    {
        $this->arguments[] = '--format=' . $format;
        return $this;
    }

    /**
     * Add the abbrev-commit option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function abbrevCommit()
    {
        $this->arguments[] = '--abbrev-commit';
        return $this;
    }

    /**
     * Add the no-abbrev-commit option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function noAbbrevCommit()
    {
        $this->arguments[] = '--no-abbrev-commit';
        return $this;
    }

    /**
     * Add the oneline option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function oneline()
    {
        $this->arguments[] = '--oneline';
        return $this;
    }

    /**
     * Add the encoding option to the command line.
     *
     * @param string $encoding The encoding.
     *
     * @return ShowCommandBuilder
     */
    public function encoding($encoding)
    {
        $this->arguments[] = '--encoding=' . $encoding;
        return $this;
    }

    /**
     * Add the notes option to the command line.
     *
     * @param null|string $ref The ref name.
     *
     * @return ShowCommandBuilder
     */
    public function notes($ref = null)
    {
        $this->arguments[] = '--notes' . ($ref ? '=' . $ref : '');
        return $this;
    }

    /**
     * Add the no-notes option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function noNotes()
    {
        $this->arguments[] = '--no-notes';
        return $this;
    }

    /**
     * Add the show-notes option to the command line.
     *
     * @param null|string $ref The ref name.
     *
     * @return ShowCommandBuilder
     */
    public function showNotes($ref = null)
    {
        $this->arguments[] = '--show-notes' . ($ref ? '=' . $ref : '');
        return $this;
    }

    /**
     * Add the standard-notes option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function standardNotes()
    {
        $this->arguments[] = '--standard-notes';
        return $this;
    }

    /**
     * Add the no-standard-notes option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function noStandardNotes()
    {
        $this->arguments[] = '--no-standard-notes';
        return $this;
    }

    /**
     * Add the show-signature option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function showSignature()
    {
        $this->arguments[] = '--show-signature';
        return $this;
    }

    /**
     * Add the no-patch option to the command line.
     *
     * @return ShowCommandBuilder
     */
    public function noPatch()
    {
        $this->arguments[] = '--no-patch';
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param string $object Name of the object to show.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($object)
    {
        $this->arguments[] = $object;
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Ahmad Marzouq <ahmad.marzouq@eagles-web.com>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Stash command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class StashCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'stash';
    }

    /**
     * Adds a message to StashCommandBuilder
     *
     * @param string $message The stash message.
     *
     * @return StashCommandBuilder
     */
    public function message($message)
    {
        $this->arguments[] = $message;
        return $this;
    }

    /**
     * List stashes and return the results
     *
     * @param string $options Takes options applicable to the git log command.
     *
     * @return mixed
     */
    public function listStash($options = null)
    {
        $this->arguments[] = 'list';
        if ($options) {
            $this->arguments[] = $options;
        }
        return $this->run();
    }

    /**
     * Show the changes recorded in the stash as a diff
     * between the stashed state and its original parent.
     * When no $stash is given, shows the latest one.
     *
     * @param int|null $stash Takes the stash number.
     *
     * @return mixed
     */
    public function show($stash = null)
    {
        $this->arguments[] = 'show';
        if ($stash) {
            $this->arguments[] = 'stash@{' . $stash . '}';
        }
        return $this->run();
    }

    /**
     * Remove a single stashed state from the stash list.
     * When no $stash is given, it removes the latest one.
     *
     * @param int|null $stash Takes the stash number.
     *
     * @return mixed
     */
    public function drop($stash = null)
    {
        $this->arguments[] = 'show';
        if ($stash) {
            $this->arguments[] = 'stash@{' . $stash . '}';
        }
        return $this->run();
    }

    /**
     * Remove a single stashed state from the stash list
     * and apply it on top of the current working tree state.
     *
     * @param int|null $stash Takes the stash number.
     *
     * @return mixed
     */
    public function pop($stash = null)
    {
        $this->arguments[] = 'pop';
        if ($stash) {
            $this->arguments[] = 'stash@{' . $stash . '}';
        }
        return $this->run();
    }

    /**
     * Like pop, but do not remove the state from the stash list.
     * Unlike pop, $stash may be any commit that looks like a commit
     * created by stash save or stash create.
     *
     * @param int|null $stash Takes the stash number.
     *
     * @return mixed
     */
    public function apply($stash = null)
    {
        $this->arguments[] = 'pop';
        if ($stash) {
            $this->arguments[] = 'stash@{' . $stash . '}';
        }
        return $this->run();
    }


    /**
     * Creates and checks out a new branch named $branchname starting from the commit at
     * which the $stash was originally created,
     * applies the changes recorded in $stash to the new working tree and index.
     *
     * @param string   $branchname The branch name.
     *
     * @param int|null $stash      Takes the stash number.
     *
     * @return mixed
     */
    public function branch($branchname, $stash = null)
    {
        $this->arguments[] = 'branch';
        $this->arguments[] = $branchname;
        if ($stash) {
            $this->arguments[] = 'stash@{' . $stash . '}';
        }
        return $this->run();
    }


    /**
     * Remove all the stashed states.
     *
     * @return mixed
     */
    public function clear()
    {
        $this->arguments[] = 'clear';
        return $this->run();
    }


    /**
     * Save your local modifications to a new stash,
     * and run git reset --hard to revert them.
     * The <message> part is optional and gives
     * the description along with the stashed state.
     *
     * @param string $message The stash message.
     *
     * @return mixed
     */
    public function save($message = null)
    {
        $this->arguments[] = 'branch';
        if ($message) {
            $this->arguments[] = $message;
        }
        return $this->run();
    }

    /**
     * Create a stash (which is a regular commit object)
     * and return its object name,
     * without storing it anywhere in the ref namespace.
     *
     * @param string $message The stash message.
     *
     * @return mixed
     */
    public function create($message = null)
    {
        $this->arguments[] = 'create';
        if ($message) {
            $this->arguments[] = $message;
        }
        return $this->run();
    }

    /**
     * Store a given stash created via git stash create
     * (which is a dangling merge commit) in the stash ref,
     * updating the stash reflog.
     *
     * @param string      $message The stash message.
     *
     * @param null|string $commit  The commit hash.
     *
     * @return mixed
     */
    public function store($message = null, $commit = null)
    {
        $this->arguments[] = 'store';
        if ($message) {
            $this->arguments[] = '--message ' . $message;
        }
        if ($commit) {
            $this->arguments[] = $commit;
        }
        return $this->run();
    }
    /**
     * Execute the command and return the result.
     * to use with message function .
     *
     * @return mixed
     */
    public function execute()
    {
        return $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Status command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class StatusCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const UNTRACKED_FILES_NO = 'no';

    public const UNTRACKED_FILES_NORMAL = 'normal';

    public const UNTRACKED_FILES_ALL = 'all';

    public const IGNORE_SUBMODULES_NONE = 'none';

    public const IGNORE_SUBMODULES_UNTRACKED = 'untracked';

    public const IGNORE_SUBMODULES_DIRTY = 'dirty';

    public const IGNORE_SUBMODULES_ALL = 'all';

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'status';
    }

    /**
     * Add the short option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function short()
    {
        $this->arguments[] = '--short';
        return $this;
    }

    /**
     * Add the branch option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function branch()
    {
        $this->arguments[] = '--branch';
        return $this;
    }

    /**
     * Add the porcelain option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function porcelain()
    {
        $this->arguments[] = '--porcelain';
        return $this;
    }

    /**
     * Add the long option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function long()
    {
        $this->arguments[] = '--long';
        return $this;
    }

    /**
     * Add the untracked-files option to the command line.
     *
     * @param null|string $mode The mode.
     *
     * @return StatusCommandBuilder
     */
    public function untrackedFiles($mode = null)
    {
        $this->arguments[] = '--untracked-files' . ($mode ? '=' . $mode : '');
        return $this;
    }

    /**
     * Add the ignore-submodules option to the command line.
     *
     * @param null|string $when The value.
     *
     * @return StatusCommandBuilder
     */
    public function ignoreSubmodules($when = null)
    {
        $this->arguments[] = '--ignore-submodules' . ($when ? '=' . $when : '');
        return $this;
    }

    /**
     * Add the ignored option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function ignored()
    {
        $this->arguments[] = '--ignored';
        return $this;
    }

    /**
     * Add the z option to the command line.
     *
     * @return StatusCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function z()
    {
        $this->arguments[] = '-z';
        return $this;
    }

    /**
     * Add the column option to the command line.
     *
     * @param null|string $options The column options.
     *
     * @return StatusCommandBuilder
     */
    public function column($options = null)
    {
        $this->arguments[] = '--column' . ($options ? '=' . $options : '');
        return $this;
    }

    /**
     * Add the  option to the command line.
     *
     * @return StatusCommandBuilder
     */
    public function noColumn()
    {
        $this->arguments[] = '--no-column';
        return $this;
    }

    /**
     * Return the parsed index and work tree status.
     *
     * The result will be an associative array of all files and an status array in the following format:
     * <code>
     * array(
     *     '&lt;pathspec&gt;' => array(
     *         'index'    => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"],
     *         'worktree' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"],
     *     )
     * )
     * </code>
     *
     * @param string $pathspec A path spec.
     *
     * @param string $_        Optional list of additional path specs.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function getStatus($pathspec = null, $_ = null)
    {
        $this->porcelain();

        $status = (string) \call_user_func_array([$this, 'execute'], \func_get_args());
        $status = \explode("\n", $status);

        $files = [];

        foreach ($status as $line) {
            if (\trim($line)) {
                $index    = \trim(\substr($line, 0, 1));
                $worktree = \trim(\substr($line, 1, 1));

                if ($index && $worktree) {
                    $file         = \trim(\substr($line, 2));
                    $files[$file] = [
                        'index'    => $index,
                        'worktree' => $worktree,
                    ];
                }
            }
        }

        return $files;
    }

    /**
     * Return the parsed index status.
     *
     * The result will be an associative array of all files and their modification status in the following format:
     * <code>
     * array(
     *     '&lt;pathspec&gt;' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"],
     * )
     * </code>
     *
     * @param string $pathspec A path spec.
     *
     * @param string $_        Optional list of additional path specs.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function getIndexStatus($pathspec = null, $_ = null)
    {
        $this->porcelain();

        $status = (string) \call_user_func_array([$this, 'execute'], \func_get_args());
        $status = \explode("\n", $status);

        $files = [];

        foreach ($status as $line) {
            if ($line = \trim($line)) {
                $index = \substr($line, 0, 1);

                if ($index) {
                    $file         = \trim(\substr($line, 2));
                    $files[$file] = $index;
                }
            }
        }

        return $files;
    }

    /**
     * Return the parsed work tree status.
     *
     * The result will be an associative array of all files and their modification status in the following format:
     * <code>
     * array(
     *     '&lt;pathspec&gt;' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"],
     * )
     * </code>
     *
     * @param string $pathspec A path spec.
     *
     * @param string $_        Optional list of additional path specs.
     *
     * @return array
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function getWorkTreeStatus($pathspec = null, $_ = null)
    {
        $this->porcelain();

        $status = (string) \call_user_func_array([$this, 'execute'], \func_get_args());
        $status = \explode("\n", $status);

        $files = [];

        foreach ($status as $line) {
            if ($line = \trim($line)) {
                $worktree = \trim(\substr($line, 1, 1));

                if ($worktree) {
                    $file         = \trim(\substr($line, 2));
                    $files[$file] = $worktree;
                }
            }
        }

        return $files;
    }

    /**
     * Build the command and execute it.
     *
     * @param null|string $pathspec A path spec.
     * @param null|string $_        Optional list of additional path specs.
     *
     * @return string
     *
     * @SuppressWarnings(PHPMD.ShortVariableName)
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
     */
    public function execute($pathspec = null, $_ = null)
    {
        /** @var list<string> $args */
        $args = \func_get_args();
        if (\count($args)) {
            $this->arguments[] = '--';
            foreach ($args as $pathspec) {
                $this->arguments[] = $pathspec;
            }
        }
        return (string) $this->run();
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Command;

/**
 * Tag command builder.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 */
class TagCommandBuilder implements CommandBuilderInterface
{
    use CommandBuilderTrait;

    public const CLEANUP_VERBATIM = 'verbatim';

    public const CLEANUP_WHITESPACE = 'whitespace';

    public const CLEANUP_STRIP = 'strip';

    /**
     * Flag if signing shall be done.
     *
     * @var bool
     */
    protected $signIsset = false;

    /**
     * Flag determining if the local user has been set.
     *
     * @var bool
     */
    protected $localUserIsset = false;

    /**
     * {@inheritDoc}
     */
    protected function initializeProcessBuilder()
    {
        $this->arguments[] = 'tag';
    }

    /**
     * Add the annotate option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function annotate()
    {
        $this->arguments[] = '--annotate';
        return $this;
    }

    /**
     * Add the sign option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function sign()
    {
        $this->signIsset   = true;
        $this->arguments[] = '--sign';
        return $this;
    }

    /**
     * Add the local-user option to the command line.
     *
     * @param string $keyId The id of the local user key.
     *
     * @return TagCommandBuilder
     */
    public function localUser($keyId)
    {
        $this->localUserIsset = true;
        $this->arguments[]    = '--local-user=' . $keyId;
        return $this;
    }

    /**
     * Add the force option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function force()
    {
        $this->arguments[] = '--force';
        return $this;
    }

    /**
     * Add the delete option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function delete()
    {
        $this->arguments[] = '--delete';
        return $this;
    }

    /**
     * Add the verify option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function verify()
    {
        $this->arguments[] = '--verify';
        return $this;
    }

    /**
     * Add the n option to the command line.
     *
     * @param int $num The number.
     *
     * @return TagCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function n($num)
    {
        $this->arguments[] = '-n' . $num;
        return $this;
    }

    /**
     * Add the l option to the command line.
     *
     * @param string $pattern The pattern.
     *
     * @return TagCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function l($pattern)
    {
        $this->arguments[] = '--list';
        $this->arguments[] = $pattern;
        return $this;
    }

    /**
     * Add the column option to the command line.
     *
     * @param null|string $options The column options.
     *
     * @return TagCommandBuilder
     */
    public function column($options = null)
    {
        $this->arguments[] = '--column' . ($options ? '=' . $options : '');
        return $this;
    }

    /**
     * Add the no-column option to the command line.
     *
     * @return TagCommandBuilder
     */
    public function noColumn()
    {
        $this->arguments[] = '--no-column';
        return $this;
    }

    /**
     * Add the contains option to the command line.
     *
     * @param string $commit The commit hash.
     *
     * @return TagCommandBuilder
     */
    public function contains($commit)
    {
        $this->arguments[] = '--contains';
        $this->arguments[] = $commit;
        return $this;
    }

    /**
     * Add the points-at option to the command line.
     *
     * @param string $object The object the tag points at.
     *
     * @return TagCommandBuilder
     */
    public function pointsAt($object)
    {
        $this->arguments[] = '--points-at';
        $this->arguments[] = $object;
        return $this;
    }

    /**
     * Add the message option to the command line.
     *
     * @param string $message The message.
     *
     * @return TagCommandBuilder
     */
    public function message($message)
    {
        $this->arguments[] = '--message=' . $message;
        return $this;
    }

    /**
     * Add the file option to the command line.
     *
     * @param string $file The file.
     *
     * @return TagCommandBuilder
     */
    public function file($file)
    {
        $this->arguments[] = '--file=' . $file;
        return $this;
    }

    /**
     * Add the cleanup option to the command line.
     *
     * @param string $mode The cleanup mode.
     *
     * @return TagCommandBuilder
     */
    public function cleanup($mode)
    {
        $this->arguments[] = '--cleanup=' . $mode;
        return $this;
    }

    /**
     * Build the command and execute it.
     *
     * @param string      $tagName Name of the tag.
     *
     * @param null|string $commit  Commit hash to tag.
     *
     * @return string
     */
    public function execute($tagName = null, $commit = null)
    {
        if (!$this->signIsset && $this->repository->getConfig()->isSignTagsEnabled()) {
            $this->sign()->localUser($this->getDefaultSignUser());
        } elseif ($this->signIsset && !$this->localUserIsset && $this->repository->getConfig()->isSignTagsEnabled()) {
            $this->localUser($this->getDefaultSignUser());
        }

        if ($tagName) {
            $this->arguments[] = $tagName;
        }

        if ($commit) {
            $this->arguments[] = $commit;
        }

        return (string) $this->run();
    }

    /**
     * Retrieve the tag names.
     *
     * @return string[]
     */
    public function getNames()
    {
        $tags = $this->execute();
        $tags = \explode("\n", $tags);
        $tags = \array_map('trim', $tags);
        $tags = \array_filter($tags);

        return $tags;
    }

    private function getDefaultSignUser(): string
    {
        if (null === $user = $this->repository->getConfig()->getSignCommitUser()) {
            throw new \RuntimeException('Sign Commit User is not set in config.');
        }

        return $user;
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp;

use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

/**
 * Shareable configuration for git repositories.
 */
class GitConfig
{
    /**
     * The path to the git executable.
     *
     * @var string
     */
    protected $gitExecutablePath = 'git';

    /**
     * ID of the GPG certificate to sign commits.
     *
     * @var string|null
     */
    protected $signCommitUser;

    /**
     * ID of the GPG certificate to sign tags.
     *
     * @var string|null
     */
    protected $signTagUser;

    /**
     * Logger facility.
     *
     * @var LoggerInterface
     */
    protected $logger;

    /** The author to use in git commits */
    private ?string $committerName = null;

    /** The author to use in git commits */
    private ?string $committerEMail = null;

    /**
     * Create new git config.
     */
    public function __construct()
    {
        $this->logger = new NullLogger();
    }

    /**
     * Set the git executable path.
     *
     * @param string $gitExecutablePath Path to the git executable.
     *
     * @return GitConfig
     */
    public function setGitExecutablePath($gitExecutablePath)
    {
        /** @psalm-suppress RedundantCastGivenDocblockType - could be anything in theory - remove when type annotated */
        $this->gitExecutablePath = (string) $gitExecutablePath;
        return $this;
    }

    /**
     * Return the git executable path.
     *
     * @return string
     */
    public function getGitExecutablePath()
    {
        return $this->gitExecutablePath;
    }

    /**
     * Enable signing of commits.
     *
     * @param string $signUser The id of the GPG certificate.
     *
     * @return GitConfig
     */
    public function enableSignCommits($signUser)
    {
        /** @psalm-suppress RedundantCastGivenDocblockType - could be anything in theory - remove when type annotated */
        $this->signCommitUser = (string) $signUser;
        return $this;
    }

    /**
     * Disable signing of commits.
     *
     * @return $this
     */
    public function disableSignCommits()
    {
        $this->signCommitUser = null;
        return $this;
    }

    /**
     * Determine if signing commits is enabled.
     *
     * @return bool
     */
    public function isSignCommitsEnabled()
    {
        return (bool) $this->signCommitUser;
    }

    /**
     * Get the id of the GPG certificate to sign commits with.
     *
     * @return string|null
     */
    public function getSignCommitUser()
    {
        return $this->signCommitUser;
    }

    /**
     * Enable signing of tags.
     *
     * @param string $signUser The id of the GPG certificate.
     *
     * @return GitConfig
     */
    public function enableSignTags($signUser)
    {
        /** @psalm-suppress RedundantCastGivenDocblockType - could be anything in theory - remove when type annotated */
        $this->signTagUser = (string) $signUser;
        return $this;
    }

    /**
     * Disable signing of tags.
     *
     * @return GitConfig
     */
    public function disableSignTags()
    {
        $this->signTagUser = null;
        return $this;
    }

    /**
     * Determine if signing tags is enabled.
     *
     * @return boolean
     */
    public function isSignTagsEnabled()
    {
        return (bool) $this->signTagUser;
    }

    /**
     * Get the id of the GPG certificate to sign tags with.
     *
     * @return string|null
     */
    public function getSignTagUser()
    {
        return $this->signTagUser;
    }

    /**
     * Set the logger facility.
     *
     * @param LoggerInterface $logger The logger to use.
     *
     * @return GitConfig
     */
    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
        return $this;
    }

    /**
     * Return the logger facility.
     *
     * @return LoggerInterface
     */
    public function getLogger()
    {
        return $this->logger;
    }

    public function setCommitterName(string $committerName): self
    {
        $this->committerName = $committerName;

        return $this;
    }

    public function getCommitterName(): ?string
    {
        return $this->committerName;
    }

    public function setCommitterEMail(string $committerEMail): self
    {
        $this->committerEMail = $committerEMail;
        return $this;
    }

    public function getCommitterEMail(): ?string
    {
        return $this->committerEMail;
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2018 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp;

use Symfony\Component\Process\Process;

/**
 * Exception thrown when execution of git failed.
 *
 * @final
 */
class GitException extends \RuntimeException
{
    /**
     * The working directory path.
     *
     * @var string
     */
    protected $workingDirectory;

    /**
     * The executed command line.
     *
     * @var string
     */
    protected $commandLine;

    /**
     * The git commands standard output.
     *
     * @var string
     */
    protected $commandOutput;

    /**
     * The git commands error output.
     *
     * @var string
     */
    protected $errorOutput;

    /**
     * Create a new git exception.
     *
     * @param string $message          The error message.
     * @param string $workingDirectory The working directory.
     * @param string $commandLine      The used command line.
     * @param string $commandOutput    The command output.
     * @param string $errorOutput      The command error output.
     */
    public function __construct(
        string $message,
        string $workingDirectory,
        string $commandLine,
        string $commandOutput,
        string $errorOutput
    ) {
        parent::__construct($message, 0, null);
        $this->workingDirectory = $workingDirectory;
        $this->commandLine      = $commandLine;
        $this->commandOutput    = $commandOutput;
        $this->errorOutput      = $errorOutput;
    }

    /**
     * Return the working directory git was executed in.
     *
     * @return string
     */
    public function getWorkingDirectory(): string
    {
        return $this->workingDirectory;
    }

    /**
     * Return the command line to execute git.
     *
     * @return string
     */
    public function getCommandLine(): string
    {
        return $this->commandLine;
    }

    /**
     * Return the git commands standard output.
     *
     * @return string
     */
    public function getCommandOutput(): string
    {
        return $this->commandOutput;
    }

    /**
     * Return the git commands error output.
     *
     * @return string
     */
    public function getErrorOutput(): string
    {
        return $this->errorOutput;
    }

    /**
     * Create new exception from process.
     *
     * @param string  $message The message to use.
     *
     * @param Process $process The process to create the message from.
     *
     * @return static
     *
     * @final
     */
    public static function createFromProcess(string $message, Process $process)
    {
        $workdir = $process->getWorkingDirectory() ?? '?';
        return new static(
            \sprintf('%s [%s]', $message, $process->getCommandLine()) .
            PHP_EOL . \sprintf('work dir: %s', $workdir) .
            PHP_EOL . $process->getErrorOutput(),
            $workdir,
            $process->getCommandLine(),
            $process->getOutput(),
            $process->getErrorOutput()
        );
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     David Molineus <mail@netzmacht.de>
 * @author     Aaron Rubin <aaron@arkitech.net>
 * @author     Matthew Gamble <git@matthewgamble.net>
 * @author     Ahmad Marzouq <ahmad.marzouq@eagles-web.com>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp;

use Bit3\GitPhp\Command\AddCommandBuilder;
use Bit3\GitPhp\Command\BranchCommandBuilder;
use Bit3\GitPhp\Command\CheckoutCommandBuilder;
use Bit3\GitPhp\Command\ConfigCommandBuilder;
use Bit3\GitPhp\Command\MergeCommandBuilder;
use Bit3\GitPhp\Command\CloneCommandBuilder;
use Bit3\GitPhp\Command\CommitCommandBuilder;
use Bit3\GitPhp\Command\DescribeCommandBuilder;
use Bit3\GitPhp\Command\FetchCommandBuilder;
use Bit3\GitPhp\Command\InitCommandBuilder;
use Bit3\GitPhp\Command\LogCommandBuilder;
use Bit3\GitPhp\Command\LsRemoteCommandBuilder;
use Bit3\GitPhp\Command\PushCommandBuilder;
use Bit3\GitPhp\Command\RemoteCommandBuilder;
use Bit3\GitPhp\Command\ResetCommandBuilder;
use Bit3\GitPhp\Command\RevParseCommandBuilder;
use Bit3\GitPhp\Command\RmCommandBuilder;
use Bit3\GitPhp\Command\ShortLogCommandBuilder;
use Bit3\GitPhp\Command\ShowCommandBuilder;
use Bit3\GitPhp\Command\StatusCommandBuilder;
use Bit3\GitPhp\Command\TagCommandBuilder;
use Bit3\GitPhp\Command\PullCommandBuilder;
use Bit3\GitPhp\Command\StashCommandBuilder;

/**
 * GIT repository adapter.
 *
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class GitRepository
{
    /**
     * The path to the git repository.
     *
     * @var string
     */
    public $repositoryPath;

    /**
     * The shared git configuration.
     *
     * @var GitConfig
     */
    public $config;

    /**
     * Create a new git repository.
     *
     * @param string         $repositoryPath The path to the git repository.
     * @param null|GitConfig $config         The configuration to use.
     */
    public function __construct($repositoryPath, ?GitConfig $config = null)
    {
        /** @psalm-suppress RedundantCastGivenDocblockType - could be anything in theory - remove when type annotated */
        $this->repositoryPath = (string) $repositoryPath;
        $this->config         = $config ?: new GitConfig();
    }

    /**
     * Return the path to the git repository.
     *
     * @return string
     */
    public function getRepositoryPath()
    {
        return $this->repositoryPath;
    }

    /**
     * Return the shared git config.
     *
     * @return GitConfig
     */
    public function getConfig()
    {
        return $this->config;
    }

    /**
     * Determine if git is already initialized in the repository path.
     *
     * @return bool
     */
    public function isInitialized()
    {
        return \is_dir($this->repositoryPath . DIRECTORY_SEPARATOR . '.git');
    }

    /**
     * Create an init command.
     *
     * @return InitCommandBuilder
     */
    public function init()
    {
        return new InitCommandBuilder($this);
    }

    /**
     * Create a clone command.
     *
     * @return CloneCommandBuilder
     */
    public function cloneRepository()
    {
        return new CloneCommandBuilder($this);
    }

    /**
     * Create a config command.
     *
     * @return ConfigCommandBuilder
     */
    public function config()
    {
        return new ConfigCommandBuilder($this);
    }

    /**
     * Create a remote command.
     *
     * @return RemoteCommandBuilder
     */
    public function remote()
    {
        return new RemoteCommandBuilder($this);
    }

    /**
     * Create a branch command.
     *
     * @return BranchCommandBuilder
     */
    public function branch()
    {
        return new BranchCommandBuilder($this);
    }

    /**
     * Create a rev-parse command.
     *
     * @return RevParseCommandBuilder
     */
    public function revParse()
    {
        return new RevParseCommandBuilder($this);
    }

    /**
     * Create describe command.
     *
     * @return DescribeCommandBuilder
     */
    public function describe()
    {
        return new DescribeCommandBuilder($this);
    }

    /**
     * Create reset command.
     *
     * @return ResetCommandBuilder
     */
    public function reset()
    {
        return new ResetCommandBuilder($this);
    }

    /**
     * Create checkout command.
     *
     * @return CheckoutCommandBuilder
     */
    public function checkout()
    {
        return new CheckoutCommandBuilder($this);
    }

    /**
     * Create push command.
     *
     * @return PushCommandBuilder
     */
    public function push()
    {
        return new PushCommandBuilder($this);
    }

    /**
     * Create fetch command.
     *
     * @return FetchCommandBuilder
     */
    public function fetch()
    {
        return new FetchCommandBuilder($this);
    }

    /**
     * Create status command.
     *
     * @return StatusCommandBuilder
     */
    public function status()
    {
        return new StatusCommandBuilder($this);
    }

    /**
     * Create add command.
     *
     * @return AddCommandBuilder
     */
    public function add()
    {
        return new AddCommandBuilder($this);
    }

    /**
     * Create rm command.
     *
     * @return RmCommandBuilder
     *
     * @SuppressWarnings(PHPMD.ShortMethodName)
     */
    public function rm()
    {
        return new RmCommandBuilder($this);
    }

    /**
     * Create commit command.
     *
     * @return CommitCommandBuilder
     */
    public function commit()
    {
        return new CommitCommandBuilder($this);
    }

    /**
     * Create tag command.
     *
     * @return TagCommandBuilder
     */
    public function tag()
    {
        return new TagCommandBuilder($this);
    }

    /**
     * Create show command.
     *
     * @return ShowCommandBuilder
     */
    public function show()
    {
        return new ShowCommandBuilder($this);
    }

    /**
     * Create log command.
     *
     * @return LogCommandBuilder
     */
    public function log()
    {
        return new LogCommandBuilder($this);
    }

    /**
     * Create shortlog command.
     *
     * @return ShortLogCommandBuilder
     */
    public function shortlog()
    {
        return new ShortLogCommandBuilder($this);
    }

    /**
     * Create ls-remote command.
     *
     * @return LsRemoteCommandBuilder
     */
    public function lsRemote()
    {
        return new LsRemoteCommandBuilder($this);
    }

    /**
     * Create Merge command.
     *
     * @return MergeCommandBuilder
     */
    public function merge()
    {
        return new MergeCommandBuilder($this);
    }

    /**
     * Create Pull command.
     *
     * @return PullCommandBuilder
     */
    public function pull()
    {
        return new PullCommandBuilder($this);
    }

    /**
     * Create stash command.
     *
     * @return StashCommandBuilder
     */
    public function stash()
    {
        return new StashCommandBuilder($this);
    }
}
<?php

/**
 * This file is part of bit3/git-php.
 *
 * (c) Tristan Lins <tristan@lins.io>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * This project is provided in good faith and hope to be usable by anyone.
 *
 * @package    bit3/git-php
 * @author     Tristan Lins <tristan@lins.io>
 * @author     Christian Schiffler <c.schiffler@cyberspectrum.de>
 * @author     Matthew Gamble <git@matthewgamble.net>
 * @author     Sven Baumann <baumann.sv@gmail.com>
 * @copyright  2014-2022 Tristan Lins <tristan@lins.io>
 * @license    https://github.com/bit3/git-php/blob/master/LICENSE MIT
 * @link       https://github.com/bit3/git-php
 * @filesource
 */

namespace Bit3\GitPhp\Test;

use Bit3\GitPhp\GitRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;

/**
 * GIT repository unit tests.
 *
 * @covers \Bit3\GitPhp\GitRepository
 */
class GitRepositoryTest extends TestCase
{
    /**
     * @var string
     */
    protected $initializedRepositoryPath;

    /**
     * @var string
     */
    protected $uninitializedRepositoryPath;

    /**
     * @var GitRepository
     */
    protected $initializedGitRepository;

    /**
     * @var GitRepository
     */
    protected $uninitializedGitRepository;

    public function setUp(): void
    {
        $this->initializedRepositoryPath = \tempnam(\sys_get_temp_dir(), 'git_');
        \unlink($this->initializedRepositoryPath);
        \mkdir($this->initializedRepositoryPath);

        $this->uninitializedRepositoryPath = \tempnam(\sys_get_temp_dir(), 'git_');
        \unlink($this->uninitializedRepositoryPath);
        \mkdir($this->uninitializedRepositoryPath);

        $zip = new \ZipArchive();
        $zip->open(__DIR__ . DIRECTORY_SEPARATOR . 'git.zip');
        $zip->extractTo($this->initializedRepositoryPath);

        $this->initializedGitRepository   = new GitRepository($this->initializedRepositoryPath);
        $this->uninitializedGitRepository = new GitRepository($this->uninitializedRepositoryPath);
    }

    public function tearDown(): void
    {
        $fs = new Filesystem();
        $fs->remove($this->initializedRepositoryPath);
        $fs->remove($this->uninitializedRepositoryPath);

        unset($this->initializedRepositoryPath);
        unset($this->uninitializedRepositoryPath);
        unset($this->initializedGitRepository);
        unset($this->uninitializedGitRepository);
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::getRepositoryPath
     */
    public function testGetRepositoryPath()
    {
        $this->assertEquals(
            $this->initializedRepositoryPath,
            $this->initializedGitRepository->getRepositoryPath()
        );
        $this->assertEquals(
            $this->uninitializedRepositoryPath,
            $this->uninitializedGitRepository->getRepositoryPath()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::isInitialized
     */
    public function testIsInitialized()
    {
        $this->assertTrue(
            $this->initializedGitRepository->isInitialized()
        );
        $this->assertFalse(
            $this->uninitializedGitRepository->isInitialized()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::init
     * @covers \Bit3\GitPhp\Command\InitCommandBuilder::execute
     */
    public function testInit()
    {
        $this->uninitializedGitRepository->init()->execute();

        $this->assertTrue(
            \is_dir($this->uninitializedRepositoryPath . DIRECTORY_SEPARATOR . '.git')
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::config
     * @covers \Bit3\GitPhp\Command\ConfigCommandBuilder::execute
     * @covers \Bit3\GitPhp\Command\ConfigCommandBuilder::get
     */
    public function testConfigGetOnInitializedRepository()
    {
        $this->assertEquals(
            'false',
            $this->initializedGitRepository->config()->file('local')->execute('core.bare')
        );
        $this->assertEquals(
            'CCA unittest',
            $this->initializedGitRepository->config()->file('local')->get('user.name')->execute()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::config
     * @covers \Bit3\GitPhp\Command\ConfigCommandBuilder
     */
    public function testConfigGetOnUnitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->config()->file('local')->execute('core.bare');
        $this->uninitializedGitRepository->config()->file('local')->get('user.name')->execute();
    }

    public function testConfigSetOnInitializedRepository()
    {
        $this->initializedGitRepository->config()->file('local')->execute('user.name', 'CCA unittest 2');

        $process = new Process(['git', 'config', '--local', 'user.name'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            'CCA unittest 2',
            trim($process->getOutput())
        );
    }

    public function testConfigAddOnInitializedRepository()
    {
        $this->initializedGitRepository->config()->file('local')->add('user.name', 'CCA unittest 2')->execute();

        $process = new Process(
            ['git', 'config', '--local', '--get-all', 'user.name'], $this->initializedRepositoryPath
        );
        $process->run();

        $names = \explode("\n", $process->getOutput());
        $names = \array_map('trim', $names);
        $names = \array_filter($names);

        $this->assertEquals(
            ['CCA unittest', 'CCA unittest 2'],
            $names
        );
    }

    public function testConfigGetAllOnInitializedRepository()
    {
        $values = $this->initializedGitRepository->config()->file('local')->getAll('gitphp.test2')->execute();

        $values = \explode("\n", $values);
        $values = \array_map('trim', $values);
        $values = \array_filter($values);

        $this->assertEquals(
            ['aa123', 'ab234', 'ac345', 'bb234'],
            $values
        );

        $values = $this->initializedGitRepository->config()->file('local')->getAll('gitphp.test2', '^a.+3.+$')->execute();

        $values = \explode("\n", $values);
        $values = \array_map('trim', $values);
        $values = \array_filter($values);

        $this->assertEquals(
            ['ab234', 'ac345'],
            $values
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::getNames
     */
    public function testListRemotesOnInitializedRepository()
    {
        $this->assertEquals(
            ['local'],
            $this->initializedGitRepository->remote()->getNames()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::getNames
     */
    public function testListRemotesOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->remote()->getNames();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::branch
     * @covers \Bit3\GitPhp\Command\BranchCommandBuilder::all
     * @covers \Bit3\GitPhp\Command\BranchCommandBuilder::getNames
     */
    public function testListBranchesOnInitializedRepository()
    {
        $this->assertEquals(
            ['master'],
            $this->initializedGitRepository->branch()->getNames()
        );
        $this->assertEquals(
            ['master', 'remotes/local/master'],
            $this->initializedGitRepository->branch()->all()->getNames()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::branch
     * @covers \Bit3\GitPhp\Command\BranchCommandBuilder::getNames
     */
    public function testListBranchesOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->branch()->getNames();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::describe
     * @covers \Bit3\GitPhp\Command\DescribeCommandBuilder::tags
     * @covers \Bit3\GitPhp\Command\DescribeCommandBuilder::all
     * @covers \Bit3\GitPhp\Command\DescribeCommandBuilder::execute
     */
    public function testDescribeOnInitializedRepository()
    {
        $this->assertEquals(
            'annotated-tag-2-g8dcaf85',
            $this->initializedGitRepository->describe()->execute()
        );
        $this->assertEquals(
            'lightweight-tag-1-g8dcaf85',
            $this->initializedGitRepository->describe()->tags()->execute()
        );
        $this->assertEquals(
            'heads/master',
            $this->initializedGitRepository->describe()->all()->execute()
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::describe
     * @covers \Bit3\GitPhp\Command\DescribeCommandBuilder::execute
     */
    public function testDescribeOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->describe()->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::setUrl
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteSetUrlOnInitializedRepository()
    {
        $this->initializedGitRepository->remote()->setUrl('local', $this->uninitializedRepositoryPath)->execute();

        $process = new Process(['git', 'config', 'remote.local.url'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            \trim($process->getOutput()),
            $this->uninitializedRepositoryPath
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::setUrl
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteSetUrlOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->remote()->setUrl('local', $this->initializedRepositoryPath)->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::setPushUrl
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteSetPushUrlOnInitializedRepository()
    {
        $this->initializedGitRepository->remote()->setPushUrl('local', $this->uninitializedRepositoryPath)->execute();

        $process = new Process(['git', 'config', 'remote.local.url'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            \trim($process->getOutput()),
            '/tmp/git'
        );

        $process = new Process(['git', 'config', 'remote.local.pushurl'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            \trim($process->getOutput()),
            $this->uninitializedRepositoryPath
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::setPushUrl
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteSetPushUrlOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->remote()->setPushUrl('local', $this->initializedRepositoryPath)->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::add
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteAddOnInitializedRepository()
    {
        $this->initializedGitRepository->remote()->add('origin', $this->uninitializedRepositoryPath)->execute();

        $process = new Process(['git', 'config', 'remote.origin.url'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            trim($process->getOutput()),
            $this->uninitializedRepositoryPath
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::remote
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::add
     * @covers \Bit3\GitPhp\Command\RemoteCommandBuilder::execute
     */
    public function testRemoteAddOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->remote()->add('origin', $this->initializedRepositoryPath)->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::fetch
     * @covers \Bit3\GitPhp\Command\FetchCommandBuilder::execute
     */
    public function testRemoteFetchOnInitializedRepository()
    {
        $process = new Process(
            ['git', 'remote', 'add', 'origin', $this->initializedRepositoryPath], $this->initializedRepositoryPath
        );
        $process->run();

        $this->initializedGitRepository->fetch()->execute();

        $process = new Process(['git', 'branch', '-a'], $this->initializedRepositoryPath);
        $process->run();

        $branches = explode("\n", $process->getOutput());
        $branches = array_map('trim', $branches);
        $branches = array_filter($branches);

        $this->assertTrue(
            \in_array('remotes/origin/master', $branches)
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::fetch
     * @covers \Bit3\GitPhp\Command\FetchCommandBuilder::execute
     */
    public function testRemoteFetchOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->fetch()->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::checkout
     * @covers \Bit3\GitPhp\Command\CheckoutCommandBuilder::execute
     */
    public function testCheckoutOnInitializedRepository()
    {
        $process = new Process(
            ['git', 'remote', 'add', 'origin', $this->initializedRepositoryPath], $this->initializedRepositoryPath
        );
        $process->run();

        $this->initializedGitRepository->checkout()->execute('6c42d7ba78e0e956bd4e25661a6c13d826ef590a');

        $process = new Process(['git', 'describe'], $this->initializedRepositoryPath);
        $process->run();

        $this->assertEquals(
            \trim($process->getOutput()),
            'annotated-tag'
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::checkout
     * @covers \Bit3\GitPhp\Command\CheckoutCommandBuilder::execute
     */
    public function testCheckoutOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->checkout()->execute('foo');
    }

    public function testPushOnInitializedRepository()
    {
        $this->markTestIncomplete();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::push
     * @covers \Bit3\GitPhp\Command\PushCommandBuilder::execute
     */
    public function testPushOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->push()->execute('foo');
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::status
     * @covers \Bit3\GitPhp\Command\StatusCommandBuilder::getStatus
     */
    public function testStatusOnInitializedRepository()
    {
        $status = $this->initializedGitRepository->status()->getStatus();

        $this->assertEquals(
            [
                'removed-but-staged.txt' => ['index' => 'A', 'worktree' => 'D'],
                'unknown-file.txt'       => ['index' => '?', 'worktree' => '?'],
            ],
            $status
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::status
     * @covers \Bit3\GitPhp\Command\StatusCommandBuilder::getStatus
     */
    public function testStatusOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->status()->getStatus();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::add
     * @covers \Bit3\GitPhp\Command\AddCommandBuilder::execute
     */
    public function testAddOnInitializedRepository()
    {
        $this->initializedGitRepository->add()->execute('unknown-file.txt');

        $process = new Process(['git', 'status', '-s'], $this->initializedRepositoryPath);
        $process->run();

        $status = \explode("\n", $process->getOutput());
        $status = \array_map('trim', $status);

        $this->assertTrue(
            \in_array('A  unknown-file.txt', $status)
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::add
     * @covers \Bit3\GitPhp\Command\AddCommandBuilder::execute
     */
    public function testAddOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->add()->execute('unknown-file.txt');
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::rm
     * @covers \Bit3\GitPhp\Command\RmCommandBuilder::execute
     */
    public function testRmOnInitializedRepository()
    {
        $this->initializedGitRepository->rm()->execute('existing-file.txt');

        $process = new Process(['git', 'status', '-s'], $this->initializedRepositoryPath);
        $process->run();

        $status = \explode("\n", $process->getOutput());
        $status = \array_map('trim', $status);

        $this->assertTrue(
            \in_array('D  existing-file.txt', $status)
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::rm
     * @covers \Bit3\GitPhp\Command\RmCommandBuilder::execute
     */
    public function testRmOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->rm()->execute('existing-file.txt');
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::commit
     * @covers \Bit3\GitPhp\Command\CommitCommandBuilder::message
     * @covers \Bit3\GitPhp\Command\CommitCommandBuilder::execute
     */
    public function testCommitOnInitializedRepository()
    {
        $this->initializedGitRepository->commit()->message('Commit changes')->execute();

        $process = new Process(['git', 'status', '-s'], $this->initializedRepositoryPath);
        $process->run();

        $status = \explode("\n", $process->getOutput());
        $status = \array_map('trim', $status);
        $status = \array_filter($status);

        $this->assertEquals(
            [
                'D existing-file.txt',
                'D removed-but-staged.txt',
                '?? unknown-file.txt',
            ],
            $status
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::commit
     * @covers \Bit3\GitPhp\Command\CommitCommandBuilder::message
     * @covers \Bit3\GitPhp\Command\CommitCommandBuilder::execute
     */
    public function testCommitOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->commit()->message('Commit changes')->execute();
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::tag
     * @covers \Bit3\GitPhp\Command\TagCommandBuilder::execute
     */
    public function testTagOnInitializedRepository()
    {
        $this->initializedGitRepository->tag()->execute('unit-test');

        $process = new Process(['git', 'tag'], $this->initializedRepositoryPath);
        $process->run();

        $tags = \explode("\n", $process->getOutput());
        $tags = \array_map('trim', $tags);
        $tags = \array_filter($tags);

        $this->assertTrue(
            \in_array('unit-test', $tags)
        );
    }

    /**
     * @covers \Bit3\GitPhp\GitRepository::tag
     * @covers \Bit3\GitPhp\Command\TagCommandBuilder::execute
     */
    public function testTagOnUninitializedRepository()
    {
        if (\method_exists($this, 'setExpectedException')) {
            $this->setExpectedException('Bit3\GitPhp\GitException');
        } else {
            $this->expectException('Bit3\GitPhp\GitException');
        }

        $this->uninitializedGitRepository->tag()->execute('unit-test');
    }
}
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Arrayy\\Arrayy' => $vendorDir . '/voku/arrayy/src/Arrayy.php',
    'Arrayy\\ArrayyIterator' => $vendorDir . '/voku/arrayy/src/ArrayyIterator.php',
    'Arrayy\\ArrayyMeta' => $vendorDir . '/voku/arrayy/src/ArrayyMeta.php',
    'Arrayy\\ArrayyRewindableExtendedGenerator' => $vendorDir . '/voku/arrayy/src/ArrayyRewindableExtendedGenerator.php',
    'Arrayy\\ArrayyRewindableGenerator' => $vendorDir . '/voku/arrayy/src/ArrayyRewindableGenerator.php',
    'Arrayy\\ArrayyStrict' => $vendorDir . '/voku/arrayy/src/ArrayyStrict.php',
    'Arrayy\\Collection\\AbstractCollection' => $vendorDir . '/voku/arrayy/src/Collection/AbstractCollection.php',
    'Arrayy\\Collection\\Collection' => $vendorDir . '/voku/arrayy/src/Collection/Collection.php',
    'Arrayy\\Collection\\CollectionInterface' => $vendorDir . '/voku/arrayy/src/Collection/CollectionInterface.php',
    'Arrayy\\Mapper\\Json' => $vendorDir . '/voku/arrayy/src/Mapper/Json.php',
    'Arrayy\\StaticArrayy' => $vendorDir . '/voku/arrayy/src/StaticArrayy.php',
    'Arrayy\\TypeCheck\\AbstractTypeCheck' => $vendorDir . '/voku/arrayy/src/TypeCheck/AbstractTypeCheck.php',
    'Arrayy\\TypeCheck\\TypeCheckArray' => $vendorDir . '/voku/arrayy/src/TypeCheck/TypeCheckArray.php',
    'Arrayy\\TypeCheck\\TypeCheckCallback' => $vendorDir . '/voku/arrayy/src/TypeCheck/TypeCheckCallback.php',
    'Arrayy\\TypeCheck\\TypeCheckInterface' => $vendorDir . '/voku/arrayy/src/TypeCheck/TypeCheckInterface.php',
    'Arrayy\\TypeCheck\\TypeCheckPhpDoc' => $vendorDir . '/voku/arrayy/src/TypeCheck/TypeCheckPhpDoc.php',
    'Arrayy\\TypeCheck\\TypeCheckSimple' => $vendorDir . '/voku/arrayy/src/TypeCheck/TypeCheckSimple.php',
    'Arrayy\\Type\\ArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/ArrayCollection.php',
    'Arrayy\\Type\\BoolArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/BoolArrayCollection.php',
    'Arrayy\\Type\\BoolCollection' => $vendorDir . '/voku/arrayy/src/Type/BoolCollection.php',
    'Arrayy\\Type\\CallableCollection' => $vendorDir . '/voku/arrayy/src/Type/CallableCollection.php',
    'Arrayy\\Type\\DetectFirstValueTypeCollection' => $vendorDir . '/voku/arrayy/src/Type/DetectFirstValueTypeCollection.php',
    'Arrayy\\Type\\FloatArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/FloatArrayCollection.php',
    'Arrayy\\Type\\FloatCollection' => $vendorDir . '/voku/arrayy/src/Type/FloatCollection.php',
    'Arrayy\\Type\\FloatIntArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/FloatIntArrayCollection.php',
    'Arrayy\\Type\\FloatIntCollection' => $vendorDir . '/voku/arrayy/src/Type/FloatIntCollection.php',
    'Arrayy\\Type\\InstanceCollection' => $vendorDir . '/voku/arrayy/src/Type/InstanceCollection.php',
    'Arrayy\\Type\\InstancesCollection' => $vendorDir . '/voku/arrayy/src/Type/InstancesCollection.php',
    'Arrayy\\Type\\IntArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/IntArrayCollection.php',
    'Arrayy\\Type\\IntCollection' => $vendorDir . '/voku/arrayy/src/Type/IntCollection.php',
    'Arrayy\\Type\\JsonSerializableCollection' => $vendorDir . '/voku/arrayy/src/Type/JsonSerializableCollection.php',
    'Arrayy\\Type\\MixedCollection' => $vendorDir . '/voku/arrayy/src/Type/MixedCollection.php',
    'Arrayy\\Type\\NonEmptyStringCollection' => $vendorDir . '/voku/arrayy/src/Type/NonEmptyStringCollection.php',
    'Arrayy\\Type\\NumericCollection' => $vendorDir . '/voku/arrayy/src/Type/NumericCollection.php',
    'Arrayy\\Type\\NumericStringCollection' => $vendorDir . '/voku/arrayy/src/Type/NumericStringCollection.php',
    'Arrayy\\Type\\ObjectCollection' => $vendorDir . '/voku/arrayy/src/Type/ObjectCollection.php',
    'Arrayy\\Type\\ResourceCollection' => $vendorDir . '/voku/arrayy/src/Type/ResourceCollection.php',
    'Arrayy\\Type\\ScalarCollection' => $vendorDir . '/voku/arrayy/src/Type/ScalarCollection.php',
    'Arrayy\\Type\\StdClassCollection' => $vendorDir . '/voku/arrayy/src/Type/StdClassCollection.php',
    'Arrayy\\Type\\StringArrayCollection' => $vendorDir . '/voku/arrayy/src/Type/StringArrayCollection.php',
    'Arrayy\\Type\\StringCollection' => $vendorDir . '/voku/arrayy/src/Type/StringCollection.php',
    'Arrayy\\Type\\TypeInterface' => $vendorDir . '/voku/arrayy/src/Type/TypeInterface.php',
    'Bit3\\GitPhp\\Command\\AbstractCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/AbstractCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\AddCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/AddCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\BranchCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/BranchCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\CheckoutCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/CheckoutCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\CloneCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/CloneCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\CommandBuilderInterface' => $vendorDir . '/bit3/git-php/src/Command/CommandBuilderInterface.php',
    'Bit3\\GitPhp\\Command\\CommandBuilderTrait' => $vendorDir . '/bit3/git-php/src/Command/CommandBuilderTrait.php',
    'Bit3\\GitPhp\\Command\\CommitCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/CommitCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\ConfigCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/ConfigCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\DescribeCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/DescribeCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\FetchCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/FetchCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\InitCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/InitCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\LogCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/LogCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\LsRemoteCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/LsRemoteCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\MergeCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/MergeCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\PullCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/PullCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\PushCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/PushCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\RemoteCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/RemoteCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\ResetCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/ResetCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\RevParseCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/RevParseCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\RmCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/RmCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\ShortLogCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/ShortLogCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\ShowCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/ShowCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\StashCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/StashCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\StatusCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/StatusCommandBuilder.php',
    'Bit3\\GitPhp\\Command\\TagCommandBuilder' => $vendorDir . '/bit3/git-php/src/Command/TagCommandBuilder.php',
    'Bit3\\GitPhp\\GitConfig' => $vendorDir . '/bit3/git-php/src/GitConfig.php',
    'Bit3\\GitPhp\\GitException' => $vendorDir . '/bit3/git-php/src/GitException.php',
    'Bit3\\GitPhp\\GitRepository' => $vendorDir . '/bit3/git-php/src/GitRepository.php',
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
    'Composer\\Semver\\Constraint\\AbstractConstraint' => $vendorDir . '/composer/semver/src/Constraint/AbstractConstraint.php',
    'Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
    'Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
    'Composer\\Semver\\Constraint\\EmptyConstraint' => $vendorDir . '/composer/semver/src/Constraint/EmptyConstraint.php',
    'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
    'Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
    'Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
    'Defuse\\Crypto\\Core' => $vendorDir . '/defuse/php-encryption/src/Core.php',
    'Defuse\\Crypto\\Crypto' => $vendorDir . '/defuse/php-encryption/src/Crypto.php',
    'Defuse\\Crypto\\DerivedKeys' => $vendorDir . '/defuse/php-encryption/src/DerivedKeys.php',
    'Defuse\\Crypto\\Encoding' => $vendorDir . '/defuse/php-encryption/src/Encoding.php',
    'Defuse\\Crypto\\Exception\\BadFormatException' => $vendorDir . '/defuse/php-encryption/src/Exception/BadFormatException.php',
    'Defuse\\Crypto\\Exception\\CryptoException' => $vendorDir . '/defuse/php-encryption/src/Exception/CryptoException.php',
    'Defuse\\Crypto\\Exception\\EnvironmentIsBrokenException' => $vendorDir . '/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php',
    'Defuse\\Crypto\\Exception\\IOException' => $vendorDir . '/defuse/php-encryption/src/Exception/IOException.php',
    'Defuse\\Crypto\\Exception\\WrongKeyOrModifiedCiphertextException' => $vendorDir . '/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php',
    'Defuse\\Crypto\\File' => $vendorDir . '/defuse/php-encryption/src/File.php',
    'Defuse\\Crypto\\Key' => $vendorDir . '/defuse/php-encryption/src/Key.php',
    'Defuse\\Crypto\\KeyOrPassword' => $vendorDir . '/defuse/php-encryption/src/KeyOrPassword.php',
    'Defuse\\Crypto\\KeyProtectedByPassword' => $vendorDir . '/defuse/php-encryption/src/KeyProtectedByPassword.php',
    'Defuse\\Crypto\\RuntimeTests' => $vendorDir . '/defuse/php-encryption/src/RuntimeTests.php',
    'Doctrine\\Deprecations\\Deprecation' => $vendorDir . '/doctrine/deprecations/src/Deprecation.php',
    'Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => $vendorDir . '/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php',
    'FW\\Installer\\App' => $baseDir . '/src/App.php',
    'FW\\Installer\\Command\\Addon' => $baseDir . '/src/Command/Addon.php',
    'FW\\Installer\\Command\\BaseCommand' => $baseDir . '/src/Command/BaseCommand.php',
    'FW\\Installer\\Command\\Install' => $baseDir . '/src/Command/Install.php',
    'FW\\Installer\\Command\\Login' => $baseDir . '/src/Command/Login.php',
    'FW\\Installer\\Command\\Publish' => $baseDir . '/src/Command/Publish.php',
    'FW\\Installer\\Command\\SelfUpdate' => $baseDir . '/src/Command/SelfUpdate.php',
    'FW\\Installer\\Command\\Setup' => $baseDir . '/src/Command/Setup.php',
    'FW\\Installer\\Command\\Task' => $baseDir . '/src/Command/Task.php',
    'FW\\Installer\\Command\\Update' => $baseDir . '/src/Command/Update.php',
    'FW\\Installer\\Helpers\\Process' => $baseDir . '/src/Helpers/Process.php',
    'FW\\Installer\\Helpers\\Prompt' => $baseDir . '/src/Helpers/Prompt.php',
    'FW\\Installer\\Providers\\BaseProvider' => $baseDir . '/src/Providers/BaseProvider.php',
    'FW\\Installer\\Providers\\Bitbucket' => $baseDir . '/src/Providers/Bitbucket.php',
    'FW\\Installer\\Providers\\Github' => $baseDir . '/src/Providers/Github.php',
    'FW\\Installer\\Task\\AbstractTask' => $baseDir . '/src/Task/AbstractTask.php',
    'FW\\Installer\\Task\\Addon' => $baseDir . '/src/Task/Addon.php',
    'FW\\Installer\\Task\\Assets' => $baseDir . '/src/Task/Assets.php',
    'FW\\Installer\\Task\\Composer' => $baseDir . '/src/Task/Composer.php',
    'FW\\Installer\\Task\\Download' => $baseDir . '/src/Task/Download.php',
    'FW\\Installer\\Task\\GitClone' => $baseDir . '/src/Task/GitClone.php',
    'FW\\Installer\\Utils\\AppInstall' => $baseDir . '/src/Utils/AppInstall.php',
    'FW\\Installer\\Utils\\CommandException' => $baseDir . '/src/Utils/CommandException.php',
    'FW\\Installer\\Utils\\Config' => $baseDir . '/src/Utils/Config.php',
    'FW\\Installer\\Utils\\Dependencies' => $baseDir . '/src/Utils/Dependencies.php',
    'FW\\Installer\\Utils\\ErrorHandler' => $baseDir . '/src/Utils/ErrorHandler.php',
    'FW\\Installer\\Utils\\File' => $baseDir . '/src/Utils/File.php',
    'FW\\Installer\\Utils\\Registry' => $baseDir . '/src/Utils/Registry.php',
    'FW\\Installer\\Utils\\RunContext' => $baseDir . '/src/Utils/RunContext.php',
    'FW\\Installer\\Utils\\SystemConfig' => $baseDir . '/src/Utils/SystemConfig.php',
    'FW\\Installer\\Utils\\Updater' => $baseDir . '/src/Utils/Updater.php',
    'FW\\Installer\\Utils\\VersionUtils' => $baseDir . '/src/Utils/VersionUtils.php',
    'GuzzleHttp\\BodySummarizer' => $vendorDir . '/guzzlehttp/guzzle/src/BodySummarizer.php',
    'GuzzleHttp\\BodySummarizerInterface' => $vendorDir . '/guzzlehttp/guzzle/src/BodySummarizerInterface.php',
    'GuzzleHttp\\Client' => $vendorDir . '/guzzlehttp/guzzle/src/Client.php',
    'GuzzleHttp\\ClientInterface' => $vendorDir . '/guzzlehttp/guzzle/src/ClientInterface.php',
    'GuzzleHttp\\ClientTrait' => $vendorDir . '/guzzlehttp/guzzle/src/ClientTrait.php',
    'GuzzleHttp\\Cookie\\CookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
    'GuzzleHttp\\Cookie\\CookieJarInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
    'GuzzleHttp\\Cookie\\FileCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
    'GuzzleHttp\\Cookie\\SessionCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
    'GuzzleHttp\\Cookie\\SetCookie' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
    'GuzzleHttp\\Exception\\BadResponseException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
    'GuzzleHttp\\Exception\\ClientException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
    'GuzzleHttp\\Exception\\ConnectException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
    'GuzzleHttp\\Exception\\GuzzleException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
    'GuzzleHttp\\Exception\\InvalidArgumentException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php',
    'GuzzleHttp\\Exception\\RequestException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
    'GuzzleHttp\\Exception\\ServerException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
    'GuzzleHttp\\Exception\\TooManyRedirectsException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
    'GuzzleHttp\\Exception\\TransferException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
    'GuzzleHttp\\HandlerStack' => $vendorDir . '/guzzlehttp/guzzle/src/HandlerStack.php',
    'GuzzleHttp\\Handler\\CurlFactory' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
    'GuzzleHttp\\Handler\\CurlFactoryInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
    'GuzzleHttp\\Handler\\CurlHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
    'GuzzleHttp\\Handler\\CurlMultiHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
    'GuzzleHttp\\Handler\\EasyHandle' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
    'GuzzleHttp\\Handler\\HeaderProcessor' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php',
    'GuzzleHttp\\Handler\\MockHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
    'GuzzleHttp\\Handler\\Proxy' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
    'GuzzleHttp\\Handler\\StreamHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
    'GuzzleHttp\\MessageFormatter' => $vendorDir . '/guzzlehttp/guzzle/src/MessageFormatter.php',
    'GuzzleHttp\\MessageFormatterInterface' => $vendorDir . '/guzzlehttp/guzzle/src/MessageFormatterInterface.php',
    'GuzzleHttp\\Middleware' => $vendorDir . '/guzzlehttp/guzzle/src/Middleware.php',
    'GuzzleHttp\\Pool' => $vendorDir . '/guzzlehttp/guzzle/src/Pool.php',
    'GuzzleHttp\\PrepareBodyMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
    'GuzzleHttp\\Promise\\AggregateException' => $vendorDir . '/guzzlehttp/promises/src/AggregateException.php',
    'GuzzleHttp\\Promise\\CancellationException' => $vendorDir . '/guzzlehttp/promises/src/CancellationException.php',
    'GuzzleHttp\\Promise\\Coroutine' => $vendorDir . '/guzzlehttp/promises/src/Coroutine.php',
    'GuzzleHttp\\Promise\\Create' => $vendorDir . '/guzzlehttp/promises/src/Create.php',
    'GuzzleHttp\\Promise\\Each' => $vendorDir . '/guzzlehttp/promises/src/Each.php',
    'GuzzleHttp\\Promise\\EachPromise' => $vendorDir . '/guzzlehttp/promises/src/EachPromise.php',
    'GuzzleHttp\\Promise\\FulfilledPromise' => $vendorDir . '/guzzlehttp/promises/src/FulfilledPromise.php',
    'GuzzleHttp\\Promise\\Is' => $vendorDir . '/guzzlehttp/promises/src/Is.php',
    'GuzzleHttp\\Promise\\Promise' => $vendorDir . '/guzzlehttp/promises/src/Promise.php',
    'GuzzleHttp\\Promise\\PromiseInterface' => $vendorDir . '/guzzlehttp/promises/src/PromiseInterface.php',
    'GuzzleHttp\\Promise\\PromisorInterface' => $vendorDir . '/guzzlehttp/promises/src/PromisorInterface.php',
    'GuzzleHttp\\Promise\\RejectedPromise' => $vendorDir . '/guzzlehttp/promises/src/RejectedPromise.php',
    'GuzzleHttp\\Promise\\RejectionException' => $vendorDir . '/guzzlehttp/promises/src/RejectionException.php',
    'GuzzleHttp\\Promise\\TaskQueue' => $vendorDir . '/guzzlehttp/promises/src/TaskQueue.php',
    'GuzzleHttp\\Promise\\TaskQueueInterface' => $vendorDir . '/guzzlehttp/promises/src/TaskQueueInterface.php',
    'GuzzleHttp\\Promise\\Utils' => $vendorDir . '/guzzlehttp/promises/src/Utils.php',
    'GuzzleHttp\\Psr7\\AppendStream' => $vendorDir . '/guzzlehttp/psr7/src/AppendStream.php',
    'GuzzleHttp\\Psr7\\BufferStream' => $vendorDir . '/guzzlehttp/psr7/src/BufferStream.php',
    'GuzzleHttp\\Psr7\\CachingStream' => $vendorDir . '/guzzlehttp/psr7/src/CachingStream.php',
    'GuzzleHttp\\Psr7\\DroppingStream' => $vendorDir . '/guzzlehttp/psr7/src/DroppingStream.php',
    'GuzzleHttp\\Psr7\\Exception\\MalformedUriException' => $vendorDir . '/guzzlehttp/psr7/src/Exception/MalformedUriException.php',
    'GuzzleHttp\\Psr7\\FnStream' => $vendorDir . '/guzzlehttp/psr7/src/FnStream.php',
    'GuzzleHttp\\Psr7\\Header' => $vendorDir . '/guzzlehttp/psr7/src/Header.php',
    'GuzzleHttp\\Psr7\\HttpFactory' => $vendorDir . '/guzzlehttp/psr7/src/HttpFactory.php',
    'GuzzleHttp\\Psr7\\InflateStream' => $vendorDir . '/guzzlehttp/psr7/src/InflateStream.php',
    'GuzzleHttp\\Psr7\\LazyOpenStream' => $vendorDir . '/guzzlehttp/psr7/src/LazyOpenStream.php',
    'GuzzleHttp\\Psr7\\LimitStream' => $vendorDir . '/guzzlehttp/psr7/src/LimitStream.php',
    'GuzzleHttp\\Psr7\\Message' => $vendorDir . '/guzzlehttp/psr7/src/Message.php',
    'GuzzleHttp\\Psr7\\MessageTrait' => $vendorDir . '/guzzlehttp/psr7/src/MessageTrait.php',
    'GuzzleHttp\\Psr7\\MimeType' => $vendorDir . '/guzzlehttp/psr7/src/MimeType.php',
    'GuzzleHttp\\Psr7\\MultipartStream' => $vendorDir . '/guzzlehttp/psr7/src/MultipartStream.php',
    'GuzzleHttp\\Psr7\\NoSeekStream' => $vendorDir . '/guzzlehttp/psr7/src/NoSeekStream.php',
    'GuzzleHttp\\Psr7\\PumpStream' => $vendorDir . '/guzzlehttp/psr7/src/PumpStream.php',
    'GuzzleHttp\\Psr7\\Query' => $vendorDir . '/guzzlehttp/psr7/src/Query.php',
    'GuzzleHttp\\Psr7\\Request' => $vendorDir . '/guzzlehttp/psr7/src/Request.php',
    'GuzzleHttp\\Psr7\\Response' => $vendorDir . '/guzzlehttp/psr7/src/Response.php',
    'GuzzleHttp\\Psr7\\Rfc7230' => $vendorDir . '/guzzlehttp/psr7/src/Rfc7230.php',
    'GuzzleHttp\\Psr7\\ServerRequest' => $vendorDir . '/guzzlehttp/psr7/src/ServerRequest.php',
    'GuzzleHttp\\Psr7\\Stream' => $vendorDir . '/guzzlehttp/psr7/src/Stream.php',
    'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => $vendorDir . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
    'GuzzleHttp\\Psr7\\StreamWrapper' => $vendorDir . '/guzzlehttp/psr7/src/StreamWrapper.php',
    'GuzzleHttp\\Psr7\\UploadedFile' => $vendorDir . '/guzzlehttp/psr7/src/UploadedFile.php',
    'GuzzleHttp\\Psr7\\Uri' => $vendorDir . '/guzzlehttp/psr7/src/Uri.php',
    'GuzzleHttp\\Psr7\\UriComparator' => $vendorDir . '/guzzlehttp/psr7/src/UriComparator.php',
    'GuzzleHttp\\Psr7\\UriNormalizer' => $vendorDir . '/guzzlehttp/psr7/src/UriNormalizer.php',
    'GuzzleHttp\\Psr7\\UriResolver' => $vendorDir . '/guzzlehttp/psr7/src/UriResolver.php',
    'GuzzleHttp\\Psr7\\Utils' => $vendorDir . '/guzzlehttp/psr7/src/Utils.php',
    'GuzzleHttp\\RedirectMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
    'GuzzleHttp\\RequestOptions' => $vendorDir . '/guzzlehttp/guzzle/src/RequestOptions.php',
    'GuzzleHttp\\RetryMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
    'GuzzleHttp\\TransferStats' => $vendorDir . '/guzzlehttp/guzzle/src/TransferStats.php',
    'GuzzleHttp\\Utils' => $vendorDir . '/guzzlehttp/guzzle/src/Utils.php',
    'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
    'PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php',
    'PHPStan\\PhpDocParser\\Ast\\Attribute' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Attribute.php',
    'PHPStan\\PhpDocParser\\Ast\\Comment' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Comment.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFloatNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNullNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprTrueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php',
    'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\DoctrineConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Node' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Node.php',
    'PHPStan\\PhpDocParser\\Ast\\NodeAttributes' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php',
    'PHPStan\\PhpDocParser\\Ast\\NodeTraverser' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php',
    'PHPStan\\PhpDocParser\\Ast\\NodeVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php',
    'PHPStan\\PhpDocParser\\Ast\\NodeVisitor\\CloningVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagMethodValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagPropertyValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\DeprecatedTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineAnnotation' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArgument' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArray' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArrayItem' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\GenericTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\InvalidTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MixinTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamClosureThisTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PureUnlessCallableIsImpureTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SealedTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ThrowsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypelessParamTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\InvalidTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php',
    'PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php',
    'PHPStan\\PhpDocParser\\Lexer\\Lexer' => $vendorDir . '/phpstan/phpdoc-parser/src/Lexer/Lexer.php',
    'PHPStan\\PhpDocParser\\ParserConfig' => $vendorDir . '/phpstan/phpdoc-parser/src/ParserConfig.php',
    'PHPStan\\PhpDocParser\\Parser\\ConstExprParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php',
    'PHPStan\\PhpDocParser\\Parser\\ParserException' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/ParserException.php',
    'PHPStan\\PhpDocParser\\Parser\\PhpDocParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php',
    'PHPStan\\PhpDocParser\\Parser\\StringUnescaper' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php',
    'PHPStan\\PhpDocParser\\Parser\\TokenIterator' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/TokenIterator.php',
    'PHPStan\\PhpDocParser\\Parser\\TypeParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/TypeParser.php',
    'PHPStan\\PhpDocParser\\Printer\\DiffElem' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/DiffElem.php',
    'PHPStan\\PhpDocParser\\Printer\\Differ' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/Differ.php',
    'PHPStan\\PhpDocParser\\Printer\\Printer' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/Printer.php',
    'PHP_Parallel_Lint\\PhpConsoleColor\\ConsoleColor' => $vendorDir . '/php-parallel-lint/php-console-color/src/ConsoleColor.php',
    'PHP_Parallel_Lint\\PhpConsoleColor\\InvalidStyleException' => $vendorDir . '/php-parallel-lint/php-console-color/src/InvalidStyleException.php',
    'PHP_Parallel_Lint\\PhpConsoleHighlighter\\Highlighter' => $vendorDir . '/php-parallel-lint/php-console-highlighter/src/Highlighter.php',
    'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
    'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
    'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
    'Psr\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/psr/event-dispatcher/src/EventDispatcherInterface.php',
    'Psr\\EventDispatcher\\ListenerProviderInterface' => $vendorDir . '/psr/event-dispatcher/src/ListenerProviderInterface.php',
    'Psr\\EventDispatcher\\StoppableEventInterface' => $vendorDir . '/psr/event-dispatcher/src/StoppableEventInterface.php',
    'Psr\\Http\\Client\\ClientExceptionInterface' => $vendorDir . '/psr/http-client/src/ClientExceptionInterface.php',
    'Psr\\Http\\Client\\ClientInterface' => $vendorDir . '/psr/http-client/src/ClientInterface.php',
    'Psr\\Http\\Client\\NetworkExceptionInterface' => $vendorDir . '/psr/http-client/src/NetworkExceptionInterface.php',
    'Psr\\Http\\Client\\RequestExceptionInterface' => $vendorDir . '/psr/http-client/src/RequestExceptionInterface.php',
    'Psr\\Http\\Message\\MessageInterface' => $vendorDir . '/psr/http-message/src/MessageInterface.php',
    'Psr\\Http\\Message\\RequestFactoryInterface' => $vendorDir . '/psr/http-factory/src/RequestFactoryInterface.php',
    'Psr\\Http\\Message\\RequestInterface' => $vendorDir . '/psr/http-message/src/RequestInterface.php',
    'Psr\\Http\\Message\\ResponseFactoryInterface' => $vendorDir . '/psr/http-factory/src/ResponseFactoryInterface.php',
    'Psr\\Http\\Message\\ResponseInterface' => $vendorDir . '/psr/http-message/src/ResponseInterface.php',
    'Psr\\Http\\Message\\ServerRequestFactoryInterface' => $vendorDir . '/psr/http-factory/src/ServerRequestFactoryInterface.php',
    'Psr\\Http\\Message\\ServerRequestInterface' => $vendorDir . '/psr/http-message/src/ServerRequestInterface.php',
    'Psr\\Http\\Message\\StreamFactoryInterface' => $vendorDir . '/psr/http-factory/src/StreamFactoryInterface.php',
    'Psr\\Http\\Message\\StreamInterface' => $vendorDir . '/psr/http-message/src/StreamInterface.php',
    'Psr\\Http\\Message\\UploadedFileFactoryInterface' => $vendorDir . '/psr/http-factory/src/UploadedFileFactoryInterface.php',
    'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php',
    'Psr\\Http\\Message\\UriFactoryInterface' => $vendorDir . '/psr/http-factory/src/UriFactoryInterface.php',
    'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php',
    'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/src/AbstractLogger.php',
    'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/src/InvalidArgumentException.php',
    'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/src/LogLevel.php',
    'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/src/LoggerAwareInterface.php',
    'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/src/LoggerAwareTrait.php',
    'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/src/LoggerInterface.php',
    'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/src/LoggerTrait.php',
    'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/src/NullLogger.php',
    'Stringy\\CollectionStringy' => $vendorDir . '/bennerinformatics/stringy/src/CollectionStringy.php',
    'Stringy\\StaticStringy' => $vendorDir . '/bennerinformatics/stringy/src/StaticStringy.php',
    'Stringy\\Stringy' => $vendorDir . '/bennerinformatics/stringy/src/Stringy.php',
    'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php',
    'Symfony\\Component\\Console\\Attribute\\AsCommand' => $vendorDir . '/symfony/console/Attribute/AsCommand.php',
    'Symfony\\Component\\Console\\CI\\GithubActionReporter' => $vendorDir . '/symfony/console/CI/GithubActionReporter.php',
    'Symfony\\Component\\Console\\Color' => $vendorDir . '/symfony/console/Color.php',
    'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
    'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
    'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
    'Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php',
    'Symfony\\Component\\Console\\Command\\CompleteCommand' => $vendorDir . '/symfony/console/Command/CompleteCommand.php',
    'Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => $vendorDir . '/symfony/console/Command/DumpCompletionCommand.php',
    'Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php',
    'Symfony\\Component\\Console\\Command\\LazyCommand' => $vendorDir . '/symfony/console/Command/LazyCommand.php',
    'Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php',
    'Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php',
    'Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => $vendorDir . '/symfony/console/Command/SignalableCommandInterface.php',
    'Symfony\\Component\\Console\\Command\\TraceableCommand' => $vendorDir . '/symfony/console/Command/TraceableCommand.php',
    'Symfony\\Component\\Console\\Completion\\CompletionInput' => $vendorDir . '/symfony/console/Completion/CompletionInput.php',
    'Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => $vendorDir . '/symfony/console/Completion/CompletionSuggestions.php',
    'Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/BashCompletionOutput.php',
    'Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => $vendorDir . '/symfony/console/Completion/Output/CompletionOutputInterface.php',
    'Symfony\\Component\\Console\\Completion\\Output\\FishCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/FishCompletionOutput.php',
    'Symfony\\Component\\Console\\Completion\\Output\\ZshCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/ZshCompletionOutput.php',
    'Symfony\\Component\\Console\\Completion\\Suggestion' => $vendorDir . '/symfony/console/Completion/Suggestion.php',
    'Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php',
    'Symfony\\Component\\Console\\Cursor' => $vendorDir . '/symfony/console/Cursor.php',
    'Symfony\\Component\\Console\\DataCollector\\CommandDataCollector' => $vendorDir . '/symfony/console/DataCollector/CommandDataCollector.php',
    'Symfony\\Component\\Console\\Debug\\CliRequest' => $vendorDir . '/symfony/console/Debug/CliRequest.php',
    'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
    'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php',
    'Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php',
    'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php',
    'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php',
    'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php',
    'Symfony\\Component\\Console\\Descriptor\\ReStructuredTextDescriptor' => $vendorDir . '/symfony/console/Descriptor/ReStructuredTextDescriptor.php',
    'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php',
    'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php',
    'Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php',
    'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php',
    'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php',
    'Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php',
    'Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => $vendorDir . '/symfony/console/Event/ConsoleSignalEvent.php',
    'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php',
    'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php',
    'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php',
    'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php',
    'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php',
    'Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php',
    'Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php',
    'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php',
    'Symfony\\Component\\Console\\Exception\\RunCommandFailedException' => $vendorDir . '/symfony/console/Exception/RunCommandFailedException.php',
    'Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php',
    'Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatter.php',
    'Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatterStyle.php',
    'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php',
    'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php',
    'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php',
    'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
    'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
    'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
    'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php',
    'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php',
    'Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php',
    'Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php',
    'Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php',
    'Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php',
    'Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php',
    'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php',
    'Symfony\\Component\\Console\\Helper\\OutputWrapper' => $vendorDir . '/symfony/console/Helper/OutputWrapper.php',
    'Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php',
    'Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php',
    'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php',
    'Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php',
    'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php',
    'Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php',
    'Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php',
    'Symfony\\Component\\Console\\Helper\\TableCellStyle' => $vendorDir . '/symfony/console/Helper/TableCellStyle.php',
    'Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php',
    'Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php',
    'Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php',
    'Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php',
    'Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php',
    'Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php',
    'Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php',
    'Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php',
    'Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php',
    'Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php',
    'Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php',
    'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php',
    'Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php',
    'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php',
    'Symfony\\Component\\Console\\Messenger\\RunCommandContext' => $vendorDir . '/symfony/console/Messenger/RunCommandContext.php',
    'Symfony\\Component\\Console\\Messenger\\RunCommandMessage' => $vendorDir . '/symfony/console/Messenger/RunCommandMessage.php',
    'Symfony\\Component\\Console\\Messenger\\RunCommandMessageHandler' => $vendorDir . '/symfony/console/Messenger/RunCommandMessageHandler.php',
    'Symfony\\Component\\Console\\Output\\AnsiColorMode' => $vendorDir . '/symfony/console/Output/AnsiColorMode.php',
    'Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php',
    'Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php',
    'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php',
    'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php',
    'Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php',
    'Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php',
    'Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php',
    'Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php',
    'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php',
    'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php',
    'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php',
    'Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php',
    'Symfony\\Component\\Console\\SignalRegistry\\SignalMap' => $vendorDir . '/symfony/console/SignalRegistry/SignalMap.php',
    'Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => $vendorDir . '/symfony/console/SignalRegistry/SignalRegistry.php',
    'Symfony\\Component\\Console\\SingleCommandApplication' => $vendorDir . '/symfony/console/SingleCommandApplication.php',
    'Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php',
    'Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php',
    'Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php',
    'Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php',
    'Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php',
    'Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => $vendorDir . '/symfony/console/Tester/CommandCompletionTester.php',
    'Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php',
    'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => $vendorDir . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php',
    'Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php',
    'Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener' => $vendorDir . '/symfony/event-dispatcher/Attribute/AsEventListener.php',
    'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
    'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => $vendorDir . '/symfony/event-dispatcher/Debug/WrappedListener.php',
    'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
    'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => $vendorDir . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
    'Symfony\\Component\\EventDispatcher\\EventDispatcher' => $vendorDir . '/symfony/event-dispatcher/EventDispatcher.php',
    'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher/EventDispatcherInterface.php',
    'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => $vendorDir . '/symfony/event-dispatcher/EventSubscriberInterface.php',
    'Symfony\\Component\\EventDispatcher\\GenericEvent' => $vendorDir . '/symfony/event-dispatcher/GenericEvent.php',
    'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => $vendorDir . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
    'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php',
    'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php',
    'Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php',
    'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/IOExceptionInterface.php',
    'Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/filesystem/Exception/InvalidArgumentException.php',
    'Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => $vendorDir . '/symfony/filesystem/Exception/RuntimeException.php',
    'Symfony\\Component\\Filesystem\\Filesystem' => $vendorDir . '/symfony/filesystem/Filesystem.php',
    'Symfony\\Component\\Filesystem\\Path' => $vendorDir . '/symfony/filesystem/Path.php',
    'Symfony\\Component\\Finder\\Adapter\\AbstractAdapter' => $vendorDir . '/symfony/finder/Adapter/AbstractAdapter.php',
    'Symfony\\Component\\Finder\\Adapter\\AbstractFindAdapter' => $vendorDir . '/symfony/finder/Adapter/AbstractFindAdapter.php',
    'Symfony\\Component\\Finder\\Adapter\\AdapterInterface' => $vendorDir . '/symfony/finder/Adapter/AdapterInterface.php',
    'Symfony\\Component\\Finder\\Adapter\\BsdFindAdapter' => $vendorDir . '/symfony/finder/Adapter/BsdFindAdapter.php',
    'Symfony\\Component\\Finder\\Adapter\\GnuFindAdapter' => $vendorDir . '/symfony/finder/Adapter/GnuFindAdapter.php',
    'Symfony\\Component\\Finder\\Adapter\\PhpAdapter' => $vendorDir . '/symfony/finder/Adapter/PhpAdapter.php',
    'Symfony\\Component\\Finder\\Comparator\\Comparator' => $vendorDir . '/symfony/finder/Comparator/Comparator.php',
    'Symfony\\Component\\Finder\\Comparator\\DateComparator' => $vendorDir . '/symfony/finder/Comparator/DateComparator.php',
    'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => $vendorDir . '/symfony/finder/Comparator/NumberComparator.php',
    'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => $vendorDir . '/symfony/finder/Exception/AccessDeniedException.php',
    'Symfony\\Component\\Finder\\Exception\\AdapterFailureException' => $vendorDir . '/symfony/finder/Exception/AdapterFailureException.php',
    'Symfony\\Component\\Finder\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/finder/Exception/ExceptionInterface.php',
    'Symfony\\Component\\Finder\\Exception\\OperationNotPermitedException' => $vendorDir . '/symfony/finder/Exception/OperationNotPermitedException.php',
    'Symfony\\Component\\Finder\\Exception\\ShellCommandFailureException' => $vendorDir . '/symfony/finder/Exception/ShellCommandFailureException.php',
    'Symfony\\Component\\Finder\\Expression\\Expression' => $vendorDir . '/symfony/finder/Expression/Expression.php',
    'Symfony\\Component\\Finder\\Expression\\Glob' => $vendorDir . '/symfony/finder/Expression/Glob.php',
    'Symfony\\Component\\Finder\\Expression\\Regex' => $vendorDir . '/symfony/finder/Expression/Regex.php',
    'Symfony\\Component\\Finder\\Expression\\ValueInterface' => $vendorDir . '/symfony/finder/Expression/ValueInterface.php',
    'Symfony\\Component\\Finder\\Finder' => $vendorDir . '/symfony/finder/Finder.php',
    'Symfony\\Component\\Finder\\Glob' => $vendorDir . '/symfony/finder/Glob.php',
    'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => $vendorDir . '/symfony/finder/Iterator/CustomFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => $vendorDir . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\FilePathsIterator' => $vendorDir . '/symfony/finder/Iterator/FilePathsIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilenameFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\FilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => $vendorDir . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => $vendorDir . '/symfony/finder/Iterator/PathFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => $vendorDir . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
    'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => $vendorDir . '/symfony/finder/Iterator/SortableIterator.php',
    'Symfony\\Component\\Finder\\Shell\\Command' => $vendorDir . '/symfony/finder/Shell/Command.php',
    'Symfony\\Component\\Finder\\Shell\\Shell' => $vendorDir . '/symfony/finder/Shell/Shell.php',
    'Symfony\\Component\\Finder\\SplFileInfo' => $vendorDir . '/symfony/finder/SplFileInfo.php',
    'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php',
    'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php',
    'Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php',
    'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
    'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php',
    'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
    'Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => $vendorDir . '/symfony/process/Exception/RunProcessFailedException.php',
    'Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
    'Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
    'Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php',
    'Symfony\\Component\\Process\\Messenger\\RunProcessContext' => $vendorDir . '/symfony/process/Messenger/RunProcessContext.php',
    'Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => $vendorDir . '/symfony/process/Messenger/RunProcessMessage.php',
    'Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => $vendorDir . '/symfony/process/Messenger/RunProcessMessageHandler.php',
    'Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
    'Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
    'Symfony\\Component\\Process\\PhpSubprocess' => $vendorDir . '/symfony/process/PhpSubprocess.php',
    'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
    'Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
    'Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',
    'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php',
    'Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php',
    'Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php',
    'Symfony\\Component\\String\\AbstractString' => $vendorDir . '/symfony/string/AbstractString.php',
    'Symfony\\Component\\String\\AbstractUnicodeString' => $vendorDir . '/symfony/string/AbstractUnicodeString.php',
    'Symfony\\Component\\String\\ByteString' => $vendorDir . '/symfony/string/ByteString.php',
    'Symfony\\Component\\String\\CodePointString' => $vendorDir . '/symfony/string/CodePointString.php',
    'Symfony\\Component\\String\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/string/Exception/ExceptionInterface.php',
    'Symfony\\Component\\String\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/string/Exception/InvalidArgumentException.php',
    'Symfony\\Component\\String\\Exception\\RuntimeException' => $vendorDir . '/symfony/string/Exception/RuntimeException.php',
    'Symfony\\Component\\String\\Inflector\\EnglishInflector' => $vendorDir . '/symfony/string/Inflector/EnglishInflector.php',
    'Symfony\\Component\\String\\Inflector\\FrenchInflector' => $vendorDir . '/symfony/string/Inflector/FrenchInflector.php',
    'Symfony\\Component\\String\\Inflector\\InflectorInterface' => $vendorDir . '/symfony/string/Inflector/InflectorInterface.php',
    'Symfony\\Component\\String\\Inflector\\SpanishInflector' => $vendorDir . '/symfony/string/Inflector/SpanishInflector.php',
    'Symfony\\Component\\String\\LazyString' => $vendorDir . '/symfony/string/LazyString.php',
    'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php',
    'Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php',
    'Symfony\\Component\\String\\TruncateMode' => $vendorDir . '/symfony/string/TruncateMode.php',
    'Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php',
    'Symfony\\Contracts\\EventDispatcher\\Event' => $vendorDir . '/symfony/event-dispatcher-contracts/Event.php',
    'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => $vendorDir . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
    'Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php',
    'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php',
    'Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
    'Symfony\\Contracts\\Service\\ServiceCollectionInterface' => $vendorDir . '/symfony/service-contracts/ServiceCollectionInterface.php',
    'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
    'Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceMethodsSubscriberTrait.php',
    'Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
    'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
    'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
    'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
    'Symfony\\Polyfill\\Iconv\\Iconv' => $vendorDir . '/symfony/polyfill-iconv/Iconv.php',
    'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => $vendorDir . '/symfony/polyfill-intl-grapheme/Grapheme.php',
    'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php',
    'Symfony\\Polyfill\\Intl\\Idn\\Info' => $vendorDir . '/symfony/polyfill-intl-idn/Info.php',
    'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
    'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
    'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
    'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
    'Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php',
    'Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php',
    'Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php',
    'phpDocumentor\\Reflection\\DocBlock' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock.php',
    'phpDocumentor\\Reflection\\DocBlockFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php',
    'phpDocumentor\\Reflection\\DocBlockFactoryInterface' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php',
    'phpDocumentor\\Reflection\\DocBlock\\Description' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php',
    'phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php',
    'phpDocumentor\\Reflection\\DocBlock\\Serializer' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php',
    'phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php',
    'phpDocumentor\\Reflection\\DocBlock\\TagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Extends_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Extends_.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\AbstractPHPStanFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ExtendsFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ExtendsFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\Factory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ImplementsFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ImplementsFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodParameterFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodParameterFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PHPStanFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ParamFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyReadFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyWriteFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ReturnFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateExtendsFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateExtendsFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateImplementsFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateImplementsFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\VarFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Implements_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Implements_.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\MethodParameter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Mixin' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Mixin.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Template' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Template.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateCovariant' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateCovariant.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateExtends' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateExtends.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateImplements' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateImplements.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php',
    'phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php',
    'phpDocumentor\\Reflection\\Element' => $vendorDir . '/phpdocumentor/reflection-common/src/Element.php',
    'phpDocumentor\\Reflection\\Exception\\PcreException' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php',
    'phpDocumentor\\Reflection\\File' => $vendorDir . '/phpdocumentor/reflection-common/src/File.php',
    'phpDocumentor\\Reflection\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-common/src/Fqsen.php',
    'phpDocumentor\\Reflection\\FqsenResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/FqsenResolver.php',
    'phpDocumentor\\Reflection\\Location' => $vendorDir . '/phpdocumentor/reflection-common/src/Location.php',
    'phpDocumentor\\Reflection\\Project' => $vendorDir . '/phpdocumentor/reflection-common/src/Project.php',
    'phpDocumentor\\Reflection\\ProjectFactory' => $vendorDir . '/phpdocumentor/reflection-common/src/ProjectFactory.php',
    'phpDocumentor\\Reflection\\PseudoType' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoType.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ArrayShape' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ArrayShapeItem' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ConstExpression' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\False_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\FloatValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\IntegerRange' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\IntegerValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ListShape' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ListShape.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ListShapeItem' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ListShapeItem.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\List_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/List_.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NegativeInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyArray' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyArray.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyList' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\Numeric_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ObjectShape' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShape.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ObjectShapeItem' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShapeItem.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\ShapeItem' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ShapeItem.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\StringValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php',
    'phpDocumentor\\Reflection\\PseudoTypes\\True_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php',
    'phpDocumentor\\Reflection\\Type' => $vendorDir . '/phpdocumentor/type-resolver/src/Type.php',
    'phpDocumentor\\Reflection\\TypeResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/TypeResolver.php',
    'phpDocumentor\\Reflection\\Types\\AbstractList' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AbstractList.php',
    'phpDocumentor\\Reflection\\Types\\AggregatedType' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php',
    'phpDocumentor\\Reflection\\Types\\ArrayKey' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php',
    'phpDocumentor\\Reflection\\Types\\Array_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Array_.php',
    'phpDocumentor\\Reflection\\Types\\Boolean' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Boolean.php',
    'phpDocumentor\\Reflection\\Types\\CallableParameter' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/CallableParameter.php',
    'phpDocumentor\\Reflection\\Types\\Callable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Callable_.php',
    'phpDocumentor\\Reflection\\Types\\ClassString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ClassString.php',
    'phpDocumentor\\Reflection\\Types\\Collection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Collection.php',
    'phpDocumentor\\Reflection\\Types\\Compound' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Compound.php',
    'phpDocumentor\\Reflection\\Types\\Context' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Context.php',
    'phpDocumentor\\Reflection\\Types\\ContextFactory' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php',
    'phpDocumentor\\Reflection\\Types\\Expression' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Expression.php',
    'phpDocumentor\\Reflection\\Types\\Float_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Float_.php',
    'phpDocumentor\\Reflection\\Types\\Integer' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Integer.php',
    'phpDocumentor\\Reflection\\Types\\InterfaceString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php',
    'phpDocumentor\\Reflection\\Types\\Intersection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Intersection.php',
    'phpDocumentor\\Reflection\\Types\\Iterable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Iterable_.php',
    'phpDocumentor\\Reflection\\Types\\Mixed_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Mixed_.php',
    'phpDocumentor\\Reflection\\Types\\Never_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Never_.php',
    'phpDocumentor\\Reflection\\Types\\Null_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Null_.php',
    'phpDocumentor\\Reflection\\Types\\Nullable' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Nullable.php',
    'phpDocumentor\\Reflection\\Types\\Object_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Object_.php',
    'phpDocumentor\\Reflection\\Types\\Parent_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Parent_.php',
    'phpDocumentor\\Reflection\\Types\\Resource_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Resource_.php',
    'phpDocumentor\\Reflection\\Types\\Scalar' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Scalar.php',
    'phpDocumentor\\Reflection\\Types\\Self_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Self_.php',
    'phpDocumentor\\Reflection\\Types\\Static_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Static_.php',
    'phpDocumentor\\Reflection\\Types\\String_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/String_.php',
    'phpDocumentor\\Reflection\\Types\\This' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/This.php',
    'phpDocumentor\\Reflection\\Types\\Void_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Void_.php',
    'phpDocumentor\\Reflection\\Utils' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Utils.php',
    'voku\\helper\\ASCII' => $vendorDir . '/voku/portable-ascii/src/voku/helper/ASCII.php',
    'voku\\helper\\AntiXSS' => $vendorDir . '/voku/anti-xss/src/voku/helper/AntiXSS.php',
    'voku\\helper\\Bootup' => $vendorDir . '/voku/portable-utf8/src/voku/helper/Bootup.php',
    'voku\\helper\\EmailCheck' => $vendorDir . '/voku/email-check/src/voku/helper/EmailCheck.php',
    'voku\\helper\\StopWords' => $vendorDir . '/voku/stop-words/src/voku/helper/StopWords.php',
    'voku\\helper\\StopWordsLanguageNotExists' => $vendorDir . '/voku/stop-words/src/voku/helper/StopWordsLanguageNotExists.php',
    'voku\\helper\\URLify' => $vendorDir . '/voku/urlify/src/voku/helper/URLify.php',
    'voku\\helper\\UTF8' => $vendorDir . '/voku/portable-utf8/src/voku/helper/UTF8.php',
);
<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
    'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
    '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
    'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
    'b46ad4fe52f4d1899a2951c7e6ea56b0' => $vendorDir . '/voku/portable-utf8/bootstrap.php',
    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
    '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
    'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
    'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
    '65380ab4d81167209b0a4fac46641984' => $vendorDir . '/voku/arrayy/src/Create.php',
    'e59173834a401a678a2c28192c24218d' => $vendorDir . '/bennerinformatics/php-path/path.php',
    '7ee43ea039522dc57cc84ff774473eb6' => $vendorDir . '/bennerinformatics/stringy/src/Create.php',
    '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
    'b45b351e6b6f7487d819961fef2fda77' => $vendorDir . '/jakeasmith/http_build_url/src/http_build_url.php',
    '940abd8fb01ee76a36b44f35dcf9783b' => $vendorDir . '/weew/helpers-array/src/array.php',
);
<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
);
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'voku\\helper\\' => array($vendorDir . '/voku/urlify/src/voku/helper', $vendorDir . '/voku/email-check/src/voku/helper', $vendorDir . '/voku/anti-xss/src/voku/helper'),
    'voku\\' => array($vendorDir . '/voku/stop-words/src/voku', $vendorDir . '/voku/portable-utf8/src/voku', $vendorDir . '/voku/portable-ascii/src/voku'),
    'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src', $vendorDir . '/phpdocumentor/reflection-common/src'),
    'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
    'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
    'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
    'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
    'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'),
    'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'),
    'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
    'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
    'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'),
    'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
    'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
    'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
    'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
    'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
    'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
    'Stringy\\' => array($vendorDir . '/bennerinformatics/stringy/src'),
    'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
    'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
    'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
    'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
    'PHP_Parallel_Lint\\PhpConsoleHighlighter\\' => array($vendorDir . '/php-parallel-lint/php-console-highlighter/src'),
    'PHP_Parallel_Lint\\PhpConsoleColor\\' => array($vendorDir . '/php-parallel-lint/php-console-color/src'),
    'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'),
    'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
    'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
    'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
    'FW\\Installer\\' => array($baseDir . '/src'),
    'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/src'),
    'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'),
    'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
    'Bit3\\GitPhp\\' => array($vendorDir . '/bit3/git-php/src'),
    'Arrayy\\' => array($vendorDir . '/voku/arrayy/src'),
);
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit99acc0ea0763a3d8cd50e9c30b597c03
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        require __DIR__ . '/platform_check.php';

        spl_autoload_register(array('ComposerAutoloaderInit99acc0ea0763a3d8cd50e9c30b597c03', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInit99acc0ea0763a3d8cd50e9c30b597c03', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03::getInitializer($loader));

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        $filesToLoad = \Composer\Autoload\ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03::$files;
        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

                require $file;
            }
        }, null, null);
        foreach ($filesToLoad as $fileIdentifier => $file) {
            $requireFile($fileIdentifier, $file);
        }

        return $loader;
    }
}
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03
{
    public static $files = array (
        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
        'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
        '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
        'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
        'b46ad4fe52f4d1899a2951c7e6ea56b0' => __DIR__ . '/..' . '/voku/portable-utf8/bootstrap.php',
        '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
        '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
        'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
        'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
        '65380ab4d81167209b0a4fac46641984' => __DIR__ . '/..' . '/voku/arrayy/src/Create.php',
        'e59173834a401a678a2c28192c24218d' => __DIR__ . '/..' . '/bennerinformatics/php-path/path.php',
        '7ee43ea039522dc57cc84ff774473eb6' => __DIR__ . '/..' . '/bennerinformatics/stringy/src/Create.php',
        '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
        'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php',
        '940abd8fb01ee76a36b44f35dcf9783b' => __DIR__ . '/..' . '/weew/helpers-array/src/array.php',
    );

    public static $prefixLengthsPsr4 = array (
        'v' =>
        array (
            'voku\\helper\\' => 12,
            'voku\\' => 5,
        ),
        'p' =>
        array (
            'phpDocumentor\\Reflection\\' => 25,
        ),
        'W' =>
        array (
            'Webmozart\\Assert\\' => 17,
        ),
        'S' =>
        array (
            'Symfony\\Polyfill\\Mbstring\\' => 26,
            'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
            'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
            'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31,
            'Symfony\\Polyfill\\Iconv\\' => 23,
            'Symfony\\Polyfill\\Ctype\\' => 23,
            'Symfony\\Contracts\\Service\\' => 26,
            'Symfony\\Contracts\\EventDispatcher\\' => 34,
            'Symfony\\Component\\String\\' => 25,
            'Symfony\\Component\\Process\\' => 26,
            'Symfony\\Component\\Finder\\' => 25,
            'Symfony\\Component\\Filesystem\\' => 29,
            'Symfony\\Component\\EventDispatcher\\' => 34,
            'Symfony\\Component\\Console\\' => 26,
            'Stringy\\' => 8,
        ),
        'P' =>
        array (
            'Psr\\Log\\' => 8,
            'Psr\\Http\\Message\\' => 17,
            'Psr\\Http\\Client\\' => 16,
            'Psr\\EventDispatcher\\' => 20,
            'Psr\\Container\\' => 14,
            'PHP_Parallel_Lint\\PhpConsoleHighlighter\\' => 40,
            'PHP_Parallel_Lint\\PhpConsoleColor\\' => 34,
            'PHPStan\\PhpDocParser\\' => 21,
        ),
        'G' =>
        array (
            'GuzzleHttp\\Psr7\\' => 16,
            'GuzzleHttp\\Promise\\' => 19,
            'GuzzleHttp\\' => 11,
        ),
        'F' =>
        array (
            'FW\\Installer\\' => 13,
        ),
        'D' =>
        array (
            'Doctrine\\Deprecations\\' => 22,
            'Defuse\\Crypto\\' => 14,
        ),
        'C' =>
        array (
            'Composer\\Semver\\' => 16,
        ),
        'B' =>
        array (
            'Bit3\\GitPhp\\' => 12,
        ),
        'A' =>
        array (
            'Arrayy\\' => 7,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'voku\\helper\\' =>
        array (
            0 => __DIR__ . '/..' . '/voku/urlify/src/voku/helper',
            1 => __DIR__ . '/..' . '/voku/email-check/src/voku/helper',
            2 => __DIR__ . '/..' . '/voku/anti-xss/src/voku/helper',
        ),
        'voku\\' =>
        array (
            0 => __DIR__ . '/..' . '/voku/stop-words/src/voku',
            1 => __DIR__ . '/..' . '/voku/portable-utf8/src/voku',
            2 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
        ),
        'phpDocumentor\\Reflection\\' =>
        array (
            0 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
            1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
            2 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
        ),
        'Webmozart\\Assert\\' =>
        array (
            0 => __DIR__ . '/..' . '/webmozart/assert/src',
        ),
        'Symfony\\Polyfill\\Mbstring\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
        ),
        'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
        ),
        'Symfony\\Polyfill\\Intl\\Idn\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
        ),
        'Symfony\\Polyfill\\Intl\\Grapheme\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme',
        ),
        'Symfony\\Polyfill\\Iconv\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-iconv',
        ),
        'Symfony\\Polyfill\\Ctype\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
        ),
        'Symfony\\Contracts\\Service\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/service-contracts',
        ),
        'Symfony\\Contracts\\EventDispatcher\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts',
        ),
        'Symfony\\Component\\String\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/string',
        ),
        'Symfony\\Component\\Process\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/process',
        ),
        'Symfony\\Component\\Finder\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/finder',
        ),
        'Symfony\\Component\\Filesystem\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/filesystem',
        ),
        'Symfony\\Component\\EventDispatcher\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
        ),
        'Symfony\\Component\\Console\\' =>
        array (
            0 => __DIR__ . '/..' . '/symfony/console',
        ),
        'Stringy\\' =>
        array (
            0 => __DIR__ . '/..' . '/bennerinformatics/stringy/src',
        ),
        'Psr\\Log\\' =>
        array (
            0 => __DIR__ . '/..' . '/psr/log/src',
        ),
        'Psr\\Http\\Message\\' =>
        array (
            0 => __DIR__ . '/..' . '/psr/http-factory/src',
            1 => __DIR__ . '/..' . '/psr/http-message/src',
        ),
        'Psr\\Http\\Client\\' =>
        array (
            0 => __DIR__ . '/..' . '/psr/http-client/src',
        ),
        'Psr\\EventDispatcher\\' =>
        array (
            0 => __DIR__ . '/..' . '/psr/event-dispatcher/src',
        ),
        'Psr\\Container\\' =>
        array (
            0 => __DIR__ . '/..' . '/psr/container/src',
        ),
        'PHP_Parallel_Lint\\PhpConsoleHighlighter\\' =>
        array (
            0 => __DIR__ . '/..' . '/php-parallel-lint/php-console-highlighter/src',
        ),
        'PHP_Parallel_Lint\\PhpConsoleColor\\' =>
        array (
            0 => __DIR__ . '/..' . '/php-parallel-lint/php-console-color/src',
        ),
        'PHPStan\\PhpDocParser\\' =>
        array (
            0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src',
        ),
        'GuzzleHttp\\Psr7\\' =>
        array (
            0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
        ),
        'GuzzleHttp\\Promise\\' =>
        array (
            0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
        ),
        'GuzzleHttp\\' =>
        array (
            0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
        ),
        'FW\\Installer\\' =>
        array (
            0 => __DIR__ . '/../..' . '/src',
        ),
        'Doctrine\\Deprecations\\' =>
        array (
            0 => __DIR__ . '/..' . '/doctrine/deprecations/src',
        ),
        'Defuse\\Crypto\\' =>
        array (
            0 => __DIR__ . '/..' . '/defuse/php-encryption/src',
        ),
        'Composer\\Semver\\' =>
        array (
            0 => __DIR__ . '/..' . '/composer/semver/src',
        ),
        'Bit3\\GitPhp\\' =>
        array (
            0 => __DIR__ . '/..' . '/bit3/git-php/src',
        ),
        'Arrayy\\' =>
        array (
            0 => __DIR__ . '/..' . '/voku/arrayy/src',
        ),
    );

    public static $classMap = array (
        'Arrayy\\Arrayy' => __DIR__ . '/..' . '/voku/arrayy/src/Arrayy.php',
        'Arrayy\\ArrayyIterator' => __DIR__ . '/..' . '/voku/arrayy/src/ArrayyIterator.php',
        'Arrayy\\ArrayyMeta' => __DIR__ . '/..' . '/voku/arrayy/src/ArrayyMeta.php',
        'Arrayy\\ArrayyRewindableExtendedGenerator' => __DIR__ . '/..' . '/voku/arrayy/src/ArrayyRewindableExtendedGenerator.php',
        'Arrayy\\ArrayyRewindableGenerator' => __DIR__ . '/..' . '/voku/arrayy/src/ArrayyRewindableGenerator.php',
        'Arrayy\\ArrayyStrict' => __DIR__ . '/..' . '/voku/arrayy/src/ArrayyStrict.php',
        'Arrayy\\Collection\\AbstractCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Collection/AbstractCollection.php',
        'Arrayy\\Collection\\Collection' => __DIR__ . '/..' . '/voku/arrayy/src/Collection/Collection.php',
        'Arrayy\\Collection\\CollectionInterface' => __DIR__ . '/..' . '/voku/arrayy/src/Collection/CollectionInterface.php',
        'Arrayy\\Mapper\\Json' => __DIR__ . '/..' . '/voku/arrayy/src/Mapper/Json.php',
        'Arrayy\\StaticArrayy' => __DIR__ . '/..' . '/voku/arrayy/src/StaticArrayy.php',
        'Arrayy\\TypeCheck\\AbstractTypeCheck' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/AbstractTypeCheck.php',
        'Arrayy\\TypeCheck\\TypeCheckArray' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/TypeCheckArray.php',
        'Arrayy\\TypeCheck\\TypeCheckCallback' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/TypeCheckCallback.php',
        'Arrayy\\TypeCheck\\TypeCheckInterface' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/TypeCheckInterface.php',
        'Arrayy\\TypeCheck\\TypeCheckPhpDoc' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/TypeCheckPhpDoc.php',
        'Arrayy\\TypeCheck\\TypeCheckSimple' => __DIR__ . '/..' . '/voku/arrayy/src/TypeCheck/TypeCheckSimple.php',
        'Arrayy\\Type\\ArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/ArrayCollection.php',
        'Arrayy\\Type\\BoolArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/BoolArrayCollection.php',
        'Arrayy\\Type\\BoolCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/BoolCollection.php',
        'Arrayy\\Type\\CallableCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/CallableCollection.php',
        'Arrayy\\Type\\DetectFirstValueTypeCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/DetectFirstValueTypeCollection.php',
        'Arrayy\\Type\\FloatArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/FloatArrayCollection.php',
        'Arrayy\\Type\\FloatCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/FloatCollection.php',
        'Arrayy\\Type\\FloatIntArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/FloatIntArrayCollection.php',
        'Arrayy\\Type\\FloatIntCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/FloatIntCollection.php',
        'Arrayy\\Type\\InstanceCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/InstanceCollection.php',
        'Arrayy\\Type\\InstancesCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/InstancesCollection.php',
        'Arrayy\\Type\\IntArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/IntArrayCollection.php',
        'Arrayy\\Type\\IntCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/IntCollection.php',
        'Arrayy\\Type\\JsonSerializableCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/JsonSerializableCollection.php',
        'Arrayy\\Type\\MixedCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/MixedCollection.php',
        'Arrayy\\Type\\NonEmptyStringCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/NonEmptyStringCollection.php',
        'Arrayy\\Type\\NumericCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/NumericCollection.php',
        'Arrayy\\Type\\NumericStringCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/NumericStringCollection.php',
        'Arrayy\\Type\\ObjectCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/ObjectCollection.php',
        'Arrayy\\Type\\ResourceCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/ResourceCollection.php',
        'Arrayy\\Type\\ScalarCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/ScalarCollection.php',
        'Arrayy\\Type\\StdClassCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/StdClassCollection.php',
        'Arrayy\\Type\\StringArrayCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/StringArrayCollection.php',
        'Arrayy\\Type\\StringCollection' => __DIR__ . '/..' . '/voku/arrayy/src/Type/StringCollection.php',
        'Arrayy\\Type\\TypeInterface' => __DIR__ . '/..' . '/voku/arrayy/src/Type/TypeInterface.php',
        'Bit3\\GitPhp\\Command\\AbstractCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/AbstractCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\AddCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/AddCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\BranchCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/BranchCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\CheckoutCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/CheckoutCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\CloneCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/CloneCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\CommandBuilderInterface' => __DIR__ . '/..' . '/bit3/git-php/src/Command/CommandBuilderInterface.php',
        'Bit3\\GitPhp\\Command\\CommandBuilderTrait' => __DIR__ . '/..' . '/bit3/git-php/src/Command/CommandBuilderTrait.php',
        'Bit3\\GitPhp\\Command\\CommitCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/CommitCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\ConfigCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/ConfigCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\DescribeCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/DescribeCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\FetchCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/FetchCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\InitCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/InitCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\LogCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/LogCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\LsRemoteCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/LsRemoteCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\MergeCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/MergeCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\PullCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/PullCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\PushCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/PushCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\RemoteCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/RemoteCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\ResetCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/ResetCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\RevParseCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/RevParseCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\RmCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/RmCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\ShortLogCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/ShortLogCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\ShowCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/ShowCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\StashCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/StashCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\StatusCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/StatusCommandBuilder.php',
        'Bit3\\GitPhp\\Command\\TagCommandBuilder' => __DIR__ . '/..' . '/bit3/git-php/src/Command/TagCommandBuilder.php',
        'Bit3\\GitPhp\\GitConfig' => __DIR__ . '/..' . '/bit3/git-php/src/GitConfig.php',
        'Bit3\\GitPhp\\GitException' => __DIR__ . '/..' . '/bit3/git-php/src/GitException.php',
        'Bit3\\GitPhp\\GitRepository' => __DIR__ . '/..' . '/bit3/git-php/src/GitRepository.php',
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
        'Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php',
        'Composer\\Semver\\Constraint\\AbstractConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/AbstractConstraint.php',
        'Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php',
        'Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php',
        'Composer\\Semver\\Constraint\\EmptyConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/EmptyConstraint.php',
        'Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php',
        'Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php',
        'Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php',
        'Defuse\\Crypto\\Core' => __DIR__ . '/..' . '/defuse/php-encryption/src/Core.php',
        'Defuse\\Crypto\\Crypto' => __DIR__ . '/..' . '/defuse/php-encryption/src/Crypto.php',
        'Defuse\\Crypto\\DerivedKeys' => __DIR__ . '/..' . '/defuse/php-encryption/src/DerivedKeys.php',
        'Defuse\\Crypto\\Encoding' => __DIR__ . '/..' . '/defuse/php-encryption/src/Encoding.php',
        'Defuse\\Crypto\\Exception\\BadFormatException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/BadFormatException.php',
        'Defuse\\Crypto\\Exception\\CryptoException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/CryptoException.php',
        'Defuse\\Crypto\\Exception\\EnvironmentIsBrokenException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php',
        'Defuse\\Crypto\\Exception\\IOException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/IOException.php',
        'Defuse\\Crypto\\Exception\\WrongKeyOrModifiedCiphertextException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php',
        'Defuse\\Crypto\\File' => __DIR__ . '/..' . '/defuse/php-encryption/src/File.php',
        'Defuse\\Crypto\\Key' => __DIR__ . '/..' . '/defuse/php-encryption/src/Key.php',
        'Defuse\\Crypto\\KeyOrPassword' => __DIR__ . '/..' . '/defuse/php-encryption/src/KeyOrPassword.php',
        'Defuse\\Crypto\\KeyProtectedByPassword' => __DIR__ . '/..' . '/defuse/php-encryption/src/KeyProtectedByPassword.php',
        'Defuse\\Crypto\\RuntimeTests' => __DIR__ . '/..' . '/defuse/php-encryption/src/RuntimeTests.php',
        'Doctrine\\Deprecations\\Deprecation' => __DIR__ . '/..' . '/doctrine/deprecations/src/Deprecation.php',
        'Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => __DIR__ . '/..' . '/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php',
        'FW\\Installer\\App' => __DIR__ . '/../..' . '/src/App.php',
        'FW\\Installer\\Command\\Addon' => __DIR__ . '/../..' . '/src/Command/Addon.php',
        'FW\\Installer\\Command\\BaseCommand' => __DIR__ . '/../..' . '/src/Command/BaseCommand.php',
        'FW\\Installer\\Command\\Install' => __DIR__ . '/../..' . '/src/Command/Install.php',
        'FW\\Installer\\Command\\Login' => __DIR__ . '/../..' . '/src/Command/Login.php',
        'FW\\Installer\\Command\\Publish' => __DIR__ . '/../..' . '/src/Command/Publish.php',
        'FW\\Installer\\Command\\SelfUpdate' => __DIR__ . '/../..' . '/src/Command/SelfUpdate.php',
        'FW\\Installer\\Command\\Setup' => __DIR__ . '/../..' . '/src/Command/Setup.php',
        'FW\\Installer\\Command\\Task' => __DIR__ . '/../..' . '/src/Command/Task.php',
        'FW\\Installer\\Command\\Update' => __DIR__ . '/../..' . '/src/Command/Update.php',
        'FW\\Installer\\Helpers\\Process' => __DIR__ . '/../..' . '/src/Helpers/Process.php',
        'FW\\Installer\\Helpers\\Prompt' => __DIR__ . '/../..' . '/src/Helpers/Prompt.php',
        'FW\\Installer\\Providers\\BaseProvider' => __DIR__ . '/../..' . '/src/Providers/BaseProvider.php',
        'FW\\Installer\\Providers\\Bitbucket' => __DIR__ . '/../..' . '/src/Providers/Bitbucket.php',
        'FW\\Installer\\Providers\\Github' => __DIR__ . '/../..' . '/src/Providers/Github.php',
        'FW\\Installer\\Task\\AbstractTask' => __DIR__ . '/../..' . '/src/Task/AbstractTask.php',
        'FW\\Installer\\Task\\Addon' => __DIR__ . '/../..' . '/src/Task/Addon.php',
        'FW\\Installer\\Task\\Assets' => __DIR__ . '/../..' . '/src/Task/Assets.php',
        'FW\\Installer\\Task\\Composer' => __DIR__ . '/../..' . '/src/Task/Composer.php',
        'FW\\Installer\\Task\\Download' => __DIR__ . '/../..' . '/src/Task/Download.php',
        'FW\\Installer\\Task\\GitClone' => __DIR__ . '/../..' . '/src/Task/GitClone.php',
        'FW\\Installer\\Utils\\AppInstall' => __DIR__ . '/../..' . '/src/Utils/AppInstall.php',
        'FW\\Installer\\Utils\\CommandException' => __DIR__ . '/../..' . '/src/Utils/CommandException.php',
        'FW\\Installer\\Utils\\Config' => __DIR__ . '/../..' . '/src/Utils/Config.php',
        'FW\\Installer\\Utils\\Dependencies' => __DIR__ . '/../..' . '/src/Utils/Dependencies.php',
        'FW\\Installer\\Utils\\ErrorHandler' => __DIR__ . '/../..' . '/src/Utils/ErrorHandler.php',
        'FW\\Installer\\Utils\\File' => __DIR__ . '/../..' . '/src/Utils/File.php',
        'FW\\Installer\\Utils\\Registry' => __DIR__ . '/../..' . '/src/Utils/Registry.php',
        'FW\\Installer\\Utils\\RunContext' => __DIR__ . '/../..' . '/src/Utils/RunContext.php',
        'FW\\Installer\\Utils\\SystemConfig' => __DIR__ . '/../..' . '/src/Utils/SystemConfig.php',
        'FW\\Installer\\Utils\\Updater' => __DIR__ . '/../..' . '/src/Utils/Updater.php',
        'FW\\Installer\\Utils\\VersionUtils' => __DIR__ . '/../..' . '/src/Utils/VersionUtils.php',
        'GuzzleHttp\\BodySummarizer' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/BodySummarizer.php',
        'GuzzleHttp\\BodySummarizerInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/BodySummarizerInterface.php',
        'GuzzleHttp\\Client' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Client.php',
        'GuzzleHttp\\ClientInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/ClientInterface.php',
        'GuzzleHttp\\ClientTrait' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/ClientTrait.php',
        'GuzzleHttp\\Cookie\\CookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
        'GuzzleHttp\\Cookie\\CookieJarInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
        'GuzzleHttp\\Cookie\\FileCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
        'GuzzleHttp\\Cookie\\SessionCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
        'GuzzleHttp\\Cookie\\SetCookie' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
        'GuzzleHttp\\Exception\\BadResponseException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
        'GuzzleHttp\\Exception\\ClientException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
        'GuzzleHttp\\Exception\\ConnectException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
        'GuzzleHttp\\Exception\\GuzzleException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
        'GuzzleHttp\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php',
        'GuzzleHttp\\Exception\\RequestException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
        'GuzzleHttp\\Exception\\ServerException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
        'GuzzleHttp\\Exception\\TooManyRedirectsException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
        'GuzzleHttp\\Exception\\TransferException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
        'GuzzleHttp\\HandlerStack' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/HandlerStack.php',
        'GuzzleHttp\\Handler\\CurlFactory' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
        'GuzzleHttp\\Handler\\CurlFactoryInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
        'GuzzleHttp\\Handler\\CurlHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
        'GuzzleHttp\\Handler\\CurlMultiHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
        'GuzzleHttp\\Handler\\EasyHandle' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
        'GuzzleHttp\\Handler\\HeaderProcessor' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php',
        'GuzzleHttp\\Handler\\MockHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
        'GuzzleHttp\\Handler\\Proxy' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
        'GuzzleHttp\\Handler\\StreamHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
        'GuzzleHttp\\MessageFormatter' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/MessageFormatter.php',
        'GuzzleHttp\\MessageFormatterInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/MessageFormatterInterface.php',
        'GuzzleHttp\\Middleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Middleware.php',
        'GuzzleHttp\\Pool' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Pool.php',
        'GuzzleHttp\\PrepareBodyMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
        'GuzzleHttp\\Promise\\AggregateException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/AggregateException.php',
        'GuzzleHttp\\Promise\\CancellationException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/CancellationException.php',
        'GuzzleHttp\\Promise\\Coroutine' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Coroutine.php',
        'GuzzleHttp\\Promise\\Create' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Create.php',
        'GuzzleHttp\\Promise\\Each' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Each.php',
        'GuzzleHttp\\Promise\\EachPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/EachPromise.php',
        'GuzzleHttp\\Promise\\FulfilledPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/FulfilledPromise.php',
        'GuzzleHttp\\Promise\\Is' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Is.php',
        'GuzzleHttp\\Promise\\Promise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Promise.php',
        'GuzzleHttp\\Promise\\PromiseInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromiseInterface.php',
        'GuzzleHttp\\Promise\\PromisorInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromisorInterface.php',
        'GuzzleHttp\\Promise\\RejectedPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectedPromise.php',
        'GuzzleHttp\\Promise\\RejectionException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectionException.php',
        'GuzzleHttp\\Promise\\TaskQueue' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueue.php',
        'GuzzleHttp\\Promise\\TaskQueueInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueueInterface.php',
        'GuzzleHttp\\Promise\\Utils' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Utils.php',
        'GuzzleHttp\\Psr7\\AppendStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/AppendStream.php',
        'GuzzleHttp\\Psr7\\BufferStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/BufferStream.php',
        'GuzzleHttp\\Psr7\\CachingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/CachingStream.php',
        'GuzzleHttp\\Psr7\\DroppingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/DroppingStream.php',
        'GuzzleHttp\\Psr7\\Exception\\MalformedUriException' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Exception/MalformedUriException.php',
        'GuzzleHttp\\Psr7\\FnStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/FnStream.php',
        'GuzzleHttp\\Psr7\\Header' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Header.php',
        'GuzzleHttp\\Psr7\\HttpFactory' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/HttpFactory.php',
        'GuzzleHttp\\Psr7\\InflateStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/InflateStream.php',
        'GuzzleHttp\\Psr7\\LazyOpenStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LazyOpenStream.php',
        'GuzzleHttp\\Psr7\\LimitStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LimitStream.php',
        'GuzzleHttp\\Psr7\\Message' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Message.php',
        'GuzzleHttp\\Psr7\\MessageTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MessageTrait.php',
        'GuzzleHttp\\Psr7\\MimeType' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MimeType.php',
        'GuzzleHttp\\Psr7\\MultipartStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MultipartStream.php',
        'GuzzleHttp\\Psr7\\NoSeekStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/NoSeekStream.php',
        'GuzzleHttp\\Psr7\\PumpStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/PumpStream.php',
        'GuzzleHttp\\Psr7\\Query' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Query.php',
        'GuzzleHttp\\Psr7\\Request' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Request.php',
        'GuzzleHttp\\Psr7\\Response' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Response.php',
        'GuzzleHttp\\Psr7\\Rfc7230' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Rfc7230.php',
        'GuzzleHttp\\Psr7\\ServerRequest' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/ServerRequest.php',
        'GuzzleHttp\\Psr7\\Stream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Stream.php',
        'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
        'GuzzleHttp\\Psr7\\StreamWrapper' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamWrapper.php',
        'GuzzleHttp\\Psr7\\UploadedFile' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UploadedFile.php',
        'GuzzleHttp\\Psr7\\Uri' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Uri.php',
        'GuzzleHttp\\Psr7\\UriComparator' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriComparator.php',
        'GuzzleHttp\\Psr7\\UriNormalizer' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriNormalizer.php',
        'GuzzleHttp\\Psr7\\UriResolver' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriResolver.php',
        'GuzzleHttp\\Psr7\\Utils' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Utils.php',
        'GuzzleHttp\\RedirectMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
        'GuzzleHttp\\RequestOptions' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RequestOptions.php',
        'GuzzleHttp\\RetryMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
        'GuzzleHttp\\TransferStats' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/TransferStats.php',
        'GuzzleHttp\\Utils' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Utils.php',
        'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
        'PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php',
        'PHPStan\\PhpDocParser\\Ast\\Attribute' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Attribute.php',
        'PHPStan\\PhpDocParser\\Ast\\Comment' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Comment.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFloatNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNullNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprTrueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php',
        'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\DoctrineConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Node' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Node.php',
        'PHPStan\\PhpDocParser\\Ast\\NodeAttributes' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php',
        'PHPStan\\PhpDocParser\\Ast\\NodeTraverser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php',
        'PHPStan\\PhpDocParser\\Ast\\NodeVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php',
        'PHPStan\\PhpDocParser\\Ast\\NodeVisitor\\CloningVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagMethodValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagPropertyValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\DeprecatedTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineAnnotation' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArgument' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArray' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArrayItem' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\GenericTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\InvalidTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MixinTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamClosureThisTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PureUnlessCallableIsImpureTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SealedTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ThrowsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypelessParamTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\InvalidTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php',
        'PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php',
        'PHPStan\\PhpDocParser\\Lexer\\Lexer' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Lexer/Lexer.php',
        'PHPStan\\PhpDocParser\\ParserConfig' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/ParserConfig.php',
        'PHPStan\\PhpDocParser\\Parser\\ConstExprParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php',
        'PHPStan\\PhpDocParser\\Parser\\ParserException' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/ParserException.php',
        'PHPStan\\PhpDocParser\\Parser\\PhpDocParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php',
        'PHPStan\\PhpDocParser\\Parser\\StringUnescaper' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php',
        'PHPStan\\PhpDocParser\\Parser\\TokenIterator' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/TokenIterator.php',
        'PHPStan\\PhpDocParser\\Parser\\TypeParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/TypeParser.php',
        'PHPStan\\PhpDocParser\\Printer\\DiffElem' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/DiffElem.php',
        'PHPStan\\PhpDocParser\\Printer\\Differ' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/Differ.php',
        'PHPStan\\PhpDocParser\\Printer\\Printer' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/Printer.php',
        'PHP_Parallel_Lint\\PhpConsoleColor\\ConsoleColor' => __DIR__ . '/..' . '/php-parallel-lint/php-console-color/src/ConsoleColor.php',
        'PHP_Parallel_Lint\\PhpConsoleColor\\InvalidStyleException' => __DIR__ . '/..' . '/php-parallel-lint/php-console-color/src/InvalidStyleException.php',
        'PHP_Parallel_Lint\\PhpConsoleHighlighter\\Highlighter' => __DIR__ . '/..' . '/php-parallel-lint/php-console-highlighter/src/Highlighter.php',
        'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
        'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
        'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
        'Psr\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/EventDispatcherInterface.php',
        'Psr\\EventDispatcher\\ListenerProviderInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/ListenerProviderInterface.php',
        'Psr\\EventDispatcher\\StoppableEventInterface' => __DIR__ . '/..' . '/psr/event-dispatcher/src/StoppableEventInterface.php',
        'Psr\\Http\\Client\\ClientExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientExceptionInterface.php',
        'Psr\\Http\\Client\\ClientInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientInterface.php',
        'Psr\\Http\\Client\\NetworkExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/NetworkExceptionInterface.php',
        'Psr\\Http\\Client\\RequestExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/RequestExceptionInterface.php',
        'Psr\\Http\\Message\\MessageInterface' => __DIR__ . '/..' . '/psr/http-message/src/MessageInterface.php',
        'Psr\\Http\\Message\\RequestFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/RequestFactoryInterface.php',
        'Psr\\Http\\Message\\RequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/RequestInterface.php',
        'Psr\\Http\\Message\\ResponseFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/ResponseFactoryInterface.php',
        'Psr\\Http\\Message\\ResponseInterface' => __DIR__ . '/..' . '/psr/http-message/src/ResponseInterface.php',
        'Psr\\Http\\Message\\ServerRequestFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/ServerRequestFactoryInterface.php',
        'Psr\\Http\\Message\\ServerRequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/ServerRequestInterface.php',
        'Psr\\Http\\Message\\StreamFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/StreamFactoryInterface.php',
        'Psr\\Http\\Message\\StreamInterface' => __DIR__ . '/..' . '/psr/http-message/src/StreamInterface.php',
        'Psr\\Http\\Message\\UploadedFileFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/UploadedFileFactoryInterface.php',
        'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php',
        'Psr\\Http\\Message\\UriFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/UriFactoryInterface.php',
        'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php',
        'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/src/AbstractLogger.php',
        'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/src/InvalidArgumentException.php',
        'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/src/LogLevel.php',
        'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareInterface.php',
        'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareTrait.php',
        'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerInterface.php',
        'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerTrait.php',
        'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/src/NullLogger.php',
        'Stringy\\CollectionStringy' => __DIR__ . '/..' . '/bennerinformatics/stringy/src/CollectionStringy.php',
        'Stringy\\StaticStringy' => __DIR__ . '/..' . '/bennerinformatics/stringy/src/StaticStringy.php',
        'Stringy\\Stringy' => __DIR__ . '/..' . '/bennerinformatics/stringy/src/Stringy.php',
        'Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php',
        'Symfony\\Component\\Console\\Attribute\\AsCommand' => __DIR__ . '/..' . '/symfony/console/Attribute/AsCommand.php',
        'Symfony\\Component\\Console\\CI\\GithubActionReporter' => __DIR__ . '/..' . '/symfony/console/CI/GithubActionReporter.php',
        'Symfony\\Component\\Console\\Color' => __DIR__ . '/..' . '/symfony/console/Color.php',
        'Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
        'Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
        'Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
        'Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php',
        'Symfony\\Component\\Console\\Command\\CompleteCommand' => __DIR__ . '/..' . '/symfony/console/Command/CompleteCommand.php',
        'Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => __DIR__ . '/..' . '/symfony/console/Command/DumpCompletionCommand.php',
        'Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php',
        'Symfony\\Component\\Console\\Command\\LazyCommand' => __DIR__ . '/..' . '/symfony/console/Command/LazyCommand.php',
        'Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php',
        'Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php',
        'Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => __DIR__ . '/..' . '/symfony/console/Command/SignalableCommandInterface.php',
        'Symfony\\Component\\Console\\Command\\TraceableCommand' => __DIR__ . '/..' . '/symfony/console/Command/TraceableCommand.php',
        'Symfony\\Component\\Console\\Completion\\CompletionInput' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionInput.php',
        'Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionSuggestions.php',
        'Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/BashCompletionOutput.php',
        'Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => __DIR__ . '/..' . '/symfony/console/Completion/Output/CompletionOutputInterface.php',
        'Symfony\\Component\\Console\\Completion\\Output\\FishCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/FishCompletionOutput.php',
        'Symfony\\Component\\Console\\Completion\\Output\\ZshCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/ZshCompletionOutput.php',
        'Symfony\\Component\\Console\\Completion\\Suggestion' => __DIR__ . '/..' . '/symfony/console/Completion/Suggestion.php',
        'Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php',
        'Symfony\\Component\\Console\\Cursor' => __DIR__ . '/..' . '/symfony/console/Cursor.php',
        'Symfony\\Component\\Console\\DataCollector\\CommandDataCollector' => __DIR__ . '/..' . '/symfony/console/DataCollector/CommandDataCollector.php',
        'Symfony\\Component\\Console\\Debug\\CliRequest' => __DIR__ . '/..' . '/symfony/console/Debug/CliRequest.php',
        'Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
        'Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php',
        'Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php',
        'Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php',
        'Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php',
        'Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php',
        'Symfony\\Component\\Console\\Descriptor\\ReStructuredTextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/ReStructuredTextDescriptor.php',
        'Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php',
        'Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php',
        'Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php',
        'Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php',
        'Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php',
        'Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php',
        'Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleSignalEvent.php',
        'Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php',
        'Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php',
        'Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php',
        'Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php',
        'Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php',
        'Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php',
        'Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php',
        'Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php',
        'Symfony\\Component\\Console\\Exception\\RunCommandFailedException' => __DIR__ . '/..' . '/symfony/console/Exception/RunCommandFailedException.php',
        'Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php',
        'Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatter.php',
        'Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatterStyle.php',
        'Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php',
        'Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php',
        'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php',
        'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
        'Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
        'Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
        'Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php',
        'Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php',
        'Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php',
        'Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php',
        'Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php',
        'Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php',
        'Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php',
        'Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php',
        'Symfony\\Component\\Console\\Helper\\OutputWrapper' => __DIR__ . '/..' . '/symfony/console/Helper/OutputWrapper.php',
        'Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php',
        'Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php',
        'Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php',
        'Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php',
        'Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php',
        'Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php',
        'Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php',
        'Symfony\\Component\\Console\\Helper\\TableCellStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableCellStyle.php',
        'Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php',
        'Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php',
        'Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php',
        'Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php',
        'Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php',
        'Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php',
        'Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php',
        'Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php',
        'Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php',
        'Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php',
        'Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php',
        'Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php',
        'Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php',
        'Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php',
        'Symfony\\Component\\Console\\Messenger\\RunCommandContext' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandContext.php',
        'Symfony\\Component\\Console\\Messenger\\RunCommandMessage' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandMessage.php',
        'Symfony\\Component\\Console\\Messenger\\RunCommandMessageHandler' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandMessageHandler.php',
        'Symfony\\Component\\Console\\Output\\AnsiColorMode' => __DIR__ . '/..' . '/symfony/console/Output/AnsiColorMode.php',
        'Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php',
        'Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php',
        'Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php',
        'Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php',
        'Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php',
        'Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php',
        'Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php',
        'Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php',
        'Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php',
        'Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php',
        'Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php',
        'Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php',
        'Symfony\\Component\\Console\\SignalRegistry\\SignalMap' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalMap.php',
        'Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalRegistry.php',
        'Symfony\\Component\\Console\\SingleCommandApplication' => __DIR__ . '/..' . '/symfony/console/SingleCommandApplication.php',
        'Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php',
        'Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php',
        'Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php',
        'Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php',
        'Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php',
        'Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandCompletionTester.php',
        'Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php',
        'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => __DIR__ . '/..' . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php',
        'Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php',
        'Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener' => __DIR__ . '/..' . '/symfony/event-dispatcher/Attribute/AsEventListener.php',
        'Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php',
        'Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener' => __DIR__ . '/..' . '/symfony/event-dispatcher/Debug/WrappedListener.php',
        'Symfony\\Component\\EventDispatcher\\DependencyInjection\\AddEventAliasesPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php',
        'Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass' => __DIR__ . '/..' . '/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php',
        'Symfony\\Component\\EventDispatcher\\EventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcher.php',
        'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventDispatcherInterface.php',
        'Symfony\\Component\\EventDispatcher\\EventSubscriberInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher/EventSubscriberInterface.php',
        'Symfony\\Component\\EventDispatcher\\GenericEvent' => __DIR__ . '/..' . '/symfony/event-dispatcher/GenericEvent.php',
        'Symfony\\Component\\EventDispatcher\\ImmutableEventDispatcher' => __DIR__ . '/..' . '/symfony/event-dispatcher/ImmutableEventDispatcher.php',
        'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php',
        'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php',
        'Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php',
        'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOExceptionInterface.php',
        'Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/InvalidArgumentException.php',
        'Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/RuntimeException.php',
        'Symfony\\Component\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/symfony/filesystem/Filesystem.php',
        'Symfony\\Component\\Filesystem\\Path' => __DIR__ . '/..' . '/symfony/filesystem/Path.php',
        'Symfony\\Component\\Finder\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/symfony/finder/Adapter/AbstractAdapter.php',
        'Symfony\\Component\\Finder\\Adapter\\AbstractFindAdapter' => __DIR__ . '/..' . '/symfony/finder/Adapter/AbstractFindAdapter.php',
        'Symfony\\Component\\Finder\\Adapter\\AdapterInterface' => __DIR__ . '/..' . '/symfony/finder/Adapter/AdapterInterface.php',
        'Symfony\\Component\\Finder\\Adapter\\BsdFindAdapter' => __DIR__ . '/..' . '/symfony/finder/Adapter/BsdFindAdapter.php',
        'Symfony\\Component\\Finder\\Adapter\\GnuFindAdapter' => __DIR__ . '/..' . '/symfony/finder/Adapter/GnuFindAdapter.php',
        'Symfony\\Component\\Finder\\Adapter\\PhpAdapter' => __DIR__ . '/..' . '/symfony/finder/Adapter/PhpAdapter.php',
        'Symfony\\Component\\Finder\\Comparator\\Comparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/Comparator.php',
        'Symfony\\Component\\Finder\\Comparator\\DateComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/DateComparator.php',
        'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/NumberComparator.php',
        'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => __DIR__ . '/..' . '/symfony/finder/Exception/AccessDeniedException.php',
        'Symfony\\Component\\Finder\\Exception\\AdapterFailureException' => __DIR__ . '/..' . '/symfony/finder/Exception/AdapterFailureException.php',
        'Symfony\\Component\\Finder\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/finder/Exception/ExceptionInterface.php',
        'Symfony\\Component\\Finder\\Exception\\OperationNotPermitedException' => __DIR__ . '/..' . '/symfony/finder/Exception/OperationNotPermitedException.php',
        'Symfony\\Component\\Finder\\Exception\\ShellCommandFailureException' => __DIR__ . '/..' . '/symfony/finder/Exception/ShellCommandFailureException.php',
        'Symfony\\Component\\Finder\\Expression\\Expression' => __DIR__ . '/..' . '/symfony/finder/Expression/Expression.php',
        'Symfony\\Component\\Finder\\Expression\\Glob' => __DIR__ . '/..' . '/symfony/finder/Expression/Glob.php',
        'Symfony\\Component\\Finder\\Expression\\Regex' => __DIR__ . '/..' . '/symfony/finder/Expression/Regex.php',
        'Symfony\\Component\\Finder\\Expression\\ValueInterface' => __DIR__ . '/..' . '/symfony/finder/Expression/ValueInterface.php',
        'Symfony\\Component\\Finder\\Finder' => __DIR__ . '/..' . '/symfony/finder/Finder.php',
        'Symfony\\Component\\Finder\\Glob' => __DIR__ . '/..' . '/symfony/finder/Glob.php',
        'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/CustomFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DateRangeFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DepthRangeFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\FilePathsIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilePathsIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FileTypeFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilecontentFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilenameFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\FilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/PathFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SizeRangeFilterIterator.php',
        'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SortableIterator.php',
        'Symfony\\Component\\Finder\\Shell\\Command' => __DIR__ . '/..' . '/symfony/finder/Shell/Command.php',
        'Symfony\\Component\\Finder\\Shell\\Shell' => __DIR__ . '/..' . '/symfony/finder/Shell/Shell.php',
        'Symfony\\Component\\Finder\\SplFileInfo' => __DIR__ . '/..' . '/symfony/finder/SplFileInfo.php',
        'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/process/Exception/ExceptionInterface.php',
        'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/process/Exception/InvalidArgumentException.php',
        'Symfony\\Component\\Process\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/process/Exception/LogicException.php',
        'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php',
        'Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php',
        'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php',
        'Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/RunProcessFailedException.php',
        'Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php',
        'Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php',
        'Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php',
        'Symfony\\Component\\Process\\Messenger\\RunProcessContext' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessContext.php',
        'Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessage.php',
        'Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessageHandler.php',
        'Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php',
        'Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php',
        'Symfony\\Component\\Process\\PhpSubprocess' => __DIR__ . '/..' . '/symfony/process/PhpSubprocess.php',
        'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php',
        'Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php',
        'Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php',
        'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/WindowsPipes.php',
        'Symfony\\Component\\Process\\Process' => __DIR__ . '/..' . '/symfony/process/Process.php',
        'Symfony\\Component\\Process\\ProcessUtils' => __DIR__ . '/..' . '/symfony/process/ProcessUtils.php',
        'Symfony\\Component\\String\\AbstractString' => __DIR__ . '/..' . '/symfony/string/AbstractString.php',
        'Symfony\\Component\\String\\AbstractUnicodeString' => __DIR__ . '/..' . '/symfony/string/AbstractUnicodeString.php',
        'Symfony\\Component\\String\\ByteString' => __DIR__ . '/..' . '/symfony/string/ByteString.php',
        'Symfony\\Component\\String\\CodePointString' => __DIR__ . '/..' . '/symfony/string/CodePointString.php',
        'Symfony\\Component\\String\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/string/Exception/ExceptionInterface.php',
        'Symfony\\Component\\String\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/string/Exception/InvalidArgumentException.php',
        'Symfony\\Component\\String\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/string/Exception/RuntimeException.php',
        'Symfony\\Component\\String\\Inflector\\EnglishInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/EnglishInflector.php',
        'Symfony\\Component\\String\\Inflector\\FrenchInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/FrenchInflector.php',
        'Symfony\\Component\\String\\Inflector\\InflectorInterface' => __DIR__ . '/..' . '/symfony/string/Inflector/InflectorInterface.php',
        'Symfony\\Component\\String\\Inflector\\SpanishInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/SpanishInflector.php',
        'Symfony\\Component\\String\\LazyString' => __DIR__ . '/..' . '/symfony/string/LazyString.php',
        'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php',
        'Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php',
        'Symfony\\Component\\String\\TruncateMode' => __DIR__ . '/..' . '/symfony/string/TruncateMode.php',
        'Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php',
        'Symfony\\Contracts\\EventDispatcher\\Event' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/Event.php',
        'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface' => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts/EventDispatcherInterface.php',
        'Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php',
        'Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php',
        'Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
        'Symfony\\Contracts\\Service\\ServiceCollectionInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceCollectionInterface.php',
        'Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
        'Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceMethodsSubscriberTrait.php',
        'Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
        'Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
        'Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
        'Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
        'Symfony\\Polyfill\\Iconv\\Iconv' => __DIR__ . '/..' . '/symfony/polyfill-iconv/Iconv.php',
        'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/Grapheme.php',
        'Symfony\\Polyfill\\Intl\\Idn\\Idn' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Idn.php',
        'Symfony\\Polyfill\\Intl\\Idn\\Info' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Info.php',
        'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
        'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
        'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php',
        'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
        'Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php',
        'Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php',
        'Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php',
        'phpDocumentor\\Reflection\\DocBlock' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock.php',
        'phpDocumentor\\Reflection\\DocBlockFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php',
        'phpDocumentor\\Reflection\\DocBlockFactoryInterface' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php',
        'phpDocumentor\\Reflection\\DocBlock\\Description' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php',
        'phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php',
        'phpDocumentor\\Reflection\\DocBlock\\Serializer' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php',
        'phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php',
        'phpDocumentor\\Reflection\\DocBlock\\TagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Extends_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Extends_.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\AbstractPHPStanFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ExtendsFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ExtendsFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\Factory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ImplementsFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ImplementsFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodParameterFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodParameterFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PHPStanFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ParamFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyReadFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyWriteFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ReturnFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateExtendsFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateExtendsFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\TemplateImplementsFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/TemplateImplementsFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\VarFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Implements_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Implements_.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\MethodParameter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Mixin' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Mixin.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Template' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Template.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateCovariant' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateCovariant.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateExtends' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateExtends.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\TemplateImplements' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TemplateImplements.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php',
        'phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php',
        'phpDocumentor\\Reflection\\Element' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Element.php',
        'phpDocumentor\\Reflection\\Exception\\PcreException' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php',
        'phpDocumentor\\Reflection\\File' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/File.php',
        'phpDocumentor\\Reflection\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Fqsen.php',
        'phpDocumentor\\Reflection\\FqsenResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/FqsenResolver.php',
        'phpDocumentor\\Reflection\\Location' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Location.php',
        'phpDocumentor\\Reflection\\Project' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Project.php',
        'phpDocumentor\\Reflection\\ProjectFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/ProjectFactory.php',
        'phpDocumentor\\Reflection\\PseudoType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoType.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ArrayShape' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ArrayShapeItem' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ConstExpression' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\False_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\FloatValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\IntegerRange' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\IntegerValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ListShape' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ListShape.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ListShapeItem' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ListShapeItem.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\List_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/List_.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NegativeInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyArray' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyArray.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyList' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\Numeric_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ObjectShape' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShape.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ObjectShapeItem' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ObjectShapeItem.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\ShapeItem' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ShapeItem.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\StringValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php',
        'phpDocumentor\\Reflection\\PseudoTypes\\True_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php',
        'phpDocumentor\\Reflection\\Type' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Type.php',
        'phpDocumentor\\Reflection\\TypeResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/TypeResolver.php',
        'phpDocumentor\\Reflection\\Types\\AbstractList' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AbstractList.php',
        'phpDocumentor\\Reflection\\Types\\AggregatedType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php',
        'phpDocumentor\\Reflection\\Types\\ArrayKey' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php',
        'phpDocumentor\\Reflection\\Types\\Array_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Array_.php',
        'phpDocumentor\\Reflection\\Types\\Boolean' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Boolean.php',
        'phpDocumentor\\Reflection\\Types\\CallableParameter' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/CallableParameter.php',
        'phpDocumentor\\Reflection\\Types\\Callable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Callable_.php',
        'phpDocumentor\\Reflection\\Types\\ClassString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ClassString.php',
        'phpDocumentor\\Reflection\\Types\\Collection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Collection.php',
        'phpDocumentor\\Reflection\\Types\\Compound' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Compound.php',
        'phpDocumentor\\Reflection\\Types\\Context' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Context.php',
        'phpDocumentor\\Reflection\\Types\\ContextFactory' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php',
        'phpDocumentor\\Reflection\\Types\\Expression' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Expression.php',
        'phpDocumentor\\Reflection\\Types\\Float_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Float_.php',
        'phpDocumentor\\Reflection\\Types\\Integer' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Integer.php',
        'phpDocumentor\\Reflection\\Types\\InterfaceString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php',
        'phpDocumentor\\Reflection\\Types\\Intersection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Intersection.php',
        'phpDocumentor\\Reflection\\Types\\Iterable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Iterable_.php',
        'phpDocumentor\\Reflection\\Types\\Mixed_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Mixed_.php',
        'phpDocumentor\\Reflection\\Types\\Never_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Never_.php',
        'phpDocumentor\\Reflection\\Types\\Null_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Null_.php',
        'phpDocumentor\\Reflection\\Types\\Nullable' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Nullable.php',
        'phpDocumentor\\Reflection\\Types\\Object_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Object_.php',
        'phpDocumentor\\Reflection\\Types\\Parent_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Parent_.php',
        'phpDocumentor\\Reflection\\Types\\Resource_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Resource_.php',
        'phpDocumentor\\Reflection\\Types\\Scalar' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Scalar.php',
        'phpDocumentor\\Reflection\\Types\\Self_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Self_.php',
        'phpDocumentor\\Reflection\\Types\\Static_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Static_.php',
        'phpDocumentor\\Reflection\\Types\\String_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/String_.php',
        'phpDocumentor\\Reflection\\Types\\This' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/This.php',
        'phpDocumentor\\Reflection\\Types\\Void_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Void_.php',
        'phpDocumentor\\Reflection\\Utils' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Utils.php',
        'voku\\helper\\ASCII' => __DIR__ . '/..' . '/voku/portable-ascii/src/voku/helper/ASCII.php',
        'voku\\helper\\AntiXSS' => __DIR__ . '/..' . '/voku/anti-xss/src/voku/helper/AntiXSS.php',
        'voku\\helper\\Bootup' => __DIR__ . '/..' . '/voku/portable-utf8/src/voku/helper/Bootup.php',
        'voku\\helper\\EmailCheck' => __DIR__ . '/..' . '/voku/email-check/src/voku/helper/EmailCheck.php',
        'voku\\helper\\StopWords' => __DIR__ . '/..' . '/voku/stop-words/src/voku/helper/StopWords.php',
        'voku\\helper\\StopWordsLanguageNotExists' => __DIR__ . '/..' . '/voku/stop-words/src/voku/helper/StopWordsLanguageNotExists.php',
        'voku\\helper\\URLify' => __DIR__ . '/..' . '/voku/urlify/src/voku/helper/URLify.php',
        'voku\\helper\\UTF8' => __DIR__ . '/..' . '/voku/portable-utf8/src/voku/helper/UTF8.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInit99acc0ea0763a3d8cd50e9c30b597c03::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var string|null */
    private $vendorDir;

    // PSR-4
    /**
     * @var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array<string, list<string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var array<string, bool>
     */
    private $missingClasses = array();

    /** @var string|null */
    private $apcuPrefix;

    /**
     * @var array<string, self>
     */
    private static $registeredLoaders = array();

    /**
     * @param string|null $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
        self::initializeIncludeClosure();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return array<string, string> Array of classname => path
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array<string, string> $classMap Class to filename map
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string              $prefix  The prefix
     * @param list<string>|string $paths   The PSR-0 root directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string              $prefix  The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths   The PSR-4 base directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string              $prefix The prefix
     * @param list<string>|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string              $prefix The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            $includeFile = self::$includeFile;
            $includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders keyed by their corresponding vendor directories.
     *
     * @return array<string, self>
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }

    /**
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) {
            return;
        }

        /**
         * Scope isolated include.
         *
         * Prevents access to $this/self from included files.
         *
         * @param  string $file
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) {
            include $file;
        }, null, null);
    }
}
{
    "packages": [
        {
            "name": "bennerinformatics/php-path",
            "version": "0.1.0",
            "version_normalized": "0.1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/BennerInformatics/php-path.git",
                "reference": "32f222ff07148e48380f84122e1bd4b4fd01c4ad"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/BennerInformatics/php-path/zipball/32f222ff07148e48380f84122e1bd4b4fd01c4ad",
                "reference": "32f222ff07148e48380f84122e1bd4b4fd01c4ad",
                "shasum": ""
            },
            "require": {
                "php": ">= 7.0.0"
            },
            "require-dev": {
                "jakub-onderka/php-console-highlighter": "^0.3.2",
                "jakub-onderka/php-parallel-lint": "^0.9.2",
                "phpunit/phpunit": "^6.1",
                "squizlabs/php_codesniffer": "^2.8"
            },
            "time": "2017-04-27T21:46:57+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "path.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Austin Burdine",
                    "email": "acburdine@gmail.com"
                }
            ],
            "description": "Set of PHP functions designed to make working with filepaths easier",
            "support": {
                "issues": "https://github.com/BennerInformatics/php-path/issues",
                "source": "https://github.com/BennerInformatics/php-path/tree/master"
            },
            "install-path": "../bennerinformatics/php-path"
        },
        {
            "name": "bennerinformatics/stringy",
            "version": "6.5.4",
            "version_normalized": "6.5.4.0",
            "source": {
                "type": "git",
                "url": "https://github.com/Hathaway12/Stringy.git",
                "reference": "fbbad81f8320d39e6918998978a3934257f52b77"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/Hathaway12/Stringy/zipball/fbbad81f8320d39e6918998978a3934257f52b77",
                "reference": "fbbad81f8320d39e6918998978a3934257f52b77",
                "shasum": ""
            },
            "require": {
                "defuse/php-encryption": "~2.0",
                "ext-json": "*",
                "php": ">=7.0.0",
                "voku/anti-xss": "~4.1",
                "voku/arrayy": "~7.8",
                "voku/email-check": "~3.1",
                "voku/portable-ascii": "~2.0",
                "voku/portable-utf8": "~6.0",
                "voku/urlify": "~5.0"
            },
            "replace": {
                "danielstjules/stringy": "~3.0",
                "voku/stringy": "*"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "time": "2026-02-17T20:57:56+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Stringy\\": "src/"
                },
                "files": [
                    "src/Create.php"
                ]
            },
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Daniel St. Jules",
                    "email": "danielst.jules@gmail.com",
                    "homepage": "http://www.danielstjules.com",
                    "role": "Maintainer"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/",
                    "role": "Fork-Maintainer"
                }
            ],
            "description": "A string manipulation library with multibyte support",
            "homepage": "https://github.com/danielstjules/Stringy",
            "keywords": [
                "helpers",
                "manipulation",
                "methods",
                "multibyte",
                "string",
                "utf",
                "utf-8",
                "utility",
                "utils"
            ],
            "support": {
                "issues": "https://github.com/voku/Stringy/issues",
                "source": "https://github.com/voku/Stringy"
            },
            "funding": [
                {
                    "type": "github",
                    "url": "https://github.com/voku"
                },
                {
                    "type": "patreon",
                    "url": "https://www.patreon.com/voku"
                },
                {
                    "type": "tidelift",
                    "url": "https://tidelift.com/funding/github/packagist/voku/stringy"
                },
                {
                    "type": "custom",
                    "url": "https://www.paypal.me/moelleken"
                }
            ],
            "install-path": "../bennerinformatics/stringy"
        },
        {
            "name": "bit3/git-php",
            "version": "dev-release/1.6.0",
            "version_normalized": "dev-release/1.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/bit3/git-php.git",
                "reference": "4f733e1e514fb9a6b352eaa18db5fba06957ab9d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/bit3/git-php/zipball/4f733e1e514fb9a6b352eaa18db5fba06957ab9d",
                "reference": "4f733e1e514fb9a6b352eaa18db5fba06957ab9d",
                "shasum": ""
            },
            "require": {
                "php": "^7.4 || ^8.0",
                "psr/log": "^1.0 || ^2.0 || ^3.0",
                "symfony/process": "^4.0 || ^5.0 || ^6.0"
            },
            "require-dev": {
                "phpcq/runner-bootstrap": "^1.0@dev",
                "symfony/filesystem": "^4.0 || ^5.0 || ^6.0"
            },
            "time": "2023-08-16T09:46:28+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-release/1.6.0": "1.6.0-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Bit3\\GitPhp\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "Easy to use GIT wrapper for PHP.",
            "support": {
                "issues": "https://github.com/bit3/git-php/issues",
                "source": "https://github.com/bit3/git-php/tree/release/1.6.0"
            },
            "install-path": "../bit3/git-php"
        },
        {
            "name": "composer/semver",
            "version": "1.7.2",
            "version_normalized": "1.7.2.0",
            "source": {
                "type": "git",
                "url": "https://github.com/composer/semver.git",
                "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/composer/semver/zipball/647490bbcaf7fc4891c58f47b825eb99d19c377a",
                "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a",
                "shasum": ""
            },
            "require": {
                "php": "^5.3.2 || ^7.0 || ^8.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^4.5 || ^5.0.5"
            },
            "time": "2020-12-03T15:47:16+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Composer\\Semver\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nils Adermann",
                    "email": "naderman@naderman.de",
                    "homepage": "http://www.naderman.de"
                },
                {
                    "name": "Jordi Boggiano",
                    "email": "j.boggiano@seld.be",
                    "homepage": "http://seld.be"
                },
                {
                    "name": "Rob Bast",
                    "email": "rob.bast@gmail.com",
                    "homepage": "http://robbast.nl"
                }
            ],
            "description": "Semver library that offers utilities, version constraint parsing and validation.",
            "keywords": [
                "semantic",
                "semver",
                "validation",
                "versioning"
            ],
            "support": {
                "irc": "irc://irc.freenode.org/composer",
                "issues": "https://github.com/composer/semver/issues",
                "source": "https://github.com/composer/semver/tree/1.7.2"
            },
            "funding": [
                {
                    "url": "https://packagist.com",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/composer",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
                    "type": "tidelift"
                }
            ],
            "install-path": "./semver"
        },
        {
            "name": "defuse/php-encryption",
            "version": "v2.4.0",
            "version_normalized": "2.4.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/defuse/php-encryption.git",
                "reference": "f53396c2d34225064647a05ca76c1da9d99e5828"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/defuse/php-encryption/zipball/f53396c2d34225064647a05ca76c1da9d99e5828",
                "reference": "f53396c2d34225064647a05ca76c1da9d99e5828",
                "shasum": ""
            },
            "require": {
                "ext-openssl": "*",
                "paragonie/random_compat": ">= 2",
                "php": ">=5.6.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^5|^6|^7|^8|^9|^10",
                "yoast/phpunit-polyfills": "^2.0.0"
            },
            "time": "2023-06-19T06:10:36+00:00",
            "bin": [
                "bin/generate-defuse-key"
            ],
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Defuse\\Crypto\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Taylor Hornby",
                    "email": "taylor@defuse.ca",
                    "homepage": "https://defuse.ca/"
                },
                {
                    "name": "Scott Arciszewski",
                    "email": "info@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "Secure PHP Encryption Library",
            "keywords": [
                "aes",
                "authenticated encryption",
                "cipher",
                "crypto",
                "cryptography",
                "encrypt",
                "encryption",
                "openssl",
                "security",
                "symmetric key cryptography"
            ],
            "support": {
                "issues": "https://github.com/defuse/php-encryption/issues",
                "source": "https://github.com/defuse/php-encryption/tree/v2.4.0"
            },
            "install-path": "../defuse/php-encryption"
        },
        {
            "name": "doctrine/deprecations",
            "version": "1.1.5",
            "version_normalized": "1.1.5.0",
            "source": {
                "type": "git",
                "url": "https://github.com/doctrine/deprecations.git",
                "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
                "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
                "shasum": ""
            },
            "require": {
                "php": "^7.1 || ^8.0"
            },
            "conflict": {
                "phpunit/phpunit": "<=7.5 || >=13"
            },
            "require-dev": {
                "doctrine/coding-standard": "^9 || ^12 || ^13",
                "phpstan/phpstan": "1.4.10 || 2.1.11",
                "phpstan/phpstan-phpunit": "^1.0 || ^2",
                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
                "psr/log": "^1 || ^2 || ^3"
            },
            "suggest": {
                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
            },
            "time": "2025-04-07T20:06:18+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Doctrine\\Deprecations\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
            "homepage": "https://www.doctrine-project.org/",
            "support": {
                "issues": "https://github.com/doctrine/deprecations/issues",
                "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
            },
            "install-path": "../doctrine/deprecations"
        },
        {
            "name": "guzzlehttp/guzzle",
            "version": "7.10.0",
            "version_normalized": "7.10.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/guzzle.git",
                "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
                "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "guzzlehttp/promises": "^2.3",
                "guzzlehttp/psr7": "^2.8",
                "php": "^7.2.5 || ^8.0",
                "psr/http-client": "^1.0",
                "symfony/deprecation-contracts": "^2.2 || ^3.0"
            },
            "provide": {
                "psr/http-client-implementation": "1.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "ext-curl": "*",
                "guzzle/client-integration-tests": "3.0.2",
                "php-http/message-factory": "^1.1",
                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                "psr/log": "^1.1 || ^2.0 || ^3.0"
            },
            "suggest": {
                "ext-curl": "Required for CURL handler support",
                "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                "psr/log": "Required for using the Log middleware"
            },
            "time": "2025-08-23T22:36:01+00:00",
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/functions_include.php"
                ],
                "psr-4": {
                    "GuzzleHttp\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "Jeremy Lindblom",
                    "email": "jeremeamia@gmail.com",
                    "homepage": "https://github.com/jeremeamia"
                },
                {
                    "name": "George Mponos",
                    "email": "gmponos@gmail.com",
                    "homepage": "https://github.com/gmponos"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://github.com/sagikazarmark"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                }
            ],
            "description": "Guzzle is a PHP HTTP client library",
            "keywords": [
                "client",
                "curl",
                "framework",
                "http",
                "http client",
                "psr-18",
                "psr-7",
                "rest",
                "web service"
            ],
            "support": {
                "issues": "https://github.com/guzzle/guzzle/issues",
                "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
                    "type": "tidelift"
                }
            ],
            "install-path": "../guzzlehttp/guzzle"
        },
        {
            "name": "guzzlehttp/promises",
            "version": "2.3.0",
            "version_normalized": "2.3.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/promises.git",
                "reference": "481557b130ef3790cf82b713667b43030dc9c957"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
                "reference": "481557b130ef3790cf82b713667b43030dc9c957",
                "shasum": ""
            },
            "require": {
                "php": "^7.2.5 || ^8.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "phpunit/phpunit": "^8.5.44 || ^9.6.25"
            },
            "time": "2025-08-22T14:34:08+00:00",
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "GuzzleHttp\\Promise\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                }
            ],
            "description": "Guzzle promises library",
            "keywords": [
                "promise"
            ],
            "support": {
                "issues": "https://github.com/guzzle/promises/issues",
                "source": "https://github.com/guzzle/promises/tree/2.3.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
                    "type": "tidelift"
                }
            ],
            "install-path": "../guzzlehttp/promises"
        },
        {
            "name": "guzzlehttp/psr7",
            "version": "2.8.0",
            "version_normalized": "2.8.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/guzzle/psr7.git",
                "reference": "21dc724a0583619cd1652f673303492272778051"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
                "reference": "21dc724a0583619cd1652f673303492272778051",
                "shasum": ""
            },
            "require": {
                "php": "^7.2.5 || ^8.0",
                "psr/http-factory": "^1.0",
                "psr/http-message": "^1.1 || ^2.0",
                "ralouphie/getallheaders": "^3.0"
            },
            "provide": {
                "psr/http-factory-implementation": "1.0",
                "psr/http-message-implementation": "1.0"
            },
            "require-dev": {
                "bamarni/composer-bin-plugin": "^1.8.2",
                "http-interop/http-factory-tests": "0.9.0",
                "phpunit/phpunit": "^8.5.44 || ^9.6.25"
            },
            "suggest": {
                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
            },
            "time": "2025-08-23T21:21:41+00:00",
            "type": "library",
            "extra": {
                "bamarni-bin": {
                    "bin-links": true,
                    "forward-command": false
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "GuzzleHttp\\Psr7\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Graham Campbell",
                    "email": "hello@gjcampbell.co.uk",
                    "homepage": "https://github.com/GrahamCampbell"
                },
                {
                    "name": "Michael Dowling",
                    "email": "mtdowling@gmail.com",
                    "homepage": "https://github.com/mtdowling"
                },
                {
                    "name": "George Mponos",
                    "email": "gmponos@gmail.com",
                    "homepage": "https://github.com/gmponos"
                },
                {
                    "name": "Tobias Nyholm",
                    "email": "tobias.nyholm@gmail.com",
                    "homepage": "https://github.com/Nyholm"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://github.com/sagikazarmark"
                },
                {
                    "name": "Tobias Schultze",
                    "email": "webmaster@tubo-world.de",
                    "homepage": "https://github.com/Tobion"
                },
                {
                    "name": "Márk Sági-Kazár",
                    "email": "mark.sagikazar@gmail.com",
                    "homepage": "https://sagikazarmark.hu"
                }
            ],
            "description": "PSR-7 message implementation that also provides common utility methods",
            "keywords": [
                "http",
                "message",
                "psr-7",
                "request",
                "response",
                "stream",
                "uri",
                "url"
            ],
            "support": {
                "issues": "https://github.com/guzzle/psr7/issues",
                "source": "https://github.com/guzzle/psr7/tree/2.8.0"
            },
            "funding": [
                {
                    "url": "https://github.com/GrahamCampbell",
                    "type": "github"
                },
                {
                    "url": "https://github.com/Nyholm",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
                    "type": "tidelift"
                }
            ],
            "install-path": "../guzzlehttp/psr7"
        },
        {
            "name": "jakeasmith/http_build_url",
            "version": "1.0.1",
            "version_normalized": "1.0.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/jakeasmith/http_build_url.git",
                "reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/jakeasmith/http_build_url/zipball/93c273e77cb1edead0cf8bcf8cd2003428e74e37",
                "reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37",
                "shasum": ""
            },
            "time": "2017-05-01T15:36:40+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/http_build_url.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jake A. Smith",
                    "email": "theman@jakeasmith.com"
                }
            ],
            "description": "Provides functionality for http_build_url() to environments without pecl_http.",
            "support": {
                "issues": "https://github.com/jakeasmith/http_build_url/issues",
                "source": "https://github.com/jakeasmith/http_build_url"
            },
            "install-path": "../jakeasmith/http_build_url"
        },
        {
            "name": "paragonie/random_compat",
            "version": "v9.99.100",
            "version_normalized": "9.99.100.0",
            "source": {
                "type": "git",
                "url": "https://github.com/paragonie/random_compat.git",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "shasum": ""
            },
            "require": {
                "php": ">= 7"
            },
            "require-dev": {
                "phpunit/phpunit": "4.*|5.*",
                "vimeo/psalm": "^1"
            },
            "suggest": {
                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
            },
            "time": "2020-10-15T08:29:30+00:00",
            "type": "library",
            "installation-source": "dist",
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Paragon Initiative Enterprises",
                    "email": "security@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
            "keywords": [
                "csprng",
                "polyfill",
                "pseudorandom",
                "random"
            ],
            "support": {
                "email": "info@paragonie.com",
                "issues": "https://github.com/paragonie/random_compat/issues",
                "source": "https://github.com/paragonie/random_compat"
            },
            "install-path": "../paragonie/random_compat"
        },
        {
            "name": "php-parallel-lint/php-console-color",
            "version": "v1.0.1",
            "version_normalized": "1.0.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-parallel-lint/PHP-Console-Color.git",
                "reference": "7adfefd530aa2d7570ba87100a99e2483a543b88"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Color/zipball/7adfefd530aa2d7570ba87100a99e2483a543b88",
                "reference": "7adfefd530aa2d7570ba87100a99e2483a543b88",
                "shasum": ""
            },
            "require": {
                "php": ">=5.3.2"
            },
            "replace": {
                "jakub-onderka/php-console-color": "*"
            },
            "require-dev": {
                "php-parallel-lint/php-code-style": "^2.0",
                "php-parallel-lint/php-parallel-lint": "^1.0",
                "php-parallel-lint/php-var-dump-check": "0.*",
                "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
            },
            "time": "2021-12-25T06:49:29+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "PHP_Parallel_Lint\\PhpConsoleColor\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-2-Clause"
            ],
            "authors": [
                {
                    "name": "Jakub Onderka",
                    "email": "jakub.onderka@gmail.com"
                }
            ],
            "description": "Simple library for creating colored console ouput.",
            "support": {
                "issues": "https://github.com/php-parallel-lint/PHP-Console-Color/issues",
                "source": "https://github.com/php-parallel-lint/PHP-Console-Color/tree/v1.0.1"
            },
            "install-path": "../php-parallel-lint/php-console-color"
        },
        {
            "name": "php-parallel-lint/php-console-highlighter",
            "version": "v1.0.0",
            "version_normalized": "1.0.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-parallel-lint/PHP-Console-Highlighter.git",
                "reference": "5b4803384d3303cf8e84141039ef56c8a123138d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Highlighter/zipball/5b4803384d3303cf8e84141039ef56c8a123138d",
                "reference": "5b4803384d3303cf8e84141039ef56c8a123138d",
                "shasum": ""
            },
            "require": {
                "ext-tokenizer": "*",
                "php": ">=5.3.2",
                "php-parallel-lint/php-console-color": "^1.0.1"
            },
            "replace": {
                "jakub-onderka/php-console-highlighter": "*"
            },
            "require-dev": {
                "php-parallel-lint/php-code-style": "^2.0",
                "php-parallel-lint/php-parallel-lint": "^1.0",
                "php-parallel-lint/php-var-dump-check": "0.*",
                "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
            },
            "time": "2022-02-18T08:23:19+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "PHP_Parallel_Lint\\PhpConsoleHighlighter\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jakub Onderka",
                    "email": "acci@acci.cz",
                    "homepage": "http://www.acci.cz/"
                }
            ],
            "description": "Highlight PHP code in terminal",
            "support": {
                "issues": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/issues",
                "source": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/tree/v1.0.0"
            },
            "install-path": "../php-parallel-lint/php-console-highlighter"
        },
        {
            "name": "phpdocumentor/reflection-common",
            "version": "2.2.0",
            "version_normalized": "2.2.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
                "shasum": ""
            },
            "require": {
                "php": "^7.2 || ^8.0"
            },
            "time": "2020-06-27T09:03:43+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-2.x": "2.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jaap van Otterdijk",
                    "email": "opensource@ijaap.nl"
                }
            ],
            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
            "homepage": "http://www.phpdoc.org",
            "keywords": [
                "FQSEN",
                "phpDocumentor",
                "phpdoc",
                "reflection",
                "static analysis"
            ],
            "support": {
                "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
                "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
            },
            "install-path": "../phpdocumentor/reflection-common"
        },
        {
            "name": "phpdocumentor/reflection-docblock",
            "version": "5.6.3",
            "version_normalized": "5.6.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
                "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9",
                "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9",
                "shasum": ""
            },
            "require": {
                "doctrine/deprecations": "^1.1",
                "ext-filter": "*",
                "php": "^7.4 || ^8.0",
                "phpdocumentor/reflection-common": "^2.2",
                "phpdocumentor/type-resolver": "^1.7",
                "phpstan/phpdoc-parser": "^1.7|^2.0",
                "webmozart/assert": "^1.9.1"
            },
            "require-dev": {
                "mockery/mockery": "~1.3.5 || ~1.6.0",
                "phpstan/extension-installer": "^1.1",
                "phpstan/phpstan": "^1.8",
                "phpstan/phpstan-mockery": "^1.1",
                "phpstan/phpstan-webmozart-assert": "^1.2",
                "phpunit/phpunit": "^9.5",
                "psalm/phar": "^5.26"
            },
            "time": "2025-08-01T19:43:32+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "5.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Mike van Riel",
                    "email": "me@mikevanriel.com"
                },
                {
                    "name": "Jaap van Otterdijk",
                    "email": "opensource@ijaap.nl"
                }
            ],
            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
            "support": {
                "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
                "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3"
            },
            "install-path": "../phpdocumentor/reflection-docblock"
        },
        {
            "name": "phpdocumentor/type-resolver",
            "version": "1.10.0",
            "version_normalized": "1.10.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpDocumentor/TypeResolver.git",
                "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
                "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
                "shasum": ""
            },
            "require": {
                "doctrine/deprecations": "^1.0",
                "php": "^7.3 || ^8.0",
                "phpdocumentor/reflection-common": "^2.0",
                "phpstan/phpdoc-parser": "^1.18|^2.0"
            },
            "require-dev": {
                "ext-tokenizer": "*",
                "phpbench/phpbench": "^1.2",
                "phpstan/extension-installer": "^1.1",
                "phpstan/phpstan": "^1.8",
                "phpstan/phpstan-phpunit": "^1.1",
                "phpunit/phpunit": "^9.5",
                "rector/rector": "^0.13.9",
                "vimeo/psalm": "^4.25"
            },
            "time": "2024-11-09T15:12:26+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-1.x": "1.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "phpDocumentor\\Reflection\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Mike van Riel",
                    "email": "me@mikevanriel.com"
                }
            ],
            "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
            "support": {
                "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
                "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
            },
            "install-path": "../phpdocumentor/type-resolver"
        },
        {
            "name": "phpstan/phpdoc-parser",
            "version": "2.3.0",
            "version_normalized": "2.3.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpstan/phpdoc-parser.git",
                "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495",
                "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495",
                "shasum": ""
            },
            "require": {
                "php": "^7.4 || ^8.0"
            },
            "require-dev": {
                "doctrine/annotations": "^2.0",
                "nikic/php-parser": "^5.3.0",
                "php-parallel-lint/php-parallel-lint": "^1.2",
                "phpstan/extension-installer": "^1.0",
                "phpstan/phpstan": "^2.0",
                "phpstan/phpstan-phpunit": "^2.0",
                "phpstan/phpstan-strict-rules": "^2.0",
                "phpunit/phpunit": "^9.6",
                "symfony/process": "^5.2"
            },
            "time": "2025-08-30T15:50:23+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "PHPStan\\PhpDocParser\\": [
                        "src/"
                    ]
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "PHPDoc parser with support for nullable, intersection and generic types",
            "support": {
                "issues": "https://github.com/phpstan/phpdoc-parser/issues",
                "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0"
            },
            "install-path": "../phpstan/phpdoc-parser"
        },
        {
            "name": "psr/container",
            "version": "2.0.2",
            "version_normalized": "2.0.2.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/container.git",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "shasum": ""
            },
            "require": {
                "php": ">=7.4.0"
            },
            "time": "2021-11-05T16:47:00+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\Container\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common Container Interface (PHP FIG PSR-11)",
            "homepage": "https://github.com/php-fig/container",
            "keywords": [
                "PSR-11",
                "container",
                "container-interface",
                "container-interop",
                "psr"
            ],
            "support": {
                "issues": "https://github.com/php-fig/container/issues",
                "source": "https://github.com/php-fig/container/tree/2.0.2"
            },
            "install-path": "../psr/container"
        },
        {
            "name": "psr/event-dispatcher",
            "version": "1.0.0",
            "version_normalized": "1.0.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/event-dispatcher.git",
                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2.0"
            },
            "time": "2019-01-08T18:20:26+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\EventDispatcher\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "http://www.php-fig.org/"
                }
            ],
            "description": "Standard interfaces for event handling.",
            "keywords": [
                "events",
                "psr",
                "psr-14"
            ],
            "support": {
                "issues": "https://github.com/php-fig/event-dispatcher/issues",
                "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
            },
            "install-path": "../psr/event-dispatcher"
        },
        {
            "name": "psr/http-client",
            "version": "1.0.3",
            "version_normalized": "1.0.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-client.git",
                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
                "shasum": ""
            },
            "require": {
                "php": "^7.0 || ^8.0",
                "psr/http-message": "^1.0 || ^2.0"
            },
            "time": "2023-09-23T14:17:50+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Client\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for HTTP clients",
            "homepage": "https://github.com/php-fig/http-client",
            "keywords": [
                "http",
                "http-client",
                "psr",
                "psr-18"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-client"
            },
            "install-path": "../psr/http-client"
        },
        {
            "name": "psr/http-factory",
            "version": "1.1.0",
            "version_normalized": "1.1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-factory.git",
                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                "shasum": ""
            },
            "require": {
                "php": ">=7.1",
                "psr/http-message": "^1.0 || ^2.0"
            },
            "time": "2024-04-15T12:06:14+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.0.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Message\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
            "keywords": [
                "factory",
                "http",
                "message",
                "psr",
                "psr-17",
                "psr-7",
                "request",
                "response"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-factory"
            },
            "install-path": "../psr/http-factory"
        },
        {
            "name": "psr/http-message",
            "version": "2.0",
            "version_normalized": "2.0.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/http-message.git",
                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
                "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
                "shasum": ""
            },
            "require": {
                "php": "^7.2 || ^8.0"
            },
            "time": "2023-04-04T09:54:51+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\Http\\Message\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for HTTP messages",
            "homepage": "https://github.com/php-fig/http-message",
            "keywords": [
                "http",
                "http-message",
                "psr",
                "psr-7",
                "request",
                "response"
            ],
            "support": {
                "source": "https://github.com/php-fig/http-message/tree/2.0"
            },
            "install-path": "../psr/http-message"
        },
        {
            "name": "psr/log",
            "version": "3.0.2",
            "version_normalized": "3.0.2.0",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/log.git",
                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
                "shasum": ""
            },
            "require": {
                "php": ">=8.0.0"
            },
            "time": "2024-09-11T13:17:53+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "3.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Psr\\Log\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common interface for logging libraries",
            "homepage": "https://github.com/php-fig/log",
            "keywords": [
                "log",
                "psr",
                "psr-3"
            ],
            "support": {
                "source": "https://github.com/php-fig/log/tree/3.0.2"
            },
            "install-path": "../psr/log"
        },
        {
            "name": "ralouphie/getallheaders",
            "version": "3.0.3",
            "version_normalized": "3.0.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/ralouphie/getallheaders.git",
                "reference": "120b605dfeb996808c31b6477290a714d356e822"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
                "reference": "120b605dfeb996808c31b6477290a714d356e822",
                "shasum": ""
            },
            "require": {
                "php": ">=5.6"
            },
            "require-dev": {
                "php-coveralls/php-coveralls": "^2.1",
                "phpunit/phpunit": "^5 || ^6.5"
            },
            "time": "2019-03-08T08:55:37+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/getallheaders.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Ralph Khattar",
                    "email": "ralph.khattar@gmail.com"
                }
            ],
            "description": "A polyfill for getallheaders.",
            "support": {
                "issues": "https://github.com/ralouphie/getallheaders/issues",
                "source": "https://github.com/ralouphie/getallheaders/tree/develop"
            },
            "install-path": "../ralouphie/getallheaders"
        },
        {
            "name": "symfony/console",
            "version": "v6.4.26",
            "version_normalized": "6.4.26.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/console.git",
                "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
                "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/deprecation-contracts": "^2.5|^3",
                "symfony/polyfill-mbstring": "~1.0",
                "symfony/service-contracts": "^2.5|^3",
                "symfony/string": "^5.4|^6.0|^7.0"
            },
            "conflict": {
                "symfony/dependency-injection": "<5.4",
                "symfony/dotenv": "<5.4",
                "symfony/event-dispatcher": "<5.4",
                "symfony/lock": "<5.4",
                "symfony/process": "<5.4"
            },
            "provide": {
                "psr/log-implementation": "1.0|2.0|3.0"
            },
            "require-dev": {
                "psr/log": "^1|^2|^3",
                "symfony/config": "^5.4|^6.0|^7.0",
                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
                "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
                "symfony/http-foundation": "^6.4|^7.0",
                "symfony/http-kernel": "^6.4|^7.0",
                "symfony/lock": "^5.4|^6.0|^7.0",
                "symfony/messenger": "^5.4|^6.0|^7.0",
                "symfony/process": "^5.4|^6.0|^7.0",
                "symfony/stopwatch": "^5.4|^6.0|^7.0",
                "symfony/var-dumper": "^5.4|^6.0|^7.0"
            },
            "time": "2025-09-26T12:13:46+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Console\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Eases the creation of beautiful and testable command line interfaces",
            "homepage": "https://symfony.com",
            "keywords": [
                "cli",
                "command-line",
                "console",
                "terminal"
            ],
            "support": {
                "source": "https://github.com/symfony/console/tree/v6.4.26"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/console"
        },
        {
            "name": "symfony/deprecation-contracts",
            "version": "v3.6.0",
            "version_normalized": "3.6.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/deprecation-contracts.git",
                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "time": "2024-09-25T14:21:43+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "function.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "A generic function and convention to trigger deprecation notices",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/deprecation-contracts"
        },
        {
            "name": "symfony/event-dispatcher",
            "version": "v6.4.25",
            "version_normalized": "6.4.25.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/event-dispatcher.git",
                "reference": "b0cf3162020603587363f0551cd3be43958611ff"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff",
                "reference": "b0cf3162020603587363f0551cd3be43958611ff",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/event-dispatcher-contracts": "^2.5|^3"
            },
            "conflict": {
                "symfony/dependency-injection": "<5.4",
                "symfony/service-contracts": "<2.5"
            },
            "provide": {
                "psr/event-dispatcher-implementation": "1.0",
                "symfony/event-dispatcher-implementation": "2.0|3.0"
            },
            "require-dev": {
                "psr/log": "^1|^2|^3",
                "symfony/config": "^5.4|^6.0|^7.0",
                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
                "symfony/error-handler": "^5.4|^6.0|^7.0",
                "symfony/expression-language": "^5.4|^6.0|^7.0",
                "symfony/http-foundation": "^5.4|^6.0|^7.0",
                "symfony/service-contracts": "^2.5|^3",
                "symfony/stopwatch": "^5.4|^6.0|^7.0"
            },
            "time": "2025-08-13T09:41:44+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\EventDispatcher\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/event-dispatcher"
        },
        {
            "name": "symfony/event-dispatcher-contracts",
            "version": "v3.6.0",
            "version_normalized": "3.6.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/event-dispatcher-contracts.git",
                "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
                "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "psr/event-dispatcher": "^1"
            },
            "time": "2024-09-25T14:21:43+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Contracts\\EventDispatcher\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Generic abstractions related to dispatching event",
            "homepage": "https://symfony.com",
            "keywords": [
                "abstractions",
                "contracts",
                "decoupling",
                "interfaces",
                "interoperability",
                "standards"
            ],
            "support": {
                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/event-dispatcher-contracts"
        },
        {
            "name": "symfony/filesystem",
            "version": "v6.4.24",
            "version_normalized": "6.4.24.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/filesystem.git",
                "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
                "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "symfony/polyfill-ctype": "~1.8",
                "symfony/polyfill-mbstring": "~1.8"
            },
            "require-dev": {
                "symfony/process": "^5.4|^6.4|^7.0"
            },
            "time": "2025-07-10T08:14:14+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Filesystem\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides basic utilities for the filesystem",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/filesystem/tree/v6.4.24"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/filesystem"
        },
        {
            "name": "symfony/finder",
            "version": "v2.8.52",
            "version_normalized": "2.8.52.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/finder.git",
                "reference": "1444eac52273e345d9b95129bf914639305a9ba4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/finder/zipball/1444eac52273e345d9b95129bf914639305a9ba4",
                "reference": "1444eac52273e345d9b95129bf914639305a9ba4",
                "shasum": ""
            },
            "require": {
                "php": ">=5.3.9"
            },
            "time": "2018-11-11T11:18:13+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.8-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Finder\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony Finder Component",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/finder/tree/v2.8.50"
            },
            "install-path": "../symfony/finder"
        },
        {
            "name": "symfony/polyfill-ctype",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-ctype.git",
                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "provide": {
                "ext-ctype": "*"
            },
            "suggest": {
                "ext-ctype": "For best performance"
            },
            "time": "2024-09-09T11:45:10+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Ctype\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Gert de Pagter",
                    "email": "BackEndTea@gmail.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for ctype functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "ctype",
                "polyfill",
                "portable"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-ctype"
        },
        {
            "name": "symfony/polyfill-iconv",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-iconv.git",
                "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
                "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "provide": {
                "ext-iconv": "*"
            },
            "suggest": {
                "ext-iconv": "For best performance"
            },
            "time": "2024-09-17T14:58:18+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Iconv\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for the Iconv extension",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "iconv",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-iconv"
        },
        {
            "name": "symfony/polyfill-intl-grapheme",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
                "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
                "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "time": "2025-06-27T09:58:17+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's grapheme_* functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "grapheme",
                "intl",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-intl-grapheme"
        },
        {
            "name": "symfony/polyfill-intl-idn",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-idn.git",
                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2",
                "symfony/polyfill-intl-normalizer": "^1.10"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "time": "2024-09-10T14:38:51+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Idn\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Laurent Bassin",
                    "email": "laurent@bassin.info"
                },
                {
                    "name": "Trevor Rowbotham",
                    "email": "trevor.rowbotham@pm.me"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "idn",
                "intl",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-intl-idn"
        },
        {
            "name": "symfony/polyfill-intl-normalizer",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
                "reference": "3833d7255cc303546435cb650316bff708a1c75c"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
                "reference": "3833d7255cc303546435cb650316bff708a1c75c",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "time": "2024-09-09T11:45:10+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
                },
                "classmap": [
                    "Resources/stubs"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's Normalizer class and related functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "intl",
                "normalizer",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-intl-normalizer"
        },
        {
            "name": "symfony/polyfill-mbstring",
            "version": "v1.33.0",
            "version_normalized": "1.33.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-mbstring.git",
                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
                "shasum": ""
            },
            "require": {
                "ext-iconv": "*",
                "php": ">=7.2"
            },
            "provide": {
                "ext-mbstring": "*"
            },
            "suggest": {
                "ext-mbstring": "For best performance"
            },
            "time": "2024-12-23T08:48:59+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Mbstring\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for the Mbstring extension",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "mbstring",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/polyfill-mbstring"
        },
        {
            "name": "symfony/polyfill-php72",
            "version": "v1.31.0",
            "version_normalized": "1.31.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-php72.git",
                "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
                "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "time": "2024-09-09T11:45:10+00:00",
            "type": "metapackage",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": null
        },
        {
            "name": "symfony/process",
            "version": "v6.4.26",
            "version_normalized": "6.4.26.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/process.git",
                "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
                "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "time": "2025-09-11T09:57:09+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Process\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Executes commands in sub-processes",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/process/tree/v6.4.26"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/process"
        },
        {
            "name": "symfony/service-contracts",
            "version": "v3.6.0",
            "version_normalized": "3.6.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/service-contracts.git",
                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "psr/container": "^1.1|^2.0",
                "symfony/deprecation-contracts": "^2.5|^3"
            },
            "conflict": {
                "ext-psr": "<1.1|>=2"
            },
            "time": "2025-04-25T09:37:31+00:00",
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.6-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Symfony\\Contracts\\Service\\": ""
                },
                "exclude-from-classmap": [
                    "/Test/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Generic abstractions related to writing services",
            "homepage": "https://symfony.com",
            "keywords": [
                "abstractions",
                "contracts",
                "decoupling",
                "interfaces",
                "interoperability",
                "standards"
            ],
            "support": {
                "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/service-contracts"
        },
        {
            "name": "symfony/string",
            "version": "v7.3.4",
            "version_normalized": "7.3.4.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/string.git",
                "reference": "f96476035142921000338bad71e5247fbc138872"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
                "reference": "f96476035142921000338bad71e5247fbc138872",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2",
                "symfony/polyfill-ctype": "~1.8",
                "symfony/polyfill-intl-grapheme": "~1.0",
                "symfony/polyfill-intl-normalizer": "~1.0",
                "symfony/polyfill-mbstring": "~1.0"
            },
            "conflict": {
                "symfony/translation-contracts": "<2.5"
            },
            "require-dev": {
                "symfony/emoji": "^7.1",
                "symfony/http-client": "^6.4|^7.0",
                "symfony/intl": "^6.4|^7.0",
                "symfony/translation-contracts": "^2.5|^3.0",
                "symfony/var-exporter": "^6.4|^7.0"
            },
            "time": "2025-09-11T14:36:48+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "Resources/functions.php"
                ],
                "psr-4": {
                    "Symfony\\Component\\String\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
            "homepage": "https://symfony.com",
            "keywords": [
                "grapheme",
                "i18n",
                "string",
                "unicode",
                "utf-8",
                "utf8"
            ],
            "support": {
                "source": "https://github.com/symfony/string/tree/v7.3.4"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "install-path": "../symfony/string"
        },
        {
            "name": "voku/anti-xss",
            "version": "4.1.42",
            "version_normalized": "4.1.42.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/anti-xss.git",
                "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/anti-xss/zipball/bca1f8607e55a3c5077483615cd93bd8f11bd675",
                "reference": "bca1f8607e55a3c5077483615cd93bd8f11bd675",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "voku/portable-utf8": "~6.0.2"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "time": "2023-07-03T14:40:46+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "4.1.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "EllisLab Dev Team",
                    "homepage": "http://ellislab.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/"
                }
            ],
            "description": "anti xss-library",
            "homepage": "https://github.com/voku/anti-xss",
            "keywords": [
                "anti-xss",
                "clean",
                "security",
                "xss"
            ],
            "support": {
                "issues": "https://github.com/voku/anti-xss/issues",
                "source": "https://github.com/voku/anti-xss/tree/4.1.42"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/anti-xss",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/anti-xss",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/anti-xss"
        },
        {
            "name": "voku/arrayy",
            "version": "7.9.6",
            "version_normalized": "7.9.6.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/Arrayy.git",
                "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/Arrayy/zipball/0e20b8c6eef7fc46694a2906e0eae2f9fc11cade",
                "reference": "0e20b8c6eef7fc46694a2906e0eae2f9fc11cade",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "php": ">=7.0.0",
                "phpdocumentor/reflection-docblock": "~4.3 || ~5.0",
                "symfony/polyfill-mbstring": "~1.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "time": "2022-12-27T12:58:32+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/Create.php"
                ],
                "psr-4": {
                    "Arrayy\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://www.moelleken.org/",
                    "role": "Maintainer"
                }
            ],
            "description": "Array manipulation library for PHP, called Arrayy!",
            "keywords": [
                "Arrayy",
                "array",
                "helpers",
                "manipulation",
                "methods",
                "utility",
                "utils"
            ],
            "support": {
                "docs": "https://voku.github.io/Arrayy/",
                "issues": "https://github.com/voku/Arrayy/issues",
                "source": "https://github.com/voku/Arrayy"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/arrayy",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/arrayy",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/arrayy"
        },
        {
            "name": "voku/email-check",
            "version": "3.1.0",
            "version_normalized": "3.1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/email-check.git",
                "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/email-check/zipball/6ea842920bbef6758b8c1e619fd1710e7a1a2cac",
                "reference": "6ea842920bbef6758b8c1e619fd1710e7a1a2cac",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "symfony/polyfill-intl-idn": "~1.10"
            },
            "require-dev": {
                "fzaninotto/faker": "~1.7",
                "phpunit/phpunit": "~6.0 || ~7.0"
            },
            "suggest": {
                "ext-intl": "Use Intl for best performance"
            },
            "time": "2021-01-27T14:14:33+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "email-check (syntax, dns, trash, ...) library",
            "homepage": "https://github.com/voku/email-check",
            "keywords": [
                "check-email",
                "email",
                "mail",
                "mail-check",
                "validate-email",
                "validate-email-address",
                "validate-mail"
            ],
            "support": {
                "issues": "https://github.com/voku/email-check/issues",
                "source": "https://github.com/voku/email-check/tree/3.1.0"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/email-check",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/email-check"
        },
        {
            "name": "voku/portable-ascii",
            "version": "2.0.3",
            "version_normalized": "2.0.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/portable-ascii.git",
                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "suggest": {
                "ext-intl": "Use Intl for transliterator_transliterate() support"
            },
            "time": "2024-11-21T01:49:47+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "https://www.moelleken.org/"
                }
            ],
            "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
            "homepage": "https://github.com/voku/portable-ascii",
            "keywords": [
                "ascii",
                "clean",
                "php"
            ],
            "support": {
                "issues": "https://github.com/voku/portable-ascii/issues",
                "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/portable-ascii",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/portable-ascii"
        },
        {
            "name": "voku/portable-utf8",
            "version": "6.0.13",
            "version_normalized": "6.0.13.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/portable-utf8.git",
                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "symfony/polyfill-iconv": "~1.0",
                "symfony/polyfill-intl-grapheme": "~1.0",
                "symfony/polyfill-intl-normalizer": "~1.0",
                "symfony/polyfill-mbstring": "~1.0",
                "symfony/polyfill-php72": "~1.0",
                "voku/portable-ascii": "~2.0.0"
            },
            "require-dev": {
                "phpstan/phpstan": "1.9.*@dev",
                "phpstan/phpstan-strict-rules": "1.4.*@dev",
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0",
                "thecodingmachine/phpstan-strict-rules": "1.0.*@dev",
                "voku/phpstan-rules": "3.1.*@dev"
            },
            "suggest": {
                "ext-ctype": "Use Ctype for e.g. hexadecimal digit detection",
                "ext-fileinfo": "Use Fileinfo for better binary file detection",
                "ext-iconv": "Use iconv for best performance",
                "ext-intl": "Use Intl for best performance",
                "ext-json": "Use JSON for string detection",
                "ext-mbstring": "Use Mbstring for best performance"
            },
            "time": "2023-03-08T08:35:38+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "(Apache-2.0 or GPL-2.0)"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Hamid Sarfraz",
                    "homepage": "http://pageconfig.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "Portable UTF-8 library - performance optimized (unicode) string functions for php.",
            "homepage": "https://github.com/voku/portable-utf8",
            "keywords": [
                "UTF",
                "clean",
                "php",
                "unicode",
                "utf-8",
                "utf8"
            ],
            "support": {
                "issues": "https://github.com/voku/portable-utf8/issues",
                "source": "https://github.com/voku/portable-utf8/tree/6.0.13"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://opencollective.com/portable-utf8",
                    "type": "open_collective"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-utf8",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/portable-utf8"
        },
        {
            "name": "voku/stop-words",
            "version": "2.0.1",
            "version_normalized": "2.0.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/stop-words.git",
                "reference": "8e63c0af20f800b1600783764e0ce19e53969f71"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/stop-words/zipball/8e63c0af20f800b1600783764e0ce19e53969f71",
                "reference": "8e63c0af20f800b1600783764e0ce19e53969f71",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0"
            },
            "time": "2018-11-23T01:37:27+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "voku\\": "src/voku/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Lars Moelleken",
                    "homepage": "http://www.moelleken.org/"
                }
            ],
            "description": "Stop-Words via PHP",
            "keywords": [
                "stop words",
                "stop-words"
            ],
            "support": {
                "issues": "https://github.com/voku/stop-words/issues",
                "source": "https://github.com/voku/stop-words/tree/master"
            },
            "install-path": "../voku/stop-words"
        },
        {
            "name": "voku/urlify",
            "version": "5.0.7",
            "version_normalized": "5.0.7.0",
            "source": {
                "type": "git",
                "url": "https://github.com/voku/urlify.git",
                "reference": "014b2074407b5db5968f836c27d8731934b330e4"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/voku/urlify/zipball/014b2074407b5db5968f836c27d8731934b330e4",
                "reference": "014b2074407b5db5968f836c27d8731934b330e4",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0",
                "voku/portable-ascii": "~2.0",
                "voku/portable-utf8": "~6.0",
                "voku/stop-words": "~2.0"
            },
            "require-dev": {
                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
            },
            "time": "2022-01-24T19:08:46+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "voku\\helper\\": "src/voku/helper/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Johnny Broadway",
                    "email": "johnny@johnnybroadway.com",
                    "homepage": "http://www.johnnybroadway.com/"
                },
                {
                    "name": "Lars Moelleken",
                    "email": "lars@moelleken.org",
                    "homepage": "https://moelleken.org/"
                }
            ],
            "description": "PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.",
            "homepage": "https://github.com/voku/urlify",
            "keywords": [
                "encode",
                "iconv",
                "link",
                "slug",
                "translit",
                "transliterate",
                "transliteration",
                "url",
                "urlify"
            ],
            "support": {
                "issues": "https://github.com/voku/urlify/issues",
                "source": "https://github.com/voku/urlify/tree/5.0.7"
            },
            "funding": [
                {
                    "url": "https://www.paypal.me/moelleken",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/voku",
                    "type": "github"
                },
                {
                    "url": "https://www.patreon.com/voku",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/voku/urlify",
                    "type": "tidelift"
                }
            ],
            "install-path": "../voku/urlify"
        },
        {
            "name": "webmozart/assert",
            "version": "1.11.0",
            "version_normalized": "1.11.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/webmozarts/assert.git",
                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
                "shasum": ""
            },
            "require": {
                "ext-ctype": "*",
                "php": "^7.2 || ^8.0"
            },
            "conflict": {
                "phpstan/phpstan": "<0.12.20",
                "vimeo/psalm": "<4.6.1 || 4.6.2"
            },
            "require-dev": {
                "phpunit/phpunit": "^8.5.13"
            },
            "time": "2022-06-03T18:03:27+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.10-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Webmozart\\Assert\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Bernhard Schussek",
                    "email": "bschussek@gmail.com"
                }
            ],
            "description": "Assertions to validate method input/output with nice error messages.",
            "keywords": [
                "assert",
                "check",
                "validate"
            ],
            "support": {
                "issues": "https://github.com/webmozarts/assert/issues",
                "source": "https://github.com/webmozarts/assert/tree/1.11.0"
            },
            "install-path": "../webmozart/assert"
        },
        {
            "name": "weew/helpers-array",
            "version": "v1.3.1",
            "version_normalized": "1.3.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/weew/helpers-array.git",
                "reference": "9bff63111f9765b4277750db8d276d92b3e16ed0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/weew/helpers-array/zipball/9bff63111f9765b4277750db8d276d92b3e16ed0",
                "reference": "9bff63111f9765b4277750db8d276d92b3e16ed0",
                "shasum": ""
            },
            "require-dev": {
                "phpunit/phpunit": "^4.7",
                "satooshi/php-coveralls": "^0.6.1"
            },
            "time": "2016-07-21T11:18:01+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/array.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Maxim Kott",
                    "email": "maximkott@gmail.com"
                }
            ],
            "description": "Useful collection of php array helpers.",
            "support": {
                "issues": "https://github.com/weew/helpers-array/issues",
                "source": "https://github.com/weew/helpers-array/tree/master"
            },
            "install-path": "../weew/helpers-array"
        }
    ],
    "dev": false,
    "dev-package-names": []
}
<?php return array(
    'root' => array(
        'name' => 'linformatics/fw-installer',
        'pretty_version' => '1.0.12',
        'version' => '1.0.12.0',
        'reference' => null,
        'type' => 'library',
        'install_path' => __DIR__ . '/../../',
        'aliases' => array(),
        'dev' => false,
    ),
    'versions' => array(
        'bennerinformatics/php-path' => array(
            'pretty_version' => '0.1.0',
            'version' => '0.1.0.0',
            'reference' => '32f222ff07148e48380f84122e1bd4b4fd01c4ad',
            'type' => 'library',
            'install_path' => __DIR__ . '/../bennerinformatics/php-path',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'bennerinformatics/stringy' => array(
            'pretty_version' => '6.5.4',
            'version' => '6.5.4.0',
            'reference' => 'fbbad81f8320d39e6918998978a3934257f52b77',
            'type' => 'library',
            'install_path' => __DIR__ . '/../bennerinformatics/stringy',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'bit3/git-php' => array(
            'pretty_version' => 'dev-release/1.6.0',
            'version' => 'dev-release/1.6.0',
            'reference' => '4f733e1e514fb9a6b352eaa18db5fba06957ab9d',
            'type' => 'library',
            'install_path' => __DIR__ . '/../bit3/git-php',
            'aliases' => array(
                0 => '1.6.0.x-dev',
            ),
            'dev_requirement' => false,
        ),
        'composer/semver' => array(
            'pretty_version' => '1.7.2',
            'version' => '1.7.2.0',
            'reference' => '647490bbcaf7fc4891c58f47b825eb99d19c377a',
            'type' => 'library',
            'install_path' => __DIR__ . '/./semver',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'danielstjules/stringy' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '~3.0',
            ),
        ),
        'defuse/php-encryption' => array(
            'pretty_version' => 'v2.4.0',
            'version' => '2.4.0.0',
            'reference' => 'f53396c2d34225064647a05ca76c1da9d99e5828',
            'type' => 'library',
            'install_path' => __DIR__ . '/../defuse/php-encryption',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'doctrine/deprecations' => array(
            'pretty_version' => '1.1.5',
            'version' => '1.1.5.0',
            'reference' => '459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38',
            'type' => 'library',
            'install_path' => __DIR__ . '/../doctrine/deprecations',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'guzzlehttp/guzzle' => array(
            'pretty_version' => '7.10.0',
            'version' => '7.10.0.0',
            'reference' => 'b51ac707cfa420b7bfd4e4d5e510ba8008e822b4',
            'type' => 'library',
            'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'guzzlehttp/promises' => array(
            'pretty_version' => '2.3.0',
            'version' => '2.3.0.0',
            'reference' => '481557b130ef3790cf82b713667b43030dc9c957',
            'type' => 'library',
            'install_path' => __DIR__ . '/../guzzlehttp/promises',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'guzzlehttp/psr7' => array(
            'pretty_version' => '2.8.0',
            'version' => '2.8.0.0',
            'reference' => '21dc724a0583619cd1652f673303492272778051',
            'type' => 'library',
            'install_path' => __DIR__ . '/../guzzlehttp/psr7',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'jakeasmith/http_build_url' => array(
            'pretty_version' => '1.0.1',
            'version' => '1.0.1.0',
            'reference' => '93c273e77cb1edead0cf8bcf8cd2003428e74e37',
            'type' => 'library',
            'install_path' => __DIR__ . '/../jakeasmith/http_build_url',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'jakub-onderka/php-console-color' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '*',
            ),
        ),
        'jakub-onderka/php-console-highlighter' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '*',
            ),
        ),
        'linformatics/fw-installer' => array(
            'pretty_version' => '1.0.12',
            'version' => '1.0.12.0',
            'reference' => null,
            'type' => 'library',
            'install_path' => __DIR__ . '/../../',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'paragonie/random_compat' => array(
            'pretty_version' => 'v9.99.100',
            'version' => '9.99.100.0',
            'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
            'type' => 'library',
            'install_path' => __DIR__ . '/../paragonie/random_compat',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'php-parallel-lint/php-console-color' => array(
            'pretty_version' => 'v1.0.1',
            'version' => '1.0.1.0',
            'reference' => '7adfefd530aa2d7570ba87100a99e2483a543b88',
            'type' => 'library',
            'install_path' => __DIR__ . '/../php-parallel-lint/php-console-color',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'php-parallel-lint/php-console-highlighter' => array(
            'pretty_version' => 'v1.0.0',
            'version' => '1.0.0.0',
            'reference' => '5b4803384d3303cf8e84141039ef56c8a123138d',
            'type' => 'library',
            'install_path' => __DIR__ . '/../php-parallel-lint/php-console-highlighter',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'phpdocumentor/reflection-common' => array(
            'pretty_version' => '2.2.0',
            'version' => '2.2.0.0',
            'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
            'type' => 'library',
            'install_path' => __DIR__ . '/../phpdocumentor/reflection-common',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'phpdocumentor/reflection-docblock' => array(
            'pretty_version' => '5.6.3',
            'version' => '5.6.3.0',
            'reference' => '94f8051919d1b0369a6bcc7931d679a511c03fe9',
            'type' => 'library',
            'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'phpdocumentor/type-resolver' => array(
            'pretty_version' => '1.10.0',
            'version' => '1.10.0.0',
            'reference' => '679e3ce485b99e84c775d28e2e96fade9a7fb50a',
            'type' => 'library',
            'install_path' => __DIR__ . '/../phpdocumentor/type-resolver',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'phpstan/phpdoc-parser' => array(
            'pretty_version' => '2.3.0',
            'version' => '2.3.0.0',
            'reference' => '1e0cd5370df5dd2e556a36b9c62f62e555870495',
            'type' => 'library',
            'install_path' => __DIR__ . '/../phpstan/phpdoc-parser',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/container' => array(
            'pretty_version' => '2.0.2',
            'version' => '2.0.2.0',
            'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/container',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/event-dispatcher' => array(
            'pretty_version' => '1.0.0',
            'version' => '1.0.0.0',
            'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/event-dispatcher',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/event-dispatcher-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '1.0',
            ),
        ),
        'psr/http-client' => array(
            'pretty_version' => '1.0.3',
            'version' => '1.0.3.0',
            'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/http-client',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/http-client-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '1.0',
            ),
        ),
        'psr/http-factory' => array(
            'pretty_version' => '1.1.0',
            'version' => '1.1.0.0',
            'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/http-factory',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/http-factory-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '1.0',
            ),
        ),
        'psr/http-message' => array(
            'pretty_version' => '2.0',
            'version' => '2.0.0.0',
            'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/http-message',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/http-message-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '1.0',
            ),
        ),
        'psr/log' => array(
            'pretty_version' => '3.0.2',
            'version' => '3.0.2.0',
            'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
            'type' => 'library',
            'install_path' => __DIR__ . '/../psr/log',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'psr/log-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '1.0|2.0|3.0',
            ),
        ),
        'ralouphie/getallheaders' => array(
            'pretty_version' => '3.0.3',
            'version' => '3.0.3.0',
            'reference' => '120b605dfeb996808c31b6477290a714d356e822',
            'type' => 'library',
            'install_path' => __DIR__ . '/../ralouphie/getallheaders',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/console' => array(
            'pretty_version' => 'v6.4.26',
            'version' => '6.4.26.0',
            'reference' => '492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/console',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/deprecation-contracts' => array(
            'pretty_version' => 'v3.6.0',
            'version' => '3.6.0.0',
            'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/event-dispatcher' => array(
            'pretty_version' => 'v6.4.25',
            'version' => '6.4.25.0',
            'reference' => 'b0cf3162020603587363f0551cd3be43958611ff',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/event-dispatcher',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/event-dispatcher-contracts' => array(
            'pretty_version' => 'v3.6.0',
            'version' => '3.6.0.0',
            'reference' => '59eb412e93815df44f05f342958efa9f46b1e586',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/event-dispatcher-implementation' => array(
            'dev_requirement' => false,
            'provided' => array(
                0 => '2.0|3.0',
            ),
        ),
        'symfony/filesystem' => array(
            'pretty_version' => 'v6.4.24',
            'version' => '6.4.24.0',
            'reference' => '75ae2edb7cdcc0c53766c30b0a2512b8df574bd8',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/filesystem',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/finder' => array(
            'pretty_version' => 'v2.8.52',
            'version' => '2.8.52.0',
            'reference' => '1444eac52273e345d9b95129bf914639305a9ba4',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/finder',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-ctype' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-iconv' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => '5f3b930437ae03ae5dff61269024d8ea1b3774aa',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-iconv',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-intl-grapheme' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-intl-idn' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-intl-normalizer' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => '3833d7255cc303546435cb650316bff708a1c75c',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-mbstring' => array(
            'pretty_version' => 'v1.33.0',
            'version' => '1.33.0.0',
            'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/polyfill-php72' => array(
            'pretty_version' => 'v1.31.0',
            'version' => '1.31.0.0',
            'reference' => 'fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce',
            'type' => 'metapackage',
            'install_path' => null,
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/process' => array(
            'pretty_version' => 'v6.4.26',
            'version' => '6.4.26.0',
            'reference' => '48bad913268c8cafabbf7034b39c8bb24fbc5ab8',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/process',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/service-contracts' => array(
            'pretty_version' => 'v3.6.0',
            'version' => '3.6.0.0',
            'reference' => 'f021b05a130d35510bd6b25fe9053c2a8a15d5d4',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/service-contracts',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'symfony/string' => array(
            'pretty_version' => 'v7.3.4',
            'version' => '7.3.4.0',
            'reference' => 'f96476035142921000338bad71e5247fbc138872',
            'type' => 'library',
            'install_path' => __DIR__ . '/../symfony/string',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/anti-xss' => array(
            'pretty_version' => '4.1.42',
            'version' => '4.1.42.0',
            'reference' => 'bca1f8607e55a3c5077483615cd93bd8f11bd675',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/anti-xss',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/arrayy' => array(
            'pretty_version' => '7.9.6',
            'version' => '7.9.6.0',
            'reference' => '0e20b8c6eef7fc46694a2906e0eae2f9fc11cade',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/arrayy',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/email-check' => array(
            'pretty_version' => '3.1.0',
            'version' => '3.1.0.0',
            'reference' => '6ea842920bbef6758b8c1e619fd1710e7a1a2cac',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/email-check',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/portable-ascii' => array(
            'pretty_version' => '2.0.3',
            'version' => '2.0.3.0',
            'reference' => 'b1d923f88091c6bf09699efcd7c8a1b1bfd7351d',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/portable-ascii',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/portable-utf8' => array(
            'pretty_version' => '6.0.13',
            'version' => '6.0.13.0',
            'reference' => 'b8ce36bf26593e5c2e81b1850ef0ffb299d2043f',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/portable-utf8',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/stop-words' => array(
            'pretty_version' => '2.0.1',
            'version' => '2.0.1.0',
            'reference' => '8e63c0af20f800b1600783764e0ce19e53969f71',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/stop-words',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'voku/stringy' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '*',
            ),
        ),
        'voku/urlify' => array(
            'pretty_version' => '5.0.7',
            'version' => '5.0.7.0',
            'reference' => '014b2074407b5db5968f836c27d8731934b330e4',
            'type' => 'library',
            'install_path' => __DIR__ . '/../voku/urlify',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'webmozart/assert' => array(
            'pretty_version' => '1.11.0',
            'version' => '1.11.0.0',
            'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991',
            'type' => 'library',
            'install_path' => __DIR__ . '/../webmozart/assert',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'weew/helpers-array' => array(
            'pretty_version' => 'v1.3.1',
            'version' => '1.3.1.0',
            'reference' => '9bff63111f9765b4277750db8d276d92b3e16ed0',
            'type' => 'library',
            'install_path' => __DIR__ . '/../weew/helpers-array',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
    ),
);
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer;

use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;

/**
 * This class is copied in every Composer installed project and available to all
 *
 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
 *
 * To require its presence, you can require `composer-runtime-api ^2.0`
 *
 * @final
 */
class InstalledVersions
{
    /**
     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
     * @internal
     */
    private static $selfDir = null;

    /**
     * @var mixed[]|null
     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
     */
    private static $installed;

    /**
     * @var bool
     */
    private static $installedIsLocalDir;

    /**
     * @var bool|null
     */
    private static $canGetVendors;

    /**
     * @var array[]
     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static $installedByVendor = array();

    /**
     * Returns a list of all package names which are present, either by being installed, replaced or provided
     *
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = array_keys($installed['versions']);
        }

        if (1 === \count($packages)) {
            return $packages[0];
        }

        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
    }

    /**
     * Returns a list of all package names with a specific type e.g. 'library'
     *
     * @param  string   $type
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();

        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }

        return $packagesByType;
    }

    /**
     * Checks whether the given package is installed
     *
     * This also returns true if the package name is provided or replaced by another package
     *
     * @param  string $packageName
     * @param  bool   $includeDevRequirements
     * @return bool
     */
    public static function isInstalled($packageName, $includeDevRequirements = true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
            }
        }

        return false;
    }

    /**
     * Checks whether the given package satisfies a version constraint
     *
     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
     *
     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
     *
     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
     * @param  string        $packageName
     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
     * @return bool
     */
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints((string) $constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

        return $provided->matches($constraint);
    }

    /**
     * Returns a version constraint representing all the range(s) which are installed for a given package
     *
     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
     * whether a given version of a package is installed, and not just whether it exists
     *
     * @param  string $packageName
     * @return string Version constraint usable with composer/semver
     */
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }

            return implode(' || ', $ranges);
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['pretty_version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
     */
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }

            return $installed['versions'][$packageName]['reference'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
     */
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @return array
     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
     */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();

        return $installed[0]['root'];
    }

    /**
     * Returns the raw installed.php data for custom implementations
     *
     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
     * @return array[]
     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
     */
    public static function getRawData()
    {
        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = include __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }

        return self::$installed;
    }

    /**
     * Returns the raw data of all installed.php which are currently loaded for custom implementations
     *
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }

    /**
     * Lets you reload the static array from another file
     *
     * This is only useful for complex integrations in which a project needs to use
     * this class but then also needs to execute another project's autoloader in process,
     * and wants to ensure both projects have access to their version of installed.php.
     *
     * A typical case would be PHPUnit, where it would need to make sure it reads all
     * the data it needs from this class, then call reload() with
     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
     * the project in which it runs can then also use this class safely, without
     * interference between PHPUnit's dependencies and the project's dependencies.
     *
     * @param  array[] $data A vendor/composer/installed.php data set
     * @return void
     *
     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
     */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();

        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
        // so we have to assume it does not, and that may result in duplicate data being returned when listing
        // all installed packages for example
        self::$installedIsLocalDir = false;
    }

    /**
     * @return string
     */
    private static function getSelfDir()
    {
        if (self::$selfDir === null) {
            self::$selfDir = strtr(__DIR__, '\\', '/');
        }

        return self::$selfDir;
    }

    /**
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
        }

        $installed = array();
        $copiedLocalDir = false;

        if (self::$canGetVendors) {
            $selfDir = self::getSelfDir();
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                $vendorDir = strtr($vendorDir, '\\', '/');
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (is_file($vendorDir.'/composer/installed.php')) {
                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                    $required = require $vendorDir.'/composer/installed.php';
                    self::$installedByVendor[$vendorDir] = $required;
                    $installed[] = $required;
                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
                        self::$installed = $required;
                        self::$installedIsLocalDir = true;
                    }
                }
                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
                    $copiedLocalDir = true;
                }
            }
        }

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                $required = require __DIR__ . '/installed.php';
                self::$installed = $required;
            } else {
                self::$installed = array();
            }
        }

        if (self::$installed !== array() && !$copiedLocalDir) {
            $installed[] = self::$installed;
        }

        return $installed;
    }
}

Copyright (c) Nils Adermann, Jordi Boggiano

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.

<?php

// platform_check.php @generated by Composer

$issues = array();

if (!(PHP_VERSION_ID >= 80200)) {
    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
}

if ($issues) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
        } elseif (!headers_sent()) {
            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
        }
    }
    throw new \RuntimeException(
        'Composer detected issues in your platform: ' . implode(' ', $issues)
    );
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver;

use Composer\Semver\Constraint\Constraint;

class Comparator
{
    /**
     * Evaluates the expression: $version1 > $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function greaterThan($version1, $version2)
    {
        return self::compare($version1, '>', $version2);
    }

    /**
     * Evaluates the expression: $version1 >= $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function greaterThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '>=', $version2);
    }

    /**
     * Evaluates the expression: $version1 < $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function lessThan($version1, $version2)
    {
        return self::compare($version1, '<', $version2);
    }

    /**
     * Evaluates the expression: $version1 <= $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function lessThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '<=', $version2);
    }

    /**
     * Evaluates the expression: $version1 == $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function equalTo($version1, $version2)
    {
        return self::compare($version1, '==', $version2);
    }

    /**
     * Evaluates the expression: $version1 != $version2.
     *
     * @param string $version1
     * @param string $version2
     *
     * @return bool
     */
    public static function notEqualTo($version1, $version2)
    {
        return self::compare($version1, '!=', $version2);
    }

    /**
     * Evaluates the expression: $version1 $operator $version2.
     *
     * @param string $version1
     * @param string $operator
     * @param string $version2
     *
     * @return bool
     */
    public static function compare($version1, $operator, $version2)
    {
        $constraint = new Constraint($operator, $version2);

        return $constraint->matches(new Constraint('==', $version1));
    }
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver\Constraint;

trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);

/**
 * Base constraint class.
 */
abstract class AbstractConstraint implements ConstraintInterface
{
    /** @var string */
    protected $prettyString;

    /**
     * @param ConstraintInterface $provider
     *
     * @return bool
     */
    public function matches(ConstraintInterface $provider)
    {
        if ($provider instanceof $this) {
            // see note at bottom of this class declaration
            return $this->matchSpecific($provider);
        }

        // turn matching around to find a match
        return $provider->matches($this);
    }

    /**
     * @param string $prettyString
     */
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }

    /**
     * @return string
     */
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }

        return $this->__toString();
    }

    // implementations must implement a method of this format:
    // not declared abstract here because type hinting violates parameter coherence (TODO right word?)
    // public function matchSpecific(<SpecificConstraintType> $provider);
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver\Constraint;

/**
 * Defines a constraint.
 */
class Constraint implements ConstraintInterface
{
    /* operator integer values */
    const OP_EQ = 0;
    const OP_LT = 1;
    const OP_LE = 2;
    const OP_GT = 3;
    const OP_GE = 4;
    const OP_NE = 5;

    /**
     * Operator to integer translation table.
     *
     * @var array
     */
    private static $transOpStr = array(
        '=' => self::OP_EQ,
        '==' => self::OP_EQ,
        '<' => self::OP_LT,
        '<=' => self::OP_LE,
        '>' => self::OP_GT,
        '>=' => self::OP_GE,
        '<>' => self::OP_NE,
        '!=' => self::OP_NE,
    );

    /**
     * Integer to operator translation table.
     *
     * @var array
     */
    private static $transOpInt = array(
        self::OP_EQ => '==',
        self::OP_LT => '<',
        self::OP_LE => '<=',
        self::OP_GT => '>',
        self::OP_GE => '>=',
        self::OP_NE => '!=',
    );

    /** @var int */
    protected $operator;

    /** @var string */
    protected $version;

    /** @var string */
    protected $prettyString;

    /**
     * @param ConstraintInterface $provider
     *
     * @return bool
     */
    public function matches(ConstraintInterface $provider)
    {
        if ($provider instanceof $this) {
            return $this->matchSpecific($provider);
        }

        // turn matching around to find a match
        return $provider->matches($this);
    }

    /**
     * @param string $prettyString
     */
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }

    /**
     * @return string
     */
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }

        return $this->__toString();
    }

    /**
     * Get all supported comparison operators.
     *
     * @return array
     */
    public static function getSupportedOperators()
    {
        return array_keys(self::$transOpStr);
    }

    /**
     * Sets operator and version to compare with.
     *
     * @param string $operator
     * @param string $version
     *
     * @throws \InvalidArgumentException if invalid operator is given.
     */
    public function __construct($operator, $version)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(sprintf(
                'Invalid operator "%s" given, expected one of: %s',
                $operator,
                implode(', ', self::getSupportedOperators())
            ));
        }

        $this->operator = self::$transOpStr[$operator];
        $this->version = $version;
    }

    /**
     * @param string $a
     * @param string $b
     * @param string $operator
     * @param bool   $compareBranches
     *
     * @throws \InvalidArgumentException if invalid operator is given.
     *
     * @return bool
     */
    public function versionCompare($a, $b, $operator, $compareBranches = false)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(sprintf(
                'Invalid operator "%s" given, expected one of: %s',
                $operator,
                implode(', ', self::getSupportedOperators())
            ));
        }

        $aIsBranch = 'dev-' === substr($a, 0, 4);
        $bIsBranch = 'dev-' === substr($b, 0, 4);

        if ($aIsBranch && $bIsBranch) {
            return $operator === '==' && $a === $b;
        }

        // when branches are not comparable, we make sure dev branches never match anything
        if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
            return false;
        }

        return version_compare($a, $b, $operator);
    }

    /**
     * @param Constraint $provider
     * @param bool       $compareBranches
     *
     * @return bool
     */
    public function matchSpecific(Constraint $provider, $compareBranches = false)
    {
        $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
        $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);

        $isEqualOp = self::OP_EQ === $this->operator;
        $isNonEqualOp = self::OP_NE === $this->operator;
        $isProviderEqualOp = self::OP_EQ === $provider->operator;
        $isProviderNonEqualOp = self::OP_NE === $provider->operator;

        // '!=' operator is match when other operator is not '==' operator or version is not match
        // these kinds of comparisons always have a solution
        if ($isNonEqualOp || $isProviderNonEqualOp) {
            return (!$isEqualOp && !$isProviderEqualOp)
                || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
        }

        // an example for the condition is <= 2.0 & < 1.0
        // these kinds of comparisons always have a solution
        if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
            return true;
        }

        if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
            // special case, e.g. require >= 1.0 and provide < 1.0
            // 1.0 >= 1.0 but 1.0 is outside of the provided interval
            return !($provider->version === $this->version
                && self::$transOpInt[$provider->operator] === $providerNoEqualOp
                && self::$transOpInt[$this->operator] !== $noEqualOp);
        }

        return false;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return self::$transOpInt[$this->operator] . ' ' . $this->version;
    }
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver\Constraint;

interface ConstraintInterface
{
    /**
     * @param ConstraintInterface $provider
     *
     * @return bool
     */
    public function matches(ConstraintInterface $provider);

    /**
     * @return string
     */
    public function getPrettyString();

    /**
     * @return string
     */
    public function __toString();
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver\Constraint;

/**
 * Defines the absence of a constraint.
 */
class EmptyConstraint implements ConstraintInterface
{
    /** @var string */
    protected $prettyString;

    /**
     * @param ConstraintInterface $provider
     *
     * @return bool
     */
    public function matches(ConstraintInterface $provider)
    {
        return true;
    }

    /**
     * @param string $prettyString
     */
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }

    /**
     * @return string
     */
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }

        return (string) $this;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return '[]';
    }
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver\Constraint;

/**
 * Defines a conjunctive or disjunctive set of constraints.
 */
class MultiConstraint implements ConstraintInterface
{
    /** @var ConstraintInterface[] */
    protected $constraints;

    /** @var string|null */
    protected $prettyString;

    /** @var bool */
    protected $conjunctive;

    /**
     * @param ConstraintInterface[] $constraints A set of constraints
     * @param bool                  $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
     */
    public function __construct(array $constraints, $conjunctive = true)
    {
        $this->constraints = $constraints;
        $this->conjunctive = $conjunctive;
    }

    /**
     * @return ConstraintInterface[]
     */
    public function getConstraints()
    {
        return $this->constraints;
    }

    /**
     * @return bool
     */
    public function isConjunctive()
    {
        return $this->conjunctive;
    }

    /**
     * @return bool
     */
    public function isDisjunctive()
    {
        return !$this->conjunctive;
    }

    /**
     * @param ConstraintInterface $provider
     *
     * @return bool
     */
    public function matches(ConstraintInterface $provider)
    {
        if (false === $this->conjunctive) {
            foreach ($this->constraints as $constraint) {
                if ($constraint->matches($provider)) {
                    return true;
                }
            }

            return false;
        }

        foreach ($this->constraints as $constraint) {
            if (!$constraint->matches($provider)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @param string|null $prettyString
     */
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }

    /**
     * @return string
     */
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }

        return (string) $this;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        $constraints = array();
        foreach ($this->constraints as $constraint) {
            $constraints[] = (string) $constraint;
        }

        return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
    }
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver;

use Composer\Semver\Constraint\Constraint;

class Semver
{
    const SORT_ASC = 1;
    const SORT_DESC = -1;

    /** @var VersionParser */
    private static $versionParser;

    /**
     * Determine if given version satisfies given constraints.
     *
     * @param string $version
     * @param string $constraints
     *
     * @return bool
     */
    public static function satisfies($version, $constraints)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }

        $versionParser = self::$versionParser;
        $provider = new Constraint('==', $versionParser->normalize($version));
        $parsedConstraints = $versionParser->parseConstraints($constraints);

        return $parsedConstraints->matches($provider);
    }

    /**
     * Return all versions that satisfy given constraints.
     *
     * @param array  $versions
     * @param string $constraints
     *
     * @return array
     */
    public static function satisfiedBy(array $versions, $constraints)
    {
        $versions = array_filter($versions, function ($version) use ($constraints) {
            return Semver::satisfies($version, $constraints);
        });

        return array_values($versions);
    }

    /**
     * Sort given array of versions.
     *
     * @param array $versions
     *
     * @return array
     */
    public static function sort(array $versions)
    {
        return self::usort($versions, self::SORT_ASC);
    }

    /**
     * Sort given array of versions in reverse.
     *
     * @param array $versions
     *
     * @return array
     */
    public static function rsort(array $versions)
    {
        return self::usort($versions, self::SORT_DESC);
    }

    /**
     * @param array $versions
     * @param int   $direction
     *
     * @return array
     */
    private static function usort(array $versions, $direction)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }

        $versionParser = self::$versionParser;
        $normalized = array();

        // Normalize outside of usort() scope for minor performance increase.
        // Creates an array of arrays: [[normalized, key], ...]
        foreach ($versions as $key => $version) {
            $normalized[] = array($versionParser->normalize($version), $key);
        }

        usort($normalized, function (array $left, array $right) use ($direction) {
            if ($left[0] === $right[0]) {
                return 0;
            }

            if (Comparator::lessThan($left[0], $right[0])) {
                return -$direction;
            }

            return $direction;
        });

        // Recreate input array, using the original indexes which are now in sorted order.
        $sorted = array();
        foreach ($normalized as $item) {
            $sorted[] = $versions[$item[1]];
        }

        return $sorted;
    }
}
<?php

/*
 * This file is part of composer/semver.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\Semver;

use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Semver\Constraint\Constraint;

/**
 * Version parser.
 *
 * @author Jordi Boggiano <j.boggiano@seld.be>
 */
class VersionParser
{
    /**
     * Regex to match pre-release data (sort of).
     *
     * Due to backwards compatibility:
     *   - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted.
     *   - Only stabilities as recognized by Composer are allowed to precede a numerical identifier.
     *   - Numerical-only pre-release identifiers are not supported, see tests.
     *
     *                        |--------------|
     * [major].[minor].[patch] -[pre-release] +[build-metadata]
     *
     * @var string
     */
    private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';

    /** @var string */
    private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';

    /**
     * Returns the stability of a version.
     *
     * @param string $version
     *
     * @return string
     */
    public static function parseStability($version)
    {
        $version = preg_replace('{#.+$}i', '', $version);

        if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
            return 'dev';
        }

        preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);

        if (!empty($match[3])) {
            return 'dev';
        }

        if (!empty($match[1])) {
            if ('beta' === $match[1] || 'b' === $match[1]) {
                return 'beta';
            }
            if ('alpha' === $match[1] || 'a' === $match[1]) {
                return 'alpha';
            }
            if ('rc' === $match[1]) {
                return 'RC';
            }
        }

        return 'stable';
    }

    /**
     * @param string $stability
     *
     * @return string
     */
    public static function normalizeStability($stability)
    {
        $stability = strtolower($stability);

        return $stability === 'rc' ? 'RC' : $stability;
    }

    /**
     * Normalizes a version string to be able to perform comparisons on it.
     *
     * @param string $version
     * @param string $fullVersion optional complete version string to give more context
     *
     * @throws \UnexpectedValueException
     *
     * @return string
     */
    public function normalize($version, $fullVersion = null)
    {
        $version = trim($version);
        $origVersion = $version;
        if (null === $fullVersion) {
            $fullVersion = $version;
        }

        // strip off aliasing
        if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
            $version = $match[1];
        }

        // strip off stability flag
        if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
            $version = substr($version, 0, strlen($version) - strlen($match[0]));
        }

        // match master-like branches
        if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
            return '9999999-dev';
        }

        // if requirement is branch-like, use full name
        if (stripos($version, 'dev-') === 0) {
            return 'dev-' . substr($version, 4);
        }

        // strip off build metadata
        if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
            $version = $match[1];
        }

        // match classical versioning
        if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = $matches[1]
                . (!empty($matches[2]) ? $matches[2] : '.0')
                . (!empty($matches[3]) ? $matches[3] : '.0')
                . (!empty($matches[4]) ? $matches[4] : '.0');
            $index = 5;
        // match date(time) based versioning
        } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = preg_replace('{\D}', '.', $matches[1]);
            $index = 2;
        }

        // add version modifiers if a version was matched
        if (isset($index)) {
            if (!empty($matches[$index])) {
                if ('stable' === $matches[$index]) {
                    return $version;
                }
                $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
            }

            if (!empty($matches[$index + 2])) {
                $version .= '-dev';
            }

            return $version;
        }

        // match dev branches
        if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
            try {
                $normalized = $this->normalizeBranch($match[1]);
                // a branch ending with -dev is only valid if it is numeric
                // if it gets prefixed with dev- it means the branch name should
                // have had a dev- prefix already when passed to normalize
                if (strpos($normalized, 'dev-') === false) {
                    return $normalized;
                }
            } catch (\Exception $e) {
            }
        }

        $extraMessage = '';
        if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
        } elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
        }

        throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
    }

    /**
     * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
     *
     * @param string $branch Branch name (e.g. 2.1.x-dev)
     *
     * @return string|false Numeric prefix if present (e.g. 2.1.) or false
     */
    public function parseNumericAliasPrefix($branch)
    {
        if (preg_match('{^(?P<version>(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
            return $matches['version'] . '.';
        }

        return false;
    }

    /**
     * Normalizes a branch name to be able to perform comparisons on it.
     *
     * @param string $name
     *
     * @return string
     */
    public function normalizeBranch($name)
    {
        $name = trim($name);

        if (in_array($name, array('master', 'trunk', 'default'))) {
            return $this->normalize($name);
        }

        if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
            $version = '';
            for ($i = 1; $i < 5; ++$i) {
                $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
            }

            return str_replace('x', '9999999', $version) . '-dev';
        }

        return 'dev-' . $name;
    }

    /**
     * Parses a constraint string into MultiConstraint and/or Constraint objects.
     *
     * @param string $constraints
     *
     * @return ConstraintInterface
     */
    public function parseConstraints($constraints)
    {
        $prettyConstraint = $constraints;

        $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
        $orGroups = array();

        foreach ($orConstraints as $constraints) {
            $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
            if (count($andConstraints) > 1) {
                $constraintObjects = array();
                foreach ($andConstraints as $constraint) {
                    foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
                        $constraintObjects[] = $parsedConstraint;
                    }
                }
            } else {
                $constraintObjects = $this->parseConstraint($andConstraints[0]);
            }

            if (1 === count($constraintObjects)) {
                $constraint = $constraintObjects[0];
            } else {
                $constraint = new MultiConstraint($constraintObjects);
            }

            $orGroups[] = $constraint;
        }

        if (1 === count($orGroups)) {
            $constraint = $orGroups[0];
        } elseif (2 === count($orGroups)
            // parse the two OR groups and if they are contiguous we collapse
            // them into one constraint
            && $orGroups[0] instanceof MultiConstraint
            && $orGroups[1] instanceof MultiConstraint
            && 2 === count($orGroups[0]->getConstraints())
            && 2 === count($orGroups[1]->getConstraints())
            && ($a = (string) $orGroups[0])
            && strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
            && ($b = (string) $orGroups[1])
            && strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
            && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
        ) {
            $constraint = new MultiConstraint(array(
                new Constraint('>=', substr($a, 4, $posA - 5)),
                new Constraint('<', substr($b, $posB + 2, -1)),
            ));
        } else {
            $constraint = new MultiConstraint($orGroups, false);
        }

        $constraint->setPrettyString($prettyConstraint);

        return $constraint;
    }

    /**
     * @param string $constraint
     *
     * @throws \UnexpectedValueException
     *
     * @return array
     */
    private function parseConstraint($constraint)
    {
        // strip off aliasing
        if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
            $constraint = $match[1];
        }

        // strip @stability flags, and keep it for later use
        if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
            $constraint = '' !== $match[1] ? $match[1] : '*';
            if ($match[2] !== 'stable') {
                $stabilityModifier = $match[2];
            }
        }

        // get rid of #refs as those are used by composer only
        if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
            $constraint = $match[1];
        }

        if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
            return array(new EmptyConstraint());
        }

        $versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';

        // Tilde Range
        //
        // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
        // version, to ensure that unstable instances of the current version are allowed. However, if a stability
        // suffix is added to the constraint, then a >= match on the current version is used instead.
        if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
            if (strpos($constraint, '~>') === 0) {
                throw new \UnexpectedValueException(
                    'Could not parse version constraint ' . $constraint . ': ' .
                    'Invalid operator "~>", you probably meant to use the "~" operator'
                );
            }

            // Work out which position in the version we are operating at
            if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
                $position = 4;
            } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }

            // when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above
            if (!empty($matches[8])) {
                $position++;
            }

            // Calculate the stability suffix
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }

            $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);

            // For upper bound, we increment the position of one more significance,
            // but highPosition = 0 would be illegal
            $highPosition = max(1, $position - 1);
            $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);

            return array(
                $lowerBound,
                $upperBound,
            );
        }

        // Caret Range
        //
        // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
        // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
        // versions 0.X >=0.1.0, and no updates for versions 0.0.X
        if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
            // Work out which position in the version we are operating at
            if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
                $position = 1;
            } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
                $position = 2;
            } else {
                $position = 3;
            }

            // Calculate the stability suffix
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }

            $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);

            // For upper bound, we increment the position of one more significance,
            // but highPosition = 0 would be illegal
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);

            return array(
                $lowerBound,
                $upperBound,
            );
        }

        // X Range
        //
        // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
        // A partial version range is treated as an X-Range, so the special character is in fact optional.
        if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
            if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }

            $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';

            if ($lowVersion === '0.0.0.0-dev') {
                return array(new Constraint('<', $highVersion));
            }

            return array(
                new Constraint('>=', $lowVersion),
                new Constraint('<', $highVersion),
            );
        }

        // Hyphen Range
        //
        // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
        // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
        // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
        // nothing that would be greater than the provided tuple parts.
        if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
            // Calculate the stability suffix
            $lowStabilitySuffix = '';
            if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
                $lowStabilitySuffix = '-dev';
            }

            $lowVersion = $this->normalize($matches['from']);
            $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);

            $empty = function ($x) {
                return ($x === 0 || $x === '0') ? false : empty($x);
            };

            if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
                $highVersion = $this->normalize($matches['to']);
                $upperBound = new Constraint('<=', $highVersion);
            } else {
                $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);

                // validate to version
                $this->normalize($matches['to']);

                $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
                $upperBound = new Constraint('<', $highVersion);
            }

            return array(
                $lowerBound,
                $upperBound,
            );
        }

        // Basic Comparators
        if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
            try {
                try {
                    $version = $this->normalize($matches[2]);
                } catch (\UnexpectedValueException $e) {
                    // recover from an invalid constraint like foobar-dev which should be dev-foobar
                    // except if the constraint uses a known operator, in which case it must be a parse error
                    if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
                        $version = $this->normalize('dev-'.substr($matches[2], 0, -4));
                    } else {
                        throw $e;
                    }
                }

                $op = $matches[1] ?: '=';

                if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
                    $version .= '-' . $stabilityModifier;
                } elseif ('<' === $op || '>=' === $op) {
                    if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
                        if (strpos($matches[2], 'dev-') !== 0) {
                            $version .= '-dev';
                        }
                    }
                }

                return array(new Constraint($matches[1] ?: '=', $version));
            } catch (\Exception $e) {
            }
        }

        $message = 'Could not parse version constraint ' . $constraint;
        if (isset($e)) {
            $message .= ': ' . $e->getMessage();
        }

        throw new \UnexpectedValueException($message);
    }

    /**
     * Increment, decrement, or simply pad a version number.
     *
     * Support function for {@link parseConstraint()}
     *
     * @param array  $matches   Array with version parts in array indexes 1,2,3,4
     * @param int    $position  1,2,3,4 - which segment of the version to increment/decrement
     * @param int    $increment
     * @param string $pad       The string to pad version parts after $position
     *
     * @return string|null The new version
     */
    private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
    {
        for ($i = 4; $i > 0; --$i) {
            if ($i > $position) {
                $matches[$i] = $pad;
            } elseif ($i === $position && $increment) {
                $matches[$i] += $increment;
                // If $matches[$i] was 0, carry the decrement
                if ($matches[$i] < 0) {
                    $matches[$i] = $pad;
                    --$position;

                    // Return null on a carry overflow
                    if ($i === 1) {
                        return null;
                    }
                }
            }
        }

        return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
    }

    /**
     * Expand shorthand stability string to long version.
     *
     * @param string $stability
     *
     * @return string
     */
    private function expandStability($stability)
    {
        $stability = strtolower($stability);

        switch ($stability) {
            case 'a':
                return 'alpha';
            case 'b':
                return 'beta';
            case 'p':
            case 'pl':
                return 'patch';
            case 'rc':
                return 'RC';
            default:
                return $stability;
        }
    }
}
<?php
    require 'defuse-crypto.phar';
    require realpath(dirname(__FILE__) . '/../vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php');
?>
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class Core
{
    const HEADER_VERSION_SIZE               = 4;
    const MINIMUM_CIPHERTEXT_SIZE           = 84;

    const CURRENT_VERSION                   = "\xDE\xF5\x02\x00";

    const CIPHER_METHOD                     = 'aes-256-ctr';
    const BLOCK_BYTE_SIZE                   = 16;
    const KEY_BYTE_SIZE                     = 32;
    const SALT_BYTE_SIZE                    = 32;
    const MAC_BYTE_SIZE                     = 32;
    const HASH_FUNCTION_NAME                = 'sha256';
    const ENCRYPTION_INFO_STRING            = 'DefusePHP|V2|KeyForEncryption';
    const AUTHENTICATION_INFO_STRING        = 'DefusePHP|V2|KeyForAuthentication';
    const BUFFER_BYTE_SIZE                  = 1048576;

    const LEGACY_CIPHER_METHOD              = 'aes-128-cbc';
    const LEGACY_BLOCK_BYTE_SIZE            = 16;
    const LEGACY_KEY_BYTE_SIZE              = 16;
    const LEGACY_HASH_FUNCTION_NAME         = 'sha256';
    const LEGACY_MAC_BYTE_SIZE              = 32;
    const LEGACY_ENCRYPTION_INFO_STRING     = 'DefusePHP|KeyForEncryption';
    const LEGACY_AUTHENTICATION_INFO_STRING = 'DefusePHP|KeyForAuthentication';

    /*
     * V2.0 Format: VERSION (4 bytes) || SALT (32 bytes) || IV (16 bytes) ||
     *              CIPHERTEXT (varies) || HMAC (32 bytes)
     *
     * V1.0 Format: HMAC (32 bytes) || IV (16 bytes) || CIPHERTEXT (varies).
     */

    /**
     * Adds an integer to a block-sized counter.
     *
     * @param string $ctr
     * @param int    $inc
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     *
     * @psalm-suppress RedundantCondition - It's valid to use is_int to check for overflow.
     */
    public static function incrementCounter($ctr, $inc)
    {
        Core::ensureTrue(
            Core::ourStrlen($ctr) === Core::BLOCK_BYTE_SIZE,
            'Trying to increment a nonce of the wrong size.'
        );

        Core::ensureTrue(
            \is_int($inc),
            'Trying to increment nonce by a non-integer.'
        );

        // The caller is probably re-using CTR-mode keystream if they increment by 0.
        Core::ensureTrue(
            $inc > 0,
            'Trying to increment a nonce by a nonpositive amount'
        );

        Core::ensureTrue(
            $inc <= PHP_INT_MAX - 255,
            'Integer overflow may occur'
        );

        /*
         * We start at the rightmost byte (big-endian)
         * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584
         */
        for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) {
            $sum = \ord($ctr[$i]) + $inc;

            /* Detect integer overflow and fail. */
            Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment');

            $ctr[$i] = \pack('C', $sum & 0xFF);
            $inc     = $sum >> 8;
        }
        return $ctr;
    }

    /**
     * Returns a random byte string of the specified length.
     *
     * @param int $octets
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    public static function secureRandom($octets)
    {
        if ($octets <= 0) {
            throw new Ex\CryptoException(
                'A zero or negative amount of random bytes was requested.'
            );
        }
        self::ensureFunctionExists('random_bytes');
        try {
            return \random_bytes(max(1, $octets));
        } catch (\Exception $ex) {
            throw new Ex\EnvironmentIsBrokenException(
                'Your system does not have a secure random number generator.'
            );
        }
    }

    /**
     * Computes the HKDF key derivation function specified in
     * http://tools.ietf.org/html/rfc5869.
     *
     * @param string $hash   Hash Function
     * @param string $ikm    Initial Keying Material
     * @param int    $length How many bytes?
     * @param string $info   What sort of key are we deriving?
     * @param string $salt
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @psalm-suppress UndefinedFunction - We're checking if the function exists first.
     *
     * @return string
     */
    public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
    {
        static $nativeHKDF = null;
        if ($nativeHKDF === null) {
            $nativeHKDF = \is_callable('\\hash_hkdf');
        }
        if ($nativeHKDF) {
            if (\is_null($salt)) {
                $salt = '';
            }
            return \hash_hkdf($hash, $ikm, $length, $info, $salt);
        }

        $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true));

        // Sanity-check the desired output length.
        Core::ensureTrue(
            !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length,
            'Bad output length requested of HDKF.'
        );

        // "if [salt] not provided, is set to a string of HashLen zeroes."
        if (\is_null($salt)) {
            $salt = \str_repeat("\x00", $digest_length);
        }

        // HKDF-Extract:
        // PRK = HMAC-Hash(salt, IKM)
        // The salt is the HMAC key.
        $prk = \hash_hmac($hash, $ikm, $salt, true);

        // HKDF-Expand:

        // This check is useless, but it serves as a reminder to the spec.
        Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length);

        // T(0) = ''
        $t          = '';
        $last_block = '';
        for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) {
            // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??)
            $last_block = \hash_hmac(
                $hash,
                $last_block . $info . \chr($block_index),
                $prk,
                true
            );
            // T = T(1) | T(2) | T(3) | ... | T(N)
            $t .= $last_block;
        }

        // ORM = first L octets of T
        /** @var string $orm */
        $orm = Core::ourSubstr($t, 0, $length);
        Core::ensureTrue(\is_string($orm));
        return $orm;
    }

    /**
     * Checks if two equal-length strings are the same without leaking
     * information through side channels.
     *
     * @param string $expected
     * @param string $given
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return bool
     */
    public static function hashEquals($expected, $given)
    {
        static $native = null;
        if ($native === null) {
            $native = \function_exists('hash_equals');
        }
        if ($native) {
            return \hash_equals($expected, $given);
        }

        // We can't just compare the strings with '==', since it would make
        // timing attacks possible. We could use the XOR-OR constant-time
        // comparison algorithm, but that may not be a reliable defense in an
        // interpreted language. So we use the approach of HMACing both strings
        // with a random key and comparing the HMACs.

        // We're not attempting to make variable-length string comparison
        // secure, as that's very difficult. Make sure the strings are the same
        // length.
        Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given));

        $blind           = Core::secureRandom(32);
        $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind);
        $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind);
        return $correct_compare === $message_compare;
    }
    /**
     * Throws an exception if the constant doesn't exist.
     *
     * @param string $name
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     */
    public static function ensureConstantExists($name)
    {
        Core::ensureTrue(
            \defined($name),
            'Constant '.$name.' does not exists'
        );
    }

    /**
     * Throws an exception if the function doesn't exist.
     *
     * @param string $name
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     */
    public static function ensureFunctionExists($name)
    {
        Core::ensureTrue(
            \function_exists($name),
            'function '.$name.' does not exists'
        );
    }

    /**
     * Throws an exception if the condition is false.
     *
     * @param bool $condition
     * @param string $message
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     */
    public static function ensureTrue($condition, $message = '')
    {
        if (!$condition) {
            throw new Ex\EnvironmentIsBrokenException($message);
        }
    }

    /*
     * We need these strlen() and substr() functions because when
     * 'mbstring.func_overload' is set in php.ini, the standard strlen() and
     * substr() are replaced by mb_strlen() and mb_substr().
     */

    /**
     * Computes the length of a string in bytes.
     *
     * @param string $str
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return int
     */
    public static function ourStrlen($str)
    {
        static $exists = null;
        if ($exists === null) {
            $exists = \extension_loaded('mbstring') && \function_exists('mb_strlen');
        }
        if ($exists) {
            $length = \mb_strlen($str, '8bit');
            Core::ensureTrue($length !== false);
            return $length;
        } else {
            return \strlen($str);
        }
    }

    /**
     * Behaves roughly like the function substr() in PHP 7 does.
     *
     * @param string $str
     * @param int    $start
     * @param int    $length
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string|bool
     */
    public static function ourSubstr($str, $start, $length = null)
    {
        static $exists = null;
        if ($exists === null) {
            $exists = \extension_loaded('mbstring') && \function_exists('mb_substr');
        }

        // This is required to make mb_substr behavior identical to substr.
        // Without this, mb_substr() would return false, contra to what the
        // PHP documentation says (it doesn't say it can return false.)
        $input_len = Core::ourStrlen($str);
        if ($start === $input_len && !$length) {
            return '';
        }

        if ($start > $input_len) {
            return false;
        }

        // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 5.3,
        // so we have to find the length ourselves. Also, substr() doesn't
        // accept null for the length.
        if (! isset($length)) {
            if ($start >= 0) {
                $length = $input_len - $start;
            } else {
                $length = -$start;
            }
        }

        if ($length < 0) {
            throw new \InvalidArgumentException(
                "Negative lengths are not supported with ourSubstr."
            );
        }

        if ($exists) {
            $substr = \mb_substr($str, $start, $length, '8bit');
            // At this point there are two cases where mb_substr can
            // legitimately return an empty string. Either $length is 0, or
            // $start is equal to the length of the string (both mb_substr and
            // substr return an empty string when this happens). It should never
            // ever return a string that's longer than $length.
            if (Core::ourStrlen($substr) > $length || (Core::ourStrlen($substr) === 0 && $length !== 0 && $start !== $input_len)) {
                throw new Ex\EnvironmentIsBrokenException(
                    'Your version of PHP has bug #66797. Its implementation of
                    mb_substr() is incorrect. See the details here:
                    https://bugs.php.net/bug.php?id=66797'
                );
            }
            return $substr;
        }

        return \substr($str, $start, $length);
    }

    /**
     * Computes the PBKDF2 password-based key derivation function.
     *
     * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in
     * RFC 6070. This implementation of PBKDF2 was originally created by Taylor
     * Hornby, with improvements from http://www.variations-of-shadow.com/.
     *
     * @param string $algorithm  The hash algorithm to use. Recommended: SHA256
     * @param string $password   The password.
     * @param string $salt       A salt that is unique to the password.
     * @param int    $count      Iteration count. Higher is better, but slower. Recommended: At least 1000.
     * @param int    $key_length The length of the derived key in bytes.
     * @param bool   $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise.
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string A $key_length-byte key derived from the password and salt.
     */
    public static function pbkdf2(
        $algorithm,
        #[\SensitiveParameter]
        $password,
        $salt,
        $count,
        $key_length,
        $raw_output = false
    )
    {
        // Type checks:
        if (! \is_string($algorithm)) {
            throw new \InvalidArgumentException(
                'pbkdf2(): algorithm must be a string'
            );
        }
        if (! \is_string($password)) {
            throw new \InvalidArgumentException(
                'pbkdf2(): password must be a string'
            );
        }
        if (! \is_string($salt)) {
            throw new \InvalidArgumentException(
                'pbkdf2(): salt must be a string'
            );
        }
        // Coerce strings to integers with no information loss or overflow
        $count += 0;
        $key_length += 0;

        $algorithm = \strtolower($algorithm);
        Core::ensureTrue(
            \in_array($algorithm, \hash_algos(), true),
            'Invalid or unsupported hash algorithm.'
        );

        // Whitelist, or we could end up with people using CRC32.
        $ok_algorithms = [
            'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
            'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',
        ];
        Core::ensureTrue(
            \in_array($algorithm, $ok_algorithms, true),
            'Algorithm is not a secure cryptographic hash function.'
        );

        Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.');

        if (\function_exists('hash_pbkdf2')) {
            // The output length is in NIBBLES (4-bits) if $raw_output is false!
            if (! $raw_output) {
                $key_length = $key_length * 2;
            }
            return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
        }

        $hash_length = Core::ourStrlen(\hash($algorithm, '', true));
        $block_count = \ceil($key_length / $hash_length);

        $output = '';
        for ($i = 1; $i <= $block_count; $i++) {
            // $i encoded as 4 bytes, big endian.
            $last = $salt . \pack('N', $i);
            // first iteration
            $last = $xorsum = \hash_hmac($algorithm, $last, $password, true);
            // perform the other $count - 1 iterations
            for ($j = 1; $j < $count; $j++) {
                /**
                 * @psalm-suppress InvalidOperand
                 */
                $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true));
            }
            $output .= $xorsum;
        }

        if ($raw_output) {
            return (string) Core::ourSubstr($output, 0, $key_length);
        } else {
            return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length));
        }
    }
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

class Crypto
{
    /**
     * Encrypts a string with a Key.
     *
     * @param string $plaintext
     * @param Key    $key
     * @param bool   $raw_binary
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws \TypeError
     *
     * @return string
     */
    public static function encrypt($plaintext, $key, $raw_binary = false)
    {
        if (!\is_string($plaintext)) {
            throw new \TypeError(
                'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.'
            );
        }
        if (!($key instanceof Key)) {
            throw new \TypeError(
                'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
            );
        }
        if (!\is_bool($raw_binary)) {
            throw new \TypeError(
                'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
            );
        }
        return self::encryptInternal(
            $plaintext,
            KeyOrPassword::createFromKey($key),
            $raw_binary
        );
    }

    /**
     * Encrypts a string with a password, using a slow key derivation function
     * to make password cracking more expensive.
     *
     * @param string $plaintext
     * @param string $password
     * @param bool   $raw_binary
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws \TypeError
     *
     * @return string
     */
    public static function encryptWithPassword(
        $plaintext,
        #[\SensitiveParameter]
        $password,
        $raw_binary = false
    )
    {
        if (!\is_string($plaintext)) {
            throw new \TypeError(
                'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.'
            );
        }
        if (!\is_string($password)) {
            throw new \TypeError(
                'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.'
            );
        }
        if (!\is_bool($raw_binary)) {
            throw new \TypeError(
                'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
            );
        }
        return self::encryptInternal(
            $plaintext,
            KeyOrPassword::createFromPassword($password),
            $raw_binary
        );
    }

    /**
     * Decrypts a ciphertext to a string with a Key.
     *
     * @param string $ciphertext
     * @param Key    $key
     * @param bool   $raw_binary
     *
     * @throws \TypeError
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     *
     * @return string
     */
    public static function decrypt($ciphertext, $key, $raw_binary = false)
    {
        if (!\is_string($ciphertext)) {
            throw new \TypeError(
                'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
            );
        }
        if (!($key instanceof Key)) {
            throw new \TypeError(
                'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
            );
        }
        if (!\is_bool($raw_binary)) {
            throw new \TypeError(
                'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
            );
        }
        return self::decryptInternal(
            $ciphertext,
            KeyOrPassword::createFromKey($key),
            $raw_binary
        );
    }

    /**
     * Decrypts a ciphertext to a string with a password, using a slow key
     * derivation function to make password cracking more expensive.
     *
     * @param string $ciphertext
     * @param string $password
     * @param bool   $raw_binary
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     * @throws \TypeError
     *
     * @return string
     */
    public static function decryptWithPassword(
        $ciphertext,
        #[\SensitiveParameter]
        $password,
        $raw_binary = false
    )
    {
        if (!\is_string($ciphertext)) {
            throw new \TypeError(
                'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
            );
        }
        if (!\is_string($password)) {
            throw new \TypeError(
                'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.'
            );
        }
        if (!\is_bool($raw_binary)) {
            throw new \TypeError(
                'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
            );
        }
        return self::decryptInternal(
            $ciphertext,
            KeyOrPassword::createFromPassword($password),
            $raw_binary
        );
    }

    /**
     * Decrypts a legacy ciphertext produced by version 1 of this library.
     *
     * @param string $ciphertext
     * @param string $key
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     * @throws \TypeError
     *
     * @return string
     */
    public static function legacyDecrypt(
        $ciphertext,
        #[\SensitiveParameter]
        $key
    )
    {
        if (!\is_string($ciphertext)) {
            throw new \TypeError(
                'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
            );
        }
        if (!\is_string($key)) {
            throw new \TypeError(
                'String expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
            );
        }

        RuntimeTests::runtimeTest();

        // Extract the HMAC from the front of the ciphertext.
        if (Core::ourStrlen($ciphertext) <= Core::LEGACY_MAC_BYTE_SIZE) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Ciphertext is too short.'
            );
        }
        /**
         * @var string
         */
        $hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
        Core::ensureTrue(\is_string($hmac));
        /**
         * @var string
         */
        $messageCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
        Core::ensureTrue(\is_string($messageCiphertext));

        // Regenerate the same authentication sub-key.
        $akey = Core::HKDF(
            Core::LEGACY_HASH_FUNCTION_NAME,
            $key,
            Core::LEGACY_KEY_BYTE_SIZE,
            Core::LEGACY_AUTHENTICATION_INFO_STRING,
            null
        );

        if (self::verifyHMAC($hmac, $messageCiphertext, $akey)) {
            // Regenerate the same encryption sub-key.
            $ekey = Core::HKDF(
                Core::LEGACY_HASH_FUNCTION_NAME,
                $key,
                Core::LEGACY_KEY_BYTE_SIZE,
                Core::LEGACY_ENCRYPTION_INFO_STRING,
                null
            );

            // Extract the IV from the ciphertext.
            if (Core::ourStrlen($messageCiphertext) <= Core::LEGACY_BLOCK_BYTE_SIZE) {
                throw new Ex\WrongKeyOrModifiedCiphertextException(
                    'Ciphertext is too short.'
                );
            }
            /**
             * @var string
             */
            $iv = Core::ourSubstr($messageCiphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
            Core::ensureTrue(\is_string($iv));

            /**
             * @var string
             */
            $actualCiphertext = Core::ourSubstr($messageCiphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
            Core::ensureTrue(\is_string($actualCiphertext));

            // Do the decryption.
            $plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
            return $plaintext;
        } else {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Integrity check failed.'
            );
        }
    }

    /**
     * Encrypts a string with either a key or a password.
     *
     * @param string        $plaintext
     * @param KeyOrPassword $secret
     * @param bool          $raw_binary
     *
     * @return string
     */
    private static function encryptInternal($plaintext, KeyOrPassword $secret, $raw_binary)
    {
        RuntimeTests::runtimeTest();

        $salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
        $keys = $secret->deriveKeys($salt);
        $ekey = $keys->getEncryptionKey();
        $akey = $keys->getAuthenticationKey();
        $iv     = Core::secureRandom(Core::BLOCK_BYTE_SIZE);

        $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv);
        $auth       = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true);
        $ciphertext = $ciphertext . $auth;

        if ($raw_binary) {
            return $ciphertext;
        }
        return Encoding::binToHex($ciphertext);
    }

    /**
     * Decrypts a ciphertext to a string with either a key or a password.
     *
     * @param string        $ciphertext
     * @param KeyOrPassword $secret
     * @param bool          $raw_binary
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     *
     * @return string
     */
    private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
    {
        RuntimeTests::runtimeTest();

        if (! $raw_binary) {
            try {
                $ciphertext = Encoding::hexToBin($ciphertext);
            } catch (Ex\BadFormatException $ex) {
                throw new Ex\WrongKeyOrModifiedCiphertextException(
                    'Ciphertext has invalid hex encoding.'
                );
            }
        }

        if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Ciphertext is too short.'
            );
        }

        // Get and check the version header.
        /** @var string $header */
        $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
        if ($header !== Core::CURRENT_VERSION) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Bad version header.'
            );
        }

        // Get the salt.
        /** @var string $salt */
        $salt = Core::ourSubstr(
            $ciphertext,
            Core::HEADER_VERSION_SIZE,
            Core::SALT_BYTE_SIZE
        );
        Core::ensureTrue(\is_string($salt));

        // Get the IV.
        /** @var string $iv */
        $iv = Core::ourSubstr(
            $ciphertext,
            Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
            Core::BLOCK_BYTE_SIZE
        );
        Core::ensureTrue(\is_string($iv));

        // Get the HMAC.
        /** @var string $hmac */
        $hmac = Core::ourSubstr(
            $ciphertext,
            Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
            Core::MAC_BYTE_SIZE
        );
        Core::ensureTrue(\is_string($hmac));

        // Get the actual encrypted ciphertext.
        /** @var string $encrypted */
        $encrypted = Core::ourSubstr(
            $ciphertext,
            Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
                Core::BLOCK_BYTE_SIZE,
            Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
                Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
        );
        Core::ensureTrue(\is_string($encrypted));

        // Derive the separate encryption and authentication keys from the key
        // or password, whichever it is.
        $keys = $secret->deriveKeys($salt);

        if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
            $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
            return $plaintext;
        } else {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Integrity check failed.'
            );
        }
    }

    /**
     * Raw unauthenticated encryption (insecure on its own).
     *
     * @param string $plaintext
     * @param string $key
     * @param string $iv
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    protected static function plainEncrypt(
        $plaintext,
        #[\SensitiveParameter]
        $key,
        #[\SensitiveParameter]
        $iv
    )
    {
        Core::ensureConstantExists('OPENSSL_RAW_DATA');
        Core::ensureFunctionExists('openssl_encrypt');
        /** @var string $ciphertext */
        $ciphertext = \openssl_encrypt(
            $plaintext,
            Core::CIPHER_METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );

        Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed');

        return $ciphertext;
    }

    /**
     * Raw unauthenticated decryption (insecure on its own).
     *
     * @param string $ciphertext
     * @param string $key
     * @param string $iv
     * @param string $cipherMethod
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    protected static function plainDecrypt(
        $ciphertext,
        #[\SensitiveParameter]
        $key,
        #[\SensitiveParameter]
        $iv,
        $cipherMethod
    )
    {
        Core::ensureConstantExists('OPENSSL_RAW_DATA');
        Core::ensureFunctionExists('openssl_decrypt');

        /** @var string $plaintext */
        $plaintext = \openssl_decrypt(
            $ciphertext,
            $cipherMethod,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );
        Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.');

        return $plaintext;
    }

    /**
     * Verifies an HMAC without leaking information through side-channels.
     *
     * @param string $expected_hmac
     * @param string $message
     * @param string $key
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return bool
     */
    protected static function verifyHMAC(
        $expected_hmac,
        $message,
        #[\SensitiveParameter]
        $key
    )
    {
        $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true);
        return Core::hashEquals($message_hmac, $expected_hmac);
    }
}
<?php

namespace Defuse\Crypto;

/**
 * Class DerivedKeys
 * @package Defuse\Crypto
 */
final class DerivedKeys
{
    /**
     * @var string
     */
    private $akey = '';

    /**
     * @var string
     */
    private $ekey = '';

    /**
     * Returns the authentication key.
     * @return string
     */
    public function getAuthenticationKey()
    {
        return $this->akey;
    }

    /**
     * Returns the encryption key.
     * @return string
     */
    public function getEncryptionKey()
    {
        return $this->ekey;
    }

    /**
     * Constructor for DerivedKeys.
     *
     * @param string $akey
     * @param string $ekey
     */
    public function __construct($akey, $ekey)
    {
        $this->akey = $akey;
        $this->ekey = $ekey;
    }
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class Encoding
{
    const CHECKSUM_BYTE_SIZE     = 32;
    const CHECKSUM_HASH_ALGO     = 'sha256';
    const SERIALIZE_HEADER_BYTES = 4;

    /**
     * Converts a byte string to a hexadecimal string without leaking
     * information through side channels.
     *
     * @param string $byte_string
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    public static function binToHex($byte_string)
    {
        $hex = '';
        $len = Core::ourStrlen($byte_string);
        for ($i = 0; $i < $len; ++$i) {
            $c = \ord($byte_string[$i]) & 0xf;
            $b = \ord($byte_string[$i]) >> 4;
            $hex .= \pack(
                'CC',
                87 + $b + ((($b - 10) >> 8) & ~38),
                87 + $c + ((($c - 10) >> 8) & ~38)
            );
        }
        return $hex;
    }

    /**
     * Converts a hexadecimal string into a byte string without leaking
     * information through side channels.
     *
     * @param string $hex_string
     *
     * @throws Ex\BadFormatException
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     * @psalm-suppress TypeDoesNotContainType
     */
    public static function hexToBin($hex_string)
    {
        $hex_pos = 0;
        $bin     = '';
        $hex_len = Core::ourStrlen($hex_string);
        $state   = 0;
        $c_acc   = 0;

        while ($hex_pos < $hex_len) {
            $c        = \ord($hex_string[$hex_pos]);
            $c_num    = $c ^ 48;
            $c_num0   = ($c_num - 10) >> 8;
            $c_alpha  = ($c & ~32) - 55;
            $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
            if (($c_num0 | $c_alpha0) === 0) {
                throw new Ex\BadFormatException(
                    'Encoding::hexToBin() input is not a hex string.'
                );
            }
            $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
            if ($state === 0) {
                $c_acc = $c_val * 16;
            } else {
                $bin .= \pack('C', $c_acc | $c_val);
            }
            $state ^= 1;
            ++$hex_pos;
        }
        return $bin;
    }
    
    /**
     * Remove trialing whitespace without table look-ups or branches.
     *
     * Calling this function may leak the length of the string as well as the
     * number of trailing whitespace characters through side-channels.
     *
     * @param string $string
     * @return string
     */
    public static function trimTrailingWhitespace($string = '')
    {
        $length = Core::ourStrlen($string);
        if ($length < 1) {
            return '';
        }
        do {
            $prevLength = $length;
            $last = $length - 1;
            $chr = \ord($string[$last]);

            /* Null Byte (0x00), a.k.a. \0 */
            // if ($chr === 0x00) $length -= 1;
            $sub = (($chr - 1) >> 8 ) & 1;
            $length -= $sub;
            $last -= $sub;

            /* Horizontal Tab (0x09) a.k.a. \t */
            $chr = \ord($string[$last]);
            // if ($chr === 0x09) $length -= 1;
            $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1;
            $length -= $sub;
            $last -= $sub;

            /* New Line (0x0a), a.k.a. \n */
            $chr = \ord($string[$last]);
            // if ($chr === 0x0a) $length -= 1;
            $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1;
            $length -= $sub;
            $last -= $sub;

            /* Carriage Return (0x0D), a.k.a. \r */
            $chr = \ord($string[$last]);
            // if ($chr === 0x0d) $length -= 1;
            $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1;
            $length -= $sub;
            $last -= $sub;

            /* Space */
            $chr = \ord($string[$last]);
            // if ($chr === 0x20) $length -= 1;
            $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1;
            $length -= $sub;
        } while ($prevLength !== $length && $length > 0);
        return (string) Core::ourSubstr($string, 0, $length);
    }

    /*
     * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS:
     *
     *      The checksum introduces a potential security weakness. For example,
     *      suppose we apply a checksum to a key, and that an adversary has an
     *      exploit against the process containing the key, such that they can
     *      overwrite an arbitrary byte of memory and then cause the checksum to
     *      be verified and learn the result.
     *
     *      In this scenario, the adversary can extract the key one byte at
     *      a time by overwriting it with their guess of its value and then
     *      asking if the checksum matches. If it does, their guess was right.
     *      This kind of attack may be more easy to implement and more reliable
     *      than a remote code execution attack.
     *
     *      This attack also applies to authenticated encryption as a whole, in
     *      the situation where the adversary can overwrite a byte of the key
     *      and then cause a valid ciphertext to be decrypted, and then
     *      determine whether the MAC check passed or failed.
     *
     *      By using the full SHA256 hash instead of truncating it, I'm ensuring
     *      that both ways of going about the attack are equivalently difficult.
     *      A shorter checksum of say 32 bits might be more useful to the
     *      adversary as an oracle in case their writes are coarser grained.
     *
     *      Because the scenario assumes a serious vulnerability, we don't try
     *      to prevent attacks of this style.
     */

    /**
     * INTERNAL USE ONLY: Applies a version header, applies a checksum, and
     * then encodes a byte string into a range of printable ASCII characters.
     *
     * @param string $header
     * @param string $bytes
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    public static function saveBytesToChecksummedAsciiSafeString(
        $header,
        #[\SensitiveParameter]
        $bytes
    )
    {
        // Headers must be a constant length to prevent one type's header from
        // being a prefix of another type's header, leading to ambiguity.
        Core::ensureTrue(
            Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES,
            'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
        );

        return Encoding::binToHex(
            $header .
            $bytes .
            \hash(
                self::CHECKSUM_HASH_ALGO,
                $header . $bytes,
                true
            )
        );
    }

    /**
     * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns
     * the encoded byte string.
     *
     * @param string $expected_header
     * @param string $string
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\BadFormatException
     *
     * @return string
     */
    public static function loadBytesFromChecksummedAsciiSafeString(
        $expected_header,
        #[\SensitiveParameter]
        $string
    )
    {
        // Headers must be a constant length to prevent one type's header from
        // being a prefix of another type's header, leading to ambiguity.
        Core::ensureTrue(
            Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES,
            'Header must be 4 bytes.'
        );

        /* If you get an exception here when attempting to load from a file, first pass your
           key to Encoding::trimTrailingWhitespace() to remove newline characters, etc.      */
        $bytes = Encoding::hexToBin($string);

        /* Make sure we have enough bytes to get the version header and checksum. */
        if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
            throw new Ex\BadFormatException(
                'Encoded data is shorter than expected.'
            );
        }

        /* Grab the version header. */
        $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);

        if ($actual_header !== $expected_header) {
            throw new Ex\BadFormatException(
                'Invalid header.'
            );
        }

        /* Grab the bytes that are part of the checksum. */
        $checked_bytes = (string) Core::ourSubstr(
            $bytes,
            0,
            Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
        );

        /* Grab the included checksum. */
        $checksum_a = (string) Core::ourSubstr(
            $bytes,
            Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
            self::CHECKSUM_BYTE_SIZE
        );

        /* Re-compute the checksum. */
        $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);

        /* Check if the checksum matches. */
        if (! Core::hashEquals($checksum_a, $checksum_b)) {
            throw new Ex\BadFormatException(
                "Data is corrupted, the checksum doesn't match"
            );
        }

        return (string) Core::ourSubstr(
            $bytes,
            self::SERIALIZE_HEADER_BYTES,
            Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE
        );
    }
}
<?php

namespace Defuse\Crypto\Exception;

class BadFormatException extends \Defuse\Crypto\Exception\CryptoException
{
}
<?php

namespace Defuse\Crypto\Exception;

class CryptoException extends \Exception
{
}
<?php

namespace Defuse\Crypto\Exception;

class EnvironmentIsBrokenException extends \Defuse\Crypto\Exception\CryptoException
{
}
<?php

namespace Defuse\Crypto\Exception;

class IOException extends \Defuse\Crypto\Exception\CryptoException
{
}
<?php

namespace Defuse\Crypto\Exception;

class WrongKeyOrModifiedCiphertextException extends \Defuse\Crypto\Exception\CryptoException
{
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class File
{
    /**
     * Encrypts the input file, saving the ciphertext to the output file.
     *
     * @param string $inputFilename
     * @param string $outputFilename
     * @param Key    $key
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     */
    public static function encryptFile($inputFilename, $outputFilename, Key $key)
    {
        self::encryptFileInternal(
            $inputFilename,
            $outputFilename,
            KeyOrPassword::createFromKey($key)
        );
    }

    /**
     * Encrypts a file with a password, using a slow key derivation function to
     * make password cracking more expensive.
     *
     * @param string $inputFilename
     * @param string $outputFilename
     * @param string $password
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     */
    public static function encryptFileWithPassword(
        $inputFilename,
        $outputFilename,
        #[\SensitiveParameter]
        $password
    )
    {
        self::encryptFileInternal(
            $inputFilename,
            $outputFilename,
            KeyOrPassword::createFromPassword($password)
        );
    }

    /**
     * Decrypts the input file, saving the plaintext to the output file.
     *
     * @param string $inputFilename
     * @param string $outputFilename
     * @param Key    $key
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function decryptFile($inputFilename, $outputFilename, Key $key)
    {
        self::decryptFileInternal(
            $inputFilename,
            $outputFilename,
            KeyOrPassword::createFromKey($key)
        );
    }

    /**
     * Decrypts a file with a password, using a slow key derivation function to
     * make password cracking more expensive.
     *
     * @param string $inputFilename
     * @param string $outputFilename
     * @param string $password
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function decryptFileWithPassword(
        $inputFilename,
        $outputFilename,
        #[\SensitiveParameter]
        $password
    )
    {
        self::decryptFileInternal(
            $inputFilename,
            $outputFilename,
            KeyOrPassword::createFromPassword($password)
        );
    }

    /**
     * Takes two resource handles and encrypts the contents of the first,
     * writing the ciphertext into the second.
     *
     * @param resource $inputHandle
     * @param resource $outputHandle
     * @param Key      $key
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function encryptResource($inputHandle, $outputHandle, Key $key)
    {
        self::encryptResourceInternal(
            $inputHandle,
            $outputHandle,
            KeyOrPassword::createFromKey($key)
        );
    }

    /**
     * Encrypts the contents of one resource handle into another with a
     * password, using a slow key derivation function to make password cracking
     * more expensive.
     *
     * @param resource $inputHandle
     * @param resource $outputHandle
     * @param string   $password
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function encryptResourceWithPassword(
        $inputHandle,
        $outputHandle,
        #[\SensitiveParameter]
        $password
    )
    {
        self::encryptResourceInternal(
            $inputHandle,
            $outputHandle,
            KeyOrPassword::createFromPassword($password)
        );
    }

    /**
     * Takes two resource handles and decrypts the contents of the first,
     * writing the plaintext into the second.
     *
     * @param resource $inputHandle
     * @param resource $outputHandle
     * @param Key      $key
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function decryptResource($inputHandle, $outputHandle, Key $key)
    {
        self::decryptResourceInternal(
            $inputHandle,
            $outputHandle,
            KeyOrPassword::createFromKey($key)
        );
    }

    /**
     * Decrypts the contents of one resource into another with a password, using
     * a slow key derivation function to make password cracking more expensive.
     *
     * @param resource $inputHandle
     * @param resource $outputHandle
     * @param string   $password
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     */
    public static function decryptResourceWithPassword(
        $inputHandle,
        $outputHandle,
        #[\SensitiveParameter]
        $password
    )
    {
        self::decryptResourceInternal(
            $inputHandle,
            $outputHandle,
            KeyOrPassword::createFromPassword($password)
        );
    }

    /**
     * Encrypts a file with either a key or a password.
     *
     * @param string        $inputFilename
     * @param string        $outputFilename
     * @param KeyOrPassword $secret
     * @return void
     *
     * @throws Ex\CryptoException
     * @throws Ex\IOException
     */
    private static function encryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
    {
        if (file_exists($inputFilename) && file_exists($outputFilename) && realpath($inputFilename) === realpath($outputFilename)) {
            throw new Ex\IOException('Input and output filenames must be different.');
        }

        /* Open the input file. */
        self::removePHPUnitErrorHandler();
        $if = @\fopen($inputFilename, 'rb');
        self::restorePHPUnitErrorHandler();
        if ($if === false) {
            throw new Ex\IOException(
                'Cannot open input file for encrypting: ' .
                self::getLastErrorMessage()
            );
        }
        if (\is_callable('\\stream_set_read_buffer')) {
            /* This call can fail, but the only consequence is performance. */
            \stream_set_read_buffer($if, 0);
        }

        /* Open the output file. */
        self::removePHPUnitErrorHandler();
        $of = @\fopen($outputFilename, 'wb');
        self::restorePHPUnitErrorHandler();
        if ($of === false) {
            \fclose($if);
            throw new Ex\IOException(
                'Cannot open output file for encrypting: ' .
                self::getLastErrorMessage()
            );
        }
        if (\is_callable('\\stream_set_write_buffer')) {
            /* This call can fail, but the only consequence is performance. */
            \stream_set_write_buffer($of, 0);
        }

        /* Perform the encryption. */
        try {
            self::encryptResourceInternal($if, $of, $secret);
        } catch (Ex\CryptoException $ex) {
            \fclose($if);
            \fclose($of);
            throw $ex;
        }

        /* Close the input file. */
        if (\fclose($if) === false) {
            \fclose($of);
            throw new Ex\IOException(
                'Cannot close input file after encrypting'
            );
        }

        /* Close the output file. */
        if (\fclose($of) === false) {
            throw new Ex\IOException(
                'Cannot close output file after encrypting'
            );
        }
    }

    /**
     * Decrypts a file with either a key or a password.
     *
     * @param string        $inputFilename
     * @param string        $outputFilename
     * @param KeyOrPassword $secret
     * @return void
     *
     * @throws Ex\CryptoException
     * @throws Ex\IOException
     */
    private static function decryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
    {
        if (file_exists($inputFilename) && file_exists($outputFilename) && realpath($inputFilename) === realpath($outputFilename)) {
            throw new Ex\IOException('Input and output filenames must be different.');
        }

        /* Open the input file. */
        self::removePHPUnitErrorHandler();
        $if = @\fopen($inputFilename, 'rb');
        self::restorePHPUnitErrorHandler();
        if ($if === false) {
            throw new Ex\IOException(
                'Cannot open input file for decrypting: ' .
                self::getLastErrorMessage()
            );
        }

        if (\is_callable('\\stream_set_read_buffer')) {
            /* This call can fail, but the only consequence is performance. */
            \stream_set_read_buffer($if, 0);
        }

        /* Open the output file. */
        self::removePHPUnitErrorHandler();
        $of = @\fopen($outputFilename, 'wb');
        self::restorePHPUnitErrorHandler();
        if ($of === false) {
            \fclose($if);
            throw new Ex\IOException(
                'Cannot open output file for decrypting: ' .
                self::getLastErrorMessage()
            );
        }

        if (\is_callable('\\stream_set_write_buffer')) {
            /* This call can fail, but the only consequence is performance. */
            \stream_set_write_buffer($of, 0);
        }

        /* Perform the decryption. */
        try {
            self::decryptResourceInternal($if, $of, $secret);
        } catch (Ex\CryptoException $ex) {
            \fclose($if);
            \fclose($of);
            throw $ex;
        }

        /* Close the input file. */
        if (\fclose($if) === false) {
            \fclose($of);
            throw new Ex\IOException(
                'Cannot close input file after decrypting'
            );
        }

        /* Close the output file. */
        if (\fclose($of) === false) {
            throw new Ex\IOException(
                'Cannot close output file after decrypting'
            );
        }
    }

    /**
     * Encrypts a resource with either a key or a password.
     *
     * @param resource      $inputHandle
     * @param resource      $outputHandle
     * @param KeyOrPassword $secret
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @psalm-suppress PossiblyInvalidArgument
     *      Fixes erroneous errors caused by PHP 7.2 switching the return value
     *      of hash_init from a resource to a HashContext.
     */
    private static function encryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
    {
        if (! \is_resource($inputHandle)) {
            throw new Ex\IOException(
                'Input handle must be a resource!'
            );
        }
        if (! \is_resource($outputHandle)) {
            throw new Ex\IOException(
                'Output handle must be a resource!'
            );
        }

        $inputStat = \fstat($inputHandle);
        $inputSize = $inputStat['size'];

        $file_salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
        $keys = $secret->deriveKeys($file_salt);
        $ekey = $keys->getEncryptionKey();
        $akey = $keys->getAuthenticationKey();

        $ivsize = Core::BLOCK_BYTE_SIZE;
        $iv     = Core::secureRandom($ivsize);

        /* Initialize a streaming HMAC state. */
        /** @var mixed $hmac */
        $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
        Core::ensureTrue(
            \is_resource($hmac) || \is_object($hmac),
            'Cannot initialize a hash context'
        );

        /* Write the header, salt, and IV. */
        self::writeBytes(
            $outputHandle,
            Core::CURRENT_VERSION . $file_salt . $iv,
            Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize
        );

        /* Add the header, salt, and IV to the HMAC. */
        \hash_update($hmac, Core::CURRENT_VERSION);
        \hash_update($hmac, $file_salt);
        \hash_update($hmac, $iv);

        /* $thisIv will be incremented after each call to the encryption. */
        $thisIv = $iv;

        /* How many blocks do we encrypt at a time? We increment by this value. */
        /**
         * @psalm-suppress RedundantCast
         */
        $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);

        /* Loop until we reach the end of the input file. */
        $at_file_end = false;
        while (! (\feof($inputHandle) || $at_file_end)) {
            /* Find out if we can read a full buffer, or only a partial one. */
            /** @var int */
            $pos = \ftell($inputHandle);
            if (!\is_int($pos)) {
                throw new Ex\IOException(
                    'Could not get current position in input file during encryption'
                );
            }
            if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) {
                /* We're at the end of the file, so we need to break out of the loop. */
                $at_file_end = true;
                $read = self::readBytes(
                    $inputHandle,
                    $inputSize - $pos
                );
            } else {
                $read = self::readBytes(
                    $inputHandle,
                    Core::BUFFER_BYTE_SIZE
                );
            }

            /* Encrypt this buffer. */
            /** @var string */
            $encrypted = \openssl_encrypt(
                $read,
                Core::CIPHER_METHOD,
                $ekey,
                OPENSSL_RAW_DATA,
                $thisIv
            );

            Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error');

            /* Write this buffer's ciphertext. */
            self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
            /* Add this buffer's ciphertext to the HMAC. */
            \hash_update($hmac, $encrypted);

            /* Increment the counter by the number of blocks in a buffer. */
            $thisIv = Core::incrementCounter($thisIv, $inc);
            /* WARNING: Usually, unless the file is a multiple of the buffer
             * size, $thisIv will contain an incorrect value here on the last
             * iteration of this loop. */
        }

        /* Get the HMAC and append it to the ciphertext. */
        $final_mac = \hash_final($hmac, true);
        self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE);
    }

    /**
     * Decrypts a file-backed resource with either a key or a password.
     *
     * @param resource      $inputHandle
     * @param resource      $outputHandle
     * @param KeyOrPassword $secret
     * @return void
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\IOException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     * @psalm-suppress PossiblyInvalidArgument
     *      Fixes erroneous errors caused by PHP 7.2 switching the return value
     *      of hash_init from a resource to a HashContext.
     */
    public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
    {
        if (! \is_resource($inputHandle)) {
            throw new Ex\IOException(
                'Input handle must be a resource!'
            );
        }
        if (! \is_resource($outputHandle)) {
            throw new Ex\IOException(
                'Output handle must be a resource!'
            );
        }

        /* Make sure the file is big enough for all the reads we need to do. */
        $stat = \fstat($inputHandle);
        if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Input file is too small to have been created by this library.'
            );
        }

        /* Check the version header. */
        $header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE);
        if ($header !== Core::CURRENT_VERSION) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Bad version header.'
            );
        }

        /* Get the salt. */
        $file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE);

        /* Get the IV. */
        $ivsize = Core::BLOCK_BYTE_SIZE;
        $iv     = self::readBytes($inputHandle, $ivsize);

        /* Derive the authentication and encryption keys. */
        $keys = $secret->deriveKeys($file_salt);
        $ekey = $keys->getEncryptionKey();
        $akey = $keys->getAuthenticationKey();

        /* We'll store the MAC of each buffer-sized chunk as we verify the
         * actual MAC, so that we can check them again when decrypting. */
        $macs = [];

        /* $thisIv will be incremented after each call to the decryption. */
        $thisIv = $iv;

        /* How many blocks do we encrypt at a time? We increment by this value. */
        /**
         * @psalm-suppress RedundantCast
         */
        $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);

        /* Get the HMAC. */
        if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === -1) {
            throw new Ex\IOException(
                'Cannot seek to beginning of MAC within input file'
            );
        }

        /* Get the position of the last byte in the actual ciphertext. */
        /** @var int $cipher_end */
        $cipher_end = \ftell($inputHandle);
        if (!\is_int($cipher_end)) {
            throw new Ex\IOException(
                'Cannot read input file'
            );
        }
        /* We have the position of the first byte of the HMAC. Go back by one. */
        --$cipher_end;

        /* Read the HMAC. */
        /** @var string $stored_mac */
        $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE);

        /* Initialize a streaming HMAC state. */
        /** @var mixed $hmac */
        $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
        Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context');

        /* Reset file pointer to the beginning of the file after the header */
        if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) {
            throw new Ex\IOException(
                'Cannot read seek within input file'
            );
        }

        /* Seek to the start of the actual ciphertext. */
        if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === -1) {
            throw new Ex\IOException(
                'Cannot seek input file to beginning of ciphertext'
            );
        }

        /* PASS #1: Calculating the HMAC. */

        \hash_update($hmac, $header);
        \hash_update($hmac, $file_salt);
        \hash_update($hmac, $iv);
        /** @var mixed $hmac2 */
        $hmac2 = \hash_copy($hmac);

        $break = false;
        while (! $break) {
            /** @var int $pos */
            $pos = \ftell($inputHandle);
            if (!\is_int($pos)) {
                throw new Ex\IOException(
                    'Could not get current position in input file during decryption'
                );
            }

            /* Read the next buffer-sized chunk (or less). */
            if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
                $break = true;
                $read  = self::readBytes(
                    $inputHandle,
                    $cipher_end - $pos + 1
                );
            } else {
                $read = self::readBytes(
                    $inputHandle,
                    Core::BUFFER_BYTE_SIZE
                );
            }

            /* Update the HMAC. */
            \hash_update($hmac, $read);

            /* Remember this buffer-sized chunk's HMAC. */
            /** @var mixed $chunk_mac */
            $chunk_mac = \hash_copy($hmac);
            Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context');
            $macs []= \hash_final($chunk_mac);
        }

        /* Get the final HMAC, which should match the stored one. */
        /** @var string $final_mac */
        $final_mac = \hash_final($hmac, true);

        /* Verify the HMAC. */
        if (! Core::hashEquals($final_mac, $stored_mac)) {
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                'Integrity check failed.'
            );
        }

        /* PASS #2: Decrypt and write output. */

        /* Rewind to the start of the actual ciphertext. */
        if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) {
            throw new Ex\IOException(
                'Could not move the input file pointer during decryption'
            );
        }

        $at_file_end = false;
        while (! $at_file_end) {
            /** @var int $pos */
            $pos = \ftell($inputHandle);
            if (!\is_int($pos)) {
                throw new Ex\IOException(
                    'Could not get current position in input file during decryption'
                );
            }

            /* Read the next buffer-sized chunk (or less). */
            if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
                $at_file_end = true;
                $read   = self::readBytes(
                    $inputHandle,
                    $cipher_end - $pos + 1
                );
            } else {
                $read = self::readBytes(
                    $inputHandle,
                    Core::BUFFER_BYTE_SIZE
                );
            }

            /* Recalculate the MAC (so far) and compare it with the one we
             * remembered from pass #1 to ensure attackers didn't change the
             * ciphertext after MAC verification. */
            \hash_update($hmac2, $read);
            /** @var mixed $calc_mac */
            $calc_mac = \hash_copy($hmac2);
            Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context');
            $calc = \hash_final($calc_mac);

            if (empty($macs)) {
                throw new Ex\WrongKeyOrModifiedCiphertextException(
                    'File was modified after MAC verification'
                );
            } elseif (! Core::hashEquals(\array_shift($macs), $calc)) {
                throw new Ex\WrongKeyOrModifiedCiphertextException(
                    'File was modified after MAC verification'
                );
            }

            /* Decrypt this buffer-sized chunk. */
            /** @var string $decrypted */
            $decrypted = \openssl_decrypt(
                $read,
                Core::CIPHER_METHOD,
                $ekey,
                OPENSSL_RAW_DATA,
                $thisIv
            );
            Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error');

            /* Write the plaintext to the output file. */
            self::writeBytes(
                $outputHandle,
                $decrypted,
                Core::ourStrlen($decrypted)
            );

            /* Increment the IV by the amount of blocks in a buffer. */
            /** @var string $thisIv */
            $thisIv = Core::incrementCounter($thisIv, $inc);
            /* WARNING: Usually, unless the file is a multiple of the buffer
             * size, $thisIv will contain an incorrect value here on the last
             * iteration of this loop. */
        }
    }

    /**
     * Read from a stream; prevent partial reads.
     *
     * @param resource $stream
     * @param int      $num_bytes
     * @return string
     *
     * @throws Ex\IOException
     * @throws Ex\EnvironmentIsBrokenException
     */
    public static function readBytes($stream, $num_bytes)
    {
        Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes');

        if ($num_bytes === 0) {
            return '';
        }

        $buf       = '';
        $remaining = $num_bytes;
        while ($remaining > 0 && ! \feof($stream)) {
            /** @var string $read */
            $read = \fread($stream, $remaining);
            if (!\is_string($read)) {
                throw new Ex\IOException(
                    'Could not read from the file'
                );
            }
            $buf .= $read;
            $remaining -= Core::ourStrlen($read);
        }
        if (Core::ourStrlen($buf) !== $num_bytes) {
            throw new Ex\IOException(
                'Tried to read past the end of the file'
            );
        }
        return $buf;
    }

    /**
     * Write to a stream; prevents partial writes.
     *
     * @param resource $stream
     * @param string   $buf
     * @param int      $num_bytes
     * @return int
     *
     * @throws Ex\IOException
     */
    public static function writeBytes($stream, $buf, $num_bytes = null)
    {
        $bufSize = Core::ourStrlen($buf);
        if ($num_bytes === null) {
            $num_bytes = $bufSize;
        }
        if ($num_bytes > $bufSize) {
            throw new Ex\IOException(
                'Trying to write more bytes than the buffer contains.'
            );
        }
        if ($num_bytes < 0) {
            throw new Ex\IOException(
                'Tried to write less than 0 bytes'
            );
        }
        $remaining = $num_bytes;
        while ($remaining > 0) {
            /** @var int $written */
            $written = \fwrite($stream, $buf, $remaining);
            if (!\is_int($written)) {
                throw new Ex\IOException(
                    'Could not write to the file'
                );
            }
            $buf = (string) Core::ourSubstr($buf, $written, null);
            $remaining -= $written;
        }
        return $num_bytes;
    }

    /**
     * Returns the last PHP error's or warning's message string.
     *
     * @return string
     */
    private static function getLastErrorMessage()
    {
        $error = error_get_last();
        if ($error === null) {
            return '[no PHP error, or you have a custom error handler set]';
        } else {
            return $error['message'];
        }
    }

    /**
     * PHPUnit sets an error handler, which prevents getLastErrorMessage() from working,
     * because error_get_last does not work when custom handlers are set.
     *
     * This is a workaround, which should be a no-op in production deployments, to make
     * getLastErrorMessage() return the error messages that the PHPUnit tests expect.
     *
     * If, in a production deployment, a custom error handler is set, the exception
     * handling will still work as usual, but the error messages will be confusing.
     *
     * @return void
     */
    private static function removePHPUnitErrorHandler() {
        if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
            set_error_handler(null);
        }
    }

    /**
     * Undoes what removePHPUnitErrorHandler did.
     *
     * @return void
     */
    private static function restorePHPUnitErrorHandler() {
        if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
            restore_error_handler();
        }
    }
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class Key
{
    const KEY_CURRENT_VERSION = "\xDE\xF0\x00\x00";
    const KEY_BYTE_SIZE       = 32;

    /**
     * @var string
     */
    private $key_bytes;

    /**
     * Creates new random key.
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return Key
     */
    public static function createNewRandomKey()
    {
        return new Key(Core::secureRandom(self::KEY_BYTE_SIZE));
    }

    /**
     * Loads a Key from its encoded form.
     *
     * By default, this function will call Encoding::trimTrailingWhitespace()
     * to remove trailing CR, LF, NUL, TAB, and SPACE characters, which are
     * commonly appended to files when working with text editors.
     *
     * @param string $saved_key_string
     * @param bool $do_not_trim (default: false)
     *
     * @throws Ex\BadFormatException
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return Key
     */
    public static function loadFromAsciiSafeString(
        #[\SensitiveParameter]
        $saved_key_string,
        $do_not_trim = false
    )
    {
        if (!$do_not_trim) {
            $saved_key_string = Encoding::trimTrailingWhitespace($saved_key_string);
        }
        $key_bytes = Encoding::loadBytesFromChecksummedAsciiSafeString(self::KEY_CURRENT_VERSION, $saved_key_string);
        return new Key($key_bytes);
    }

    /**
     * Encodes the Key into a string of printable ASCII characters.
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    public function saveToAsciiSafeString()
    {
        return Encoding::saveBytesToChecksummedAsciiSafeString(
            self::KEY_CURRENT_VERSION,
            $this->key_bytes
        );
    }

    /**
     * Gets the raw bytes of the key.
     *
     * @return string
     */
    public function getRawBytes()
    {
        return $this->key_bytes;
    }

    /**
     * Constructs a new Key object from a string of raw bytes.
     *
     * @param string $bytes
     *
     * @throws Ex\EnvironmentIsBrokenException
     */
    private function __construct(
        #[\SensitiveParameter]
        $bytes
    )
    {
        Core::ensureTrue(
            Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE,
            'Bad key length.'
        );
        $this->key_bytes = $bytes;
    }

}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class KeyOrPassword
{
    const PBKDF2_ITERATIONS    = 100000;
    const SECRET_TYPE_KEY      = 1;
    const SECRET_TYPE_PASSWORD = 2;

    /**
     * @var int
     */
    private $secret_type = 0;

    /**
     * @var Key|string
     */
    private $secret;

    /**
     * Initializes an instance of KeyOrPassword from a key.
     *
     * @param Key $key
     *
     * @return KeyOrPassword
     */
    public static function createFromKey(Key $key)
    {
        return new KeyOrPassword(self::SECRET_TYPE_KEY, $key);
    }

    /**
     * Initializes an instance of KeyOrPassword from a password.
     *
     * @param string $password
     *
     * @return KeyOrPassword
     */
    public static function createFromPassword(
        #[\SensitiveParameter]
        $password
    )
    {
        return new KeyOrPassword(self::SECRET_TYPE_PASSWORD, $password);
    }

    /**
     * Derives authentication and encryption keys from the secret, using a slow
     * key derivation function if the secret is a password.
     *
     * @param string $salt
     *
     * @throws Ex\CryptoException
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return DerivedKeys
     */
    public function deriveKeys($salt)
    {
        Core::ensureTrue(
            Core::ourStrlen($salt) === Core::SALT_BYTE_SIZE,
            'Bad salt.'
        );

        if ($this->secret_type === self::SECRET_TYPE_KEY) {
            Core::ensureTrue($this->secret instanceof Key);
            /**
             * @psalm-suppress PossiblyInvalidMethodCall
             */
            $akey = Core::HKDF(
                Core::HASH_FUNCTION_NAME,
                $this->secret->getRawBytes(),
                Core::KEY_BYTE_SIZE,
                Core::AUTHENTICATION_INFO_STRING,
                $salt
            );
            /**
             * @psalm-suppress PossiblyInvalidMethodCall
             */
            $ekey = Core::HKDF(
                Core::HASH_FUNCTION_NAME,
                $this->secret->getRawBytes(),
                Core::KEY_BYTE_SIZE,
                Core::ENCRYPTION_INFO_STRING,
                $salt
            );
            return new DerivedKeys($akey, $ekey);
        } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
            Core::ensureTrue(\is_string($this->secret));
            /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
             * GitHub issue #230. The fix is to pre-hash the password to ensure
             * it is short. We do the prehashing here instead of in pbkdf2() so
             * that pbkdf2() still computes the function as defined by the
             * standard. */

            /**
             * @psalm-suppress PossiblyInvalidArgument
             */
            $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true);

            $prekey = Core::pbkdf2(
                Core::HASH_FUNCTION_NAME,
                $prehash,
                $salt,
                self::PBKDF2_ITERATIONS,
                Core::KEY_BYTE_SIZE,
                true
            );
            $akey = Core::HKDF(
                Core::HASH_FUNCTION_NAME,
                $prekey,
                Core::KEY_BYTE_SIZE,
                Core::AUTHENTICATION_INFO_STRING,
                $salt
            );
            /* Note the cryptographic re-use of $salt here. */
            $ekey = Core::HKDF(
                Core::HASH_FUNCTION_NAME,
                $prekey,
                Core::KEY_BYTE_SIZE,
                Core::ENCRYPTION_INFO_STRING,
                $salt
            );
            return new DerivedKeys($akey, $ekey);
        } else {
            throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
        }
    }

    /**
     * Constructor for KeyOrPassword.
     *
     * @param int   $secret_type
     * @param mixed $secret      (either a Key or a password string)
     */
    private function __construct(
        $secret_type,
        #[\SensitiveParameter]
        $secret
    )
    {
        // The constructor is private, so these should never throw.
        if ($secret_type === self::SECRET_TYPE_KEY) {
            Core::ensureTrue($secret instanceof Key);
        } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) {
            Core::ensureTrue(\is_string($secret));
        } else {
            throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
        }
        $this->secret_type = $secret_type;
        $this->secret = $secret;
    }
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

final class KeyProtectedByPassword
{
    const PASSWORD_KEY_CURRENT_VERSION = "\xDE\xF1\x00\x00";

    /**
     * @var string
     */
    private $encrypted_key = '';

    /**
     * Creates a random key protected by the provided password.
     *
     * @param string $password
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return KeyProtectedByPassword
     */
    public static function createRandomPasswordProtectedKey(
        #[\SensitiveParameter]
        $password
    )
    {
        $inner_key = Key::createNewRandomKey();
        /* The password is hashed as a form of poor-man's domain separation
         * between this use of encryptWithPassword() and other uses of
         * encryptWithPassword() that the user may also be using as part of the
         * same protocol. */
        $encrypted_key = Crypto::encryptWithPassword(
            $inner_key->saveToAsciiSafeString(),
            \hash(Core::HASH_FUNCTION_NAME, $password, true),
            true
        );

        return new KeyProtectedByPassword($encrypted_key);
    }

    /**
     * Loads a KeyProtectedByPassword from its encoded form.
     *
     * @param string $saved_key_string
     *
     * @throws Ex\BadFormatException
     *
     * @return KeyProtectedByPassword
     */
    public static function loadFromAsciiSafeString(
        #[\SensitiveParameter]
        $saved_key_string
    )
    {
        $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString(
            self::PASSWORD_KEY_CURRENT_VERSION,
            $saved_key_string
        );
        return new KeyProtectedByPassword($encrypted_key);
    }

    /**
     * Encodes the KeyProtectedByPassword into a string of printable ASCII
     * characters.
     *
     * @throws Ex\EnvironmentIsBrokenException
     *
     * @return string
     */
    public function saveToAsciiSafeString()
    {
        return Encoding::saveBytesToChecksummedAsciiSafeString(
            self::PASSWORD_KEY_CURRENT_VERSION,
            $this->encrypted_key
        );
    }

    /**
     * Decrypts the protected key, returning an unprotected Key object that can
     * be used for encryption and decryption.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     *
     * @param string $password
     * @return Key
     */
    public function unlockKey(
        #[\SensitiveParameter]
        $password
    )
    {
        try {
            $inner_key_encoded = Crypto::decryptWithPassword(
                $this->encrypted_key,
                \hash(Core::HASH_FUNCTION_NAME, $password, true),
                true
            );
            return Key::loadFromAsciiSafeString($inner_key_encoded);
        } catch (Ex\BadFormatException $ex) {
            /* This should never happen unless an attacker replaced the
             * encrypted key ciphertext with some other ciphertext that was
             * encrypted with the same password. We transform the exception type
             * here in order to make the API simpler, avoiding the need to
             * document that this method might throw an Ex\BadFormatException. */
            throw new Ex\WrongKeyOrModifiedCiphertextException(
                "The decrypted key was found to be in an invalid format. " .
                "This very likely indicates it was modified by an attacker."
            );
        }
    }

    /**
     * Changes the password.
     *
     * @param string $current_password
     * @param string $new_password
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @throws Ex\WrongKeyOrModifiedCiphertextException
     *
     * @return KeyProtectedByPassword
     */
    public function changePassword(
        #[\SensitiveParameter]
        $current_password,
        #[\SensitiveParameter]
        $new_password
    )
    {
        $inner_key = $this->unlockKey($current_password);
        /* The password is hashed as a form of poor-man's domain separation
         * between this use of encryptWithPassword() and other uses of
         * encryptWithPassword() that the user may also be using as part of the
         * same protocol. */
        $encrypted_key = Crypto::encryptWithPassword(
            $inner_key->saveToAsciiSafeString(),
            \hash(Core::HASH_FUNCTION_NAME, $new_password, true),
            true
        );

        $this->encrypted_key = $encrypted_key;

        return $this;
    }

    /**
     * Constructor for KeyProtectedByPassword.
     *
     * @param string $encrypted_key
     */
    private function __construct($encrypted_key)
    {
        $this->encrypted_key = $encrypted_key;
    }
}
<?php

namespace Defuse\Crypto;

use Defuse\Crypto\Exception as Ex;

/*
 * We're using static class inheritance to get access to protected methods
 * inside Crypto. To make it easy to know where the method we're calling can be
 * found, within this file, prefix calls with `Crypto::` or `RuntimeTests::`,
 * and don't use `self::`.
 */

class RuntimeTests extends Crypto
{
    /**
     * Runs the runtime tests.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @return void
     */
    public static function runtimeTest()
    {
        // 0: Tests haven't been run yet.
        // 1: Tests have passed.
        // 2: Tests are running right now.
        // 3: Tests have failed.
        static $test_state = 0;

        if ($test_state === 1 || $test_state === 2) {
            return;
        }

        if ($test_state === 3) {
            /* If an intermittent problem caused a test to fail previously, we
             * want that to be indicated to the user with every call to this
             * library. This way, if the user first does something they really
             * don't care about, and just ignores all exceptions, they won't get
             * screwed when they then start to use the library for something
             * they do care about. */
            throw new Ex\EnvironmentIsBrokenException('Tests failed previously.');
        }

        try {
            $test_state = 2;

            Core::ensureFunctionExists('openssl_get_cipher_methods');
            if (\in_array(Core::CIPHER_METHOD, \openssl_get_cipher_methods()) === false) {
                throw new Ex\EnvironmentIsBrokenException(
                    'Cipher method not supported. This is normally caused by an outdated ' .
                    'version of OpenSSL (and/or OpenSSL compiled for FIPS compliance). ' .
                    'Please upgrade to a newer version of OpenSSL that supports ' .
                    Core::CIPHER_METHOD . ' to use this library.'
                );
            }

            RuntimeTests::AESTestVector();
            RuntimeTests::HMACTestVector();
            RuntimeTests::HKDFTestVector();

            RuntimeTests::testEncryptDecrypt();
            Core::ensureTrue(Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) === Core::KEY_BYTE_SIZE);

            Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING);
        } catch (Ex\EnvironmentIsBrokenException $ex) {
            // Do this, otherwise it will stay in the "tests are running" state.
            $test_state = 3;
            throw $ex;
        }

        // Change this to '0' make the tests always re-run (for benchmarking).
        $test_state = 1;
    }

    /**
     * High-level tests of Crypto operations.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @return void
     */
    private static function testEncryptDecrypt()
    {
        $key  = Key::createNewRandomKey();
        $data = "EnCrYpT EvErYThInG\x00\x00";

        // Make sure encrypting then decrypting doesn't change the message.
        $ciphertext = Crypto::encrypt($data, $key, true);
        try {
            $decrypted = Crypto::decrypt($ciphertext, $key, true);
        } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) {
            // It's important to catch this and change it into a
            // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick
            // the user into thinking it's just an invalid ciphertext!
            throw new Ex\EnvironmentIsBrokenException();
        }
        Core::ensureTrue($decrypted === $data);

        // Modifying the ciphertext: Appending a string.
        try {
            Crypto::decrypt($ciphertext . 'a', $key, true);
            throw new Ex\EnvironmentIsBrokenException();
        } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
        }

        // Modifying the ciphertext: Changing an HMAC byte.
        $indices_to_change = [
            0, // The header.
            Core::HEADER_VERSION_SIZE + 1, // the salt
            Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV
            Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext
        ];

        foreach ($indices_to_change as $index) {
            try {
                $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256);
                Crypto::decrypt($ciphertext, $key, true);
                throw new Ex\EnvironmentIsBrokenException();
            } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
            }
        }

        // Decrypting with the wrong key.
        $key        = Key::createNewRandomKey();
        $data       = 'abcdef';
        $ciphertext = Crypto::encrypt($data, $key, true);
        $wrong_key  = Key::createNewRandomKey();
        try {
            Crypto::decrypt($ciphertext, $wrong_key, true);
            throw new Ex\EnvironmentIsBrokenException();
        } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
        }

        // Ciphertext too small.
        $key        = Key::createNewRandomKey();
        $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1);
        try {
            Crypto::decrypt($ciphertext, $key, true);
            throw new Ex\EnvironmentIsBrokenException();
        } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
        }
    }

    /**
     * Test HKDF against test vectors.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @return void
     */
    private static function HKDFTestVector()
    {
        // HKDF test vectors from RFC 5869

        // Test Case 1
        $ikm    = \str_repeat("\x0b", 22);
        $salt   = Encoding::hexToBin('000102030405060708090a0b0c');
        $info   = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9');
        $length = 42;
        $okm    = Encoding::hexToBin(
            '3cb25f25faacd57a90434f64d0362f2a' .
            '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' .
            '34007208d5b887185865'
        );
        $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt);
        Core::ensureTrue($computed_okm === $okm);

        // Test Case 7
        $ikm    = \str_repeat("\x0c", 22);
        $length = 42;
        $okm    = Encoding::hexToBin(
            '2c91117204d745f3500d636a62f64f0a' .
            'b3bae548aa53d423b0d1f27ebba6f5e5' .
            '673a081d70cce7acfc48'
        );
        $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null);
        Core::ensureTrue($computed_okm === $okm);
    }

    /**
     * Test HMAC against test vectors.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @return void
     */
    private static function HMACTestVector()
    {
        // HMAC test vector From RFC 4231 (Test Case 1)
        $key     = \str_repeat("\x0b", 20);
        $data    = 'Hi There';
        $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7';
        Core::ensureTrue(
            \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct
        );
    }

    /**
     * Test AES against test vectors.
     *
     * @throws Ex\EnvironmentIsBrokenException
     * @return void
     */
    private static function AESTestVector()
    {
        // AES CTR mode test vector from NIST SP 800-38A
        $key = Encoding::hexToBin(
            '603deb1015ca71be2b73aef0857d7781' .
            '1f352c073b6108d72d9810a30914dff4'
        );
        $iv        = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
        $plaintext = Encoding::hexToBin(
            '6bc1bee22e409f96e93d7e117393172a' .
            'ae2d8a571e03ac9c9eb76fac45af8e51' .
            '30c81c46a35ce411e5fbc1191a0a52ef' .
            'f69f2445df4f9b17ad2b417be66c3710'
        );
        $ciphertext = Encoding::hexToBin(
            '601ec313775789a5b7a7f504bbf3d228' .
            'f443e3ca4d62b59aca84e990cacaf5c5' .
            '2b0930daa23de94ce87017ba2d84988d' .
            'dfc9c58db67aada613c2dd08457941a6'
        );

        $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
        Core::ensureTrue($computed_ciphertext === $ciphertext);

        $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
        Core::ensureTrue($computed_plaintext === $plaintext);
    }
}
<?php

declare(strict_types=1);

namespace Doctrine\Deprecations;

use Psr\Log\LoggerInterface;

use function array_key_exists;
use function array_reduce;
use function assert;
use function debug_backtrace;
use function sprintf;
use function str_replace;
use function strpos;
use function strrpos;
use function substr;
use function trigger_error;

use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const DIRECTORY_SEPARATOR;
use const E_USER_DEPRECATED;

/**
 * Manages Deprecation logging in different ways.
 *
 * By default triggered exceptions are not logged.
 *
 * To enable different deprecation logging mechanisms you can call the
 * following methods:
 *
 *  - Minimal collection of deprecations via getTriggeredDeprecations()
 *    \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
 *
 *  - Uses @trigger_error with E_USER_DEPRECATED
 *    \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
 *
 *  - Sends deprecation messages via a PSR-3 logger
 *    \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
 *
 * Packages that trigger deprecations should use the `trigger()` or
 * `triggerIfCalledFromOutside()` methods.
 */
class Deprecation
{
    private const TYPE_NONE               = 0;
    private const TYPE_TRACK_DEPRECATIONS = 1;
    private const TYPE_TRIGGER_ERROR      = 2;
    private const TYPE_PSR_LOGGER         = 4;

    /** @var int-mask-of<self::TYPE_*>|null */
    private static $type;

    /** @var LoggerInterface|null */
    private static $logger;

    /** @var array<string,bool> */
    private static $ignoredPackages = [];

    /** @var array<string,int> */
    private static $triggeredDeprecations = [];

    /** @var array<string,bool> */
    private static $ignoredLinks = [];

    /** @var bool */
    private static $deduplication = true;

    /**
     * Trigger a deprecation for the given package and identfier.
     *
     * The link should point to a Github issue or Wiki entry detailing the
     * deprecation. It is additionally used to de-duplicate the trigger of the
     * same deprecation during a request.
     *
     * @param float|int|string $args
     */
    public static function trigger(string $package, string $link, string $message, ...$args): void
    {
        $type = self::$type ?? self::getTypeFromEnv();

        if ($type === self::TYPE_NONE) {
            return;
        }

        if (isset(self::$ignoredLinks[$link])) {
            return;
        }

        if (array_key_exists($link, self::$triggeredDeprecations)) {
            self::$triggeredDeprecations[$link]++;
        } else {
            self::$triggeredDeprecations[$link] = 1;
        }

        if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
            return;
        }

        if (isset(self::$ignoredPackages[$package])) {
            return;
        }

        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);

        $message = sprintf($message, ...$args);

        self::delegateTriggerToBackend($message, $backtrace, $link, $package);
    }

    /**
     * Trigger a deprecation for the given package and identifier when called from outside.
     *
     * "Outside" means we assume that $package is currently installed as a
     * dependency and the caller is not a file in that package. When $package
     * is installed as a root package then deprecations triggered from the
     * tests folder are also considered "outside".
     *
     * This deprecation method assumes that you are using Composer to install
     * the dependency and are using the default /vendor/ folder and not a
     * Composer plugin to change the install location. The assumption is also
     * that $package is the exact composer packge name.
     *
     * Compared to {@link trigger()} this method causes some overhead when
     * deprecation tracking is enabled even during deduplication, because it
     * needs to call {@link debug_backtrace()}
     *
     * @param float|int|string $args
     */
    public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
    {
        $type = self::$type ?? self::getTypeFromEnv();

        if ($type === self::TYPE_NONE) {
            return;
        }

        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);

        // first check that the caller is not from a tests folder, in which case we always let deprecations pass
        if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
            $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $package) . DIRECTORY_SEPARATOR;

            if (strpos($backtrace[0]['file'], $path) === false) {
                return;
            }

            if (strpos($backtrace[1]['file'], $path) !== false) {
                return;
            }
        }

        if (isset(self::$ignoredLinks[$link])) {
            return;
        }

        if (array_key_exists($link, self::$triggeredDeprecations)) {
            self::$triggeredDeprecations[$link]++;
        } else {
            self::$triggeredDeprecations[$link] = 1;
        }

        if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
            return;
        }

        if (isset(self::$ignoredPackages[$package])) {
            return;
        }

        $message = sprintf($message, ...$args);

        self::delegateTriggerToBackend($message, $backtrace, $link, $package);
    }

    /** @param list<array{function: string, line?: int, file?: string, class?: class-string, type?: string, args?: mixed[], object?: object}> $backtrace */
    private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
    {
        $type = self::$type ?? self::getTypeFromEnv();

        if (($type & self::TYPE_PSR_LOGGER) > 0) {
            $context = [
                'file' => $backtrace[0]['file'] ?? null,
                'line' => $backtrace[0]['line'] ?? null,
                'package' => $package,
                'link' => $link,
            ];

            assert(self::$logger !== null);

            self::$logger->notice($message, $context);
        }

        if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) {
            return;
        }

        $message .= sprintf(
            ' (%s:%d called by %s:%d, %s, package %s)',
            self::basename($backtrace[0]['file'] ?? 'native code'),
            $backtrace[0]['line'] ?? 0,
            self::basename($backtrace[1]['file'] ?? 'native code'),
            $backtrace[1]['line'] ?? 0,
            $link,
            $package
        );

        @trigger_error($message, E_USER_DEPRECATED);
    }

    /**
     * A non-local-aware version of PHPs basename function.
     */
    private static function basename(string $filename): string
    {
        $pos = strrpos($filename, DIRECTORY_SEPARATOR);

        if ($pos === false) {
            return $filename;
        }

        return substr($filename, $pos + 1);
    }

    public static function enableTrackingDeprecations(): void
    {
        self::$type  = self::$type ?? self::getTypeFromEnv();
        self::$type |= self::TYPE_TRACK_DEPRECATIONS;
    }

    public static function enableWithTriggerError(): void
    {
        self::$type  = self::$type ?? self::getTypeFromEnv();
        self::$type |= self::TYPE_TRIGGER_ERROR;
    }

    public static function enableWithPsrLogger(LoggerInterface $logger): void
    {
        self::$type   = self::$type ?? self::getTypeFromEnv();
        self::$type  |= self::TYPE_PSR_LOGGER;
        self::$logger = $logger;
    }

    public static function withoutDeduplication(): void
    {
        self::$deduplication = false;
    }

    public static function disable(): void
    {
        self::$type          = self::TYPE_NONE;
        self::$logger        = null;
        self::$deduplication = true;
        self::$ignoredLinks  = [];

        foreach (self::$triggeredDeprecations as $link => $count) {
            self::$triggeredDeprecations[$link] = 0;
        }
    }

    public static function ignorePackage(string $packageName): void
    {
        self::$ignoredPackages[$packageName] = true;
    }

    public static function ignoreDeprecations(string ...$links): void
    {
        foreach ($links as $link) {
            self::$ignoredLinks[$link] = true;
        }
    }

    public static function getUniqueTriggeredDeprecationsCount(): int
    {
        return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) {
            return $carry + $count;
        }, 0);
    }

    /**
     * Returns each triggered deprecation link identifier and the amount of occurrences.
     *
     * @return array<string,int>
     */
    public static function getTriggeredDeprecations(): array
    {
        return self::$triggeredDeprecations;
    }

    /** @return int-mask-of<self::TYPE_*> */
    private static function getTypeFromEnv(): int
    {
        switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) {
            case 'trigger':
                self::$type = self::TYPE_TRIGGER_ERROR;
                break;

            case 'track':
                self::$type = self::TYPE_TRACK_DEPRECATIONS;
                break;

            default:
                self::$type = self::TYPE_NONE;
                break;
        }

        return self::$type;
    }
}
<?php

declare(strict_types=1);

namespace Doctrine\Deprecations\PHPUnit;

use Doctrine\Deprecations\Deprecation;
use PHPUnit\Framework\Attributes\After;
use PHPUnit\Framework\Attributes\Before;

use function sprintf;

trait VerifyDeprecations
{
    /** @var array<string,int> */
    private $doctrineDeprecationsExpectations = [];

    /** @var array<string,int> */
    private $doctrineNoDeprecationsExpectations = [];

    public function expectDeprecationWithIdentifier(string $identifier): void
    {
        $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
    }

    public function expectNoDeprecationWithIdentifier(string $identifier): void
    {
        $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
    }

    /** @before */
    #[Before]
    public function enableDeprecationTracking(): void
    {
        Deprecation::enableTrackingDeprecations();
    }

    /** @after */
    #[After]
    public function verifyDeprecationsAreTriggered(): void
    {
        foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
            $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;

            $this->assertTrue(
                $actualCount > $expectation,
                sprintf(
                    "Expected deprecation with identifier '%s' was not triggered by code executed in test.",
                    $identifier
                )
            );
        }

        foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
            $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;

            $this->assertTrue(
                $actualCount === $expectation,
                sprintf(
                    "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
                    $identifier
                )
            );
        }
    }
}
<?php

namespace GuzzleHttp;

use Psr\Http\Message\MessageInterface;

final class BodySummarizer implements BodySummarizerInterface
{
    /**
     * @var int|null
     */
    private $truncateAt;

    public function __construct(?int $truncateAt = null)
    {
        $this->truncateAt = $truncateAt;
    }

    /**
     * Returns a summarized message body.
     */
    public function summarize(MessageInterface $message): ?string
    {
        return $this->truncateAt === null
            ? Psr7\Message::bodySummary($message)
            : Psr7\Message::bodySummary($message, $this->truncateAt);
    }
}
<?php

namespace GuzzleHttp;

use Psr\Http\Message\MessageInterface;

interface BodySummarizerInterface
{
    /**
     * Returns a summarized message body.
     */
    public function summarize(MessageInterface $message): ?string;
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
 * @final
 */
class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
{
    use ClientTrait;

    /**
     * @var array Default request options
     */
    private $config;

    /**
     * Clients accept an array of constructor parameters.
     *
     * Here's an example of creating a client using a base_uri and an array of
     * default request options to apply to each request:
     *
     *     $client = new Client([
     *         'base_uri'        => 'http://www.foo.com/1.0/',
     *         'timeout'         => 0,
     *         'allow_redirects' => false,
     *         'proxy'           => '192.168.16.1:10'
     *     ]);
     *
     * Client configuration settings include the following options:
     *
     * - handler: (callable) Function that transfers HTTP requests over the
     *   wire. The function is called with a Psr7\Http\Message\RequestInterface
     *   and array of transfer options, and must return a
     *   GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
     *   Psr7\Http\Message\ResponseInterface on success.
     *   If no handler is provided, a default handler will be created
     *   that enables all of the request options below by attaching all of the
     *   default middleware to the handler.
     * - base_uri: (string|UriInterface) Base URI of the client that is merged
     *   into relative URIs. Can be a string or instance of UriInterface.
     * - **: any request option
     *
     * @param array $config Client configuration settings.
     *
     * @see RequestOptions for a list of available request options.
     */
    public function __construct(array $config = [])
    {
        if (!isset($config['handler'])) {
            $config['handler'] = HandlerStack::create();
        } elseif (!\is_callable($config['handler'])) {
            throw new InvalidArgumentException('handler must be a callable');
        }

        // Convert the base_uri to a UriInterface
        if (isset($config['base_uri'])) {
            $config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
        }

        $this->configureDefaults($config);
    }

    /**
     * @param string $method
     * @param array  $args
     *
     * @return PromiseInterface|ResponseInterface
     *
     * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
     */
    public function __call($method, $args)
    {
        if (\count($args) < 1) {
            throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
        }

        $uri = $args[0];
        $opts = $args[1] ?? [];

        return \substr($method, -5) === 'Async'
            ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
            : $this->request($method, $uri, $opts);
    }

    /**
     * Asynchronously send an HTTP request.
     *
     * @param array $options Request options to apply to the given
     *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
     */
    public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
    {
        // Merge the base URI into the request URI if needed.
        $options = $this->prepareDefaults($options);

        return $this->transfer(
            $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
            $options
        );
    }

    /**
     * Send an HTTP request.
     *
     * @param array $options Request options to apply to the given
     *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
     *
     * @throws GuzzleException
     */
    public function send(RequestInterface $request, array $options = []): ResponseInterface
    {
        $options[RequestOptions::SYNCHRONOUS] = true;

        return $this->sendAsync($request, $options)->wait();
    }

    /**
     * The HttpClient PSR (PSR-18) specify this method.
     *
     * {@inheritDoc}
     */
    public function sendRequest(RequestInterface $request): ResponseInterface
    {
        $options[RequestOptions::SYNCHRONOUS] = true;
        $options[RequestOptions::ALLOW_REDIRECTS] = false;
        $options[RequestOptions::HTTP_ERRORS] = false;

        return $this->sendAsync($request, $options)->wait();
    }

    /**
     * Create and send an asynchronous HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string              $method  HTTP method
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
     */
    public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
    {
        $options = $this->prepareDefaults($options);
        // Remove request modifying parameter because it can be done up-front.
        $headers = $options['headers'] ?? [];
        $body = $options['body'] ?? null;
        $version = $options['version'] ?? '1.1';
        // Merge the URI into the base URI.
        $uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
        if (\is_array($body)) {
            throw $this->invalidBody();
        }
        $request = new Psr7\Request($method, $uri, $headers, $body, $version);
        // Remove the option so that they are not doubly-applied.
        unset($options['headers'], $options['body'], $options['version']);

        return $this->transfer($request, $options);
    }

    /**
     * Create and send an HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string              $method  HTTP method.
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
     *
     * @throws GuzzleException
     */
    public function request(string $method, $uri = '', array $options = []): ResponseInterface
    {
        $options[RequestOptions::SYNCHRONOUS] = true;

        return $this->requestAsync($method, $uri, $options)->wait();
    }

    /**
     * Get a client configuration option.
     *
     * These options include default request options of the client, a "handler"
     * (if utilized by the concrete client), and a "base_uri" if utilized by
     * the concrete client.
     *
     * @param string|null $option The config option to retrieve.
     *
     * @return mixed
     *
     * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
     */
    public function getConfig(?string $option = null)
    {
        return $option === null
            ? $this->config
            : ($this->config[$option] ?? null);
    }

    private function buildUri(UriInterface $uri, array $config): UriInterface
    {
        if (isset($config['base_uri'])) {
            $uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
        }

        if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
            $idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
            $uri = Utils::idnUriConvert($uri, $idnOptions);
        }

        return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
    }

    /**
     * Configures the default options for a client.
     */
    private function configureDefaults(array $config): void
    {
        $defaults = [
            'allow_redirects' => RedirectMiddleware::$defaultSettings,
            'http_errors' => true,
            'decode_content' => true,
            'verify' => true,
            'cookies' => false,
            'idn_conversion' => false,
        ];

        // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.

        // We can only trust the HTTP_PROXY environment variable in a CLI
        // process due to the fact that PHP has no reliable mechanism to
        // get environment variables that start with "HTTP_".
        if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
            $defaults['proxy']['http'] = $proxy;
        }

        if ($proxy = Utils::getenv('HTTPS_PROXY')) {
            $defaults['proxy']['https'] = $proxy;
        }

        if ($noProxy = Utils::getenv('NO_PROXY')) {
            $cleanedNoProxy = \str_replace(' ', '', $noProxy);
            $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
        }

        $this->config = $config + $defaults;

        if (!empty($config['cookies']) && $config['cookies'] === true) {
            $this->config['cookies'] = new CookieJar();
        }

        // Add the default user-agent header.
        if (!isset($this->config['headers'])) {
            $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
        } else {
            // Add the User-Agent header if one was not already set.
            foreach (\array_keys($this->config['headers']) as $name) {
                if (\strtolower($name) === 'user-agent') {
                    return;
                }
            }
            $this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
        }
    }

    /**
     * Merges default options into the array.
     *
     * @param array $options Options to modify by reference
     */
    private function prepareDefaults(array $options): array
    {
        $defaults = $this->config;

        if (!empty($defaults['headers'])) {
            // Default headers are only added if they are not present.
            $defaults['_conditional'] = $defaults['headers'];
            unset($defaults['headers']);
        }

        // Special handling for headers is required as they are added as
        // conditional headers and as headers passed to a request ctor.
        if (\array_key_exists('headers', $options)) {
            // Allows default headers to be unset.
            if ($options['headers'] === null) {
                $defaults['_conditional'] = [];
                unset($options['headers']);
            } elseif (!\is_array($options['headers'])) {
                throw new InvalidArgumentException('headers must be an array');
            }
        }

        // Shallow merge defaults underneath options.
        $result = $options + $defaults;

        // Remove null values.
        foreach ($result as $k => $v) {
            if ($v === null) {
                unset($result[$k]);
            }
        }

        return $result;
    }

    /**
     * Transfers the given request and applies request options.
     *
     * The URI of the request is not modified and the request options are used
     * as-is without merging in default options.
     *
     * @param array $options See \GuzzleHttp\RequestOptions.
     */
    private function transfer(RequestInterface $request, array $options): PromiseInterface
    {
        $request = $this->applyOptions($request, $options);
        /** @var HandlerStack $handler */
        $handler = $options['handler'];

        try {
            return P\Create::promiseFor($handler($request, $options));
        } catch (\Exception $e) {
            return P\Create::rejectionFor($e);
        }
    }

    /**
     * Applies the array of request options to a request.
     */
    private function applyOptions(RequestInterface $request, array &$options): RequestInterface
    {
        $modify = [
            'set_headers' => [],
        ];

        if (isset($options['headers'])) {
            if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
                throw new InvalidArgumentException('The headers array must have header name as keys.');
            }
            $modify['set_headers'] = $options['headers'];
            unset($options['headers']);
        }

        if (isset($options['form_params'])) {
            if (isset($options['multipart'])) {
                throw new InvalidArgumentException('You cannot use '
                    .'form_params and multipart at the same time. Use the '
                    .'form_params option if you want to send application/'
                    .'x-www-form-urlencoded requests, and the multipart '
                    .'option to send multipart/form-data requests.');
            }
            $options['body'] = \http_build_query($options['form_params'], '', '&');
            unset($options['form_params']);
            // Ensure that we don't have the header in different case and set the new value.
            $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
            $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
        }

        if (isset($options['multipart'])) {
            $options['body'] = new Psr7\MultipartStream($options['multipart']);
            unset($options['multipart']);
        }

        if (isset($options['json'])) {
            $options['body'] = Utils::jsonEncode($options['json']);
            unset($options['json']);
            // Ensure that we don't have the header in different case and set the new value.
            $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
            $options['_conditional']['Content-Type'] = 'application/json';
        }

        if (!empty($options['decode_content'])
            && $options['decode_content'] !== true
        ) {
            // Ensure that we don't have the header in different case and set the new value.
            $options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
            $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
        }

        if (isset($options['body'])) {
            if (\is_array($options['body'])) {
                throw $this->invalidBody();
            }
            $modify['body'] = Psr7\Utils::streamFor($options['body']);
            unset($options['body']);
        }

        if (!empty($options['auth']) && \is_array($options['auth'])) {
            $value = $options['auth'];
            $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
            switch ($type) {
                case 'basic':
                    // Ensure that we don't have the header in different case and set the new value.
                    $modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
                    $modify['set_headers']['Authorization'] = 'Basic '
                        .\base64_encode("$value[0]:$value[1]");
                    break;
                case 'digest':
                    // @todo: Do not rely on curl
                    $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
                    $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
                    break;
                case 'ntlm':
                    $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
                    $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
                    break;
            }
        }

        if (isset($options['query'])) {
            $value = $options['query'];
            if (\is_array($value)) {
                $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
            }
            if (!\is_string($value)) {
                throw new InvalidArgumentException('query must be a string or array');
            }
            $modify['query'] = $value;
            unset($options['query']);
        }

        // Ensure that sink is not an invalid value.
        if (isset($options['sink'])) {
            // TODO: Add more sink validation?
            if (\is_bool($options['sink'])) {
                throw new InvalidArgumentException('sink must not be a boolean');
            }
        }

        if (isset($options['version'])) {
            $modify['version'] = $options['version'];
        }

        $request = Psr7\Utils::modifyRequest($request, $modify);
        if ($request->getBody() instanceof Psr7\MultipartStream) {
            // Use a multipart/form-data POST if a Content-Type is not set.
            // Ensure that we don't have the header in different case and set the new value.
            $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
            $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
                .$request->getBody()->getBoundary();
        }

        // Merge in conditional headers if they are not present.
        if (isset($options['_conditional'])) {
            // Build up the changes so it's in a single clone of the message.
            $modify = [];
            foreach ($options['_conditional'] as $k => $v) {
                if (!$request->hasHeader($k)) {
                    $modify['set_headers'][$k] = $v;
                }
            }
            $request = Psr7\Utils::modifyRequest($request, $modify);
            // Don't pass this internal value along to middleware/handlers.
            unset($options['_conditional']);
        }

        return $request;
    }

    /**
     * Return an InvalidArgumentException with pre-set message.
     */
    private function invalidBody(): InvalidArgumentException
    {
        return new InvalidArgumentException('Passing in the "body" request '
            .'option as an array to send a request is not supported. '
            .'Please use the "form_params" request option to send a '
            .'application/x-www-form-urlencoded request, or the "multipart" '
            .'request option to send a multipart/form-data request.');
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
 * Client interface for sending HTTP requests.
 */
interface ClientInterface
{
    /**
     * The Guzzle major version.
     */
    public const MAJOR_VERSION = 7;

    /**
     * Send an HTTP request.
     *
     * @param RequestInterface $request Request to send
     * @param array            $options Request options to apply to the given
     *                                  request and to the transfer.
     *
     * @throws GuzzleException
     */
    public function send(RequestInterface $request, array $options = []): ResponseInterface;

    /**
     * Asynchronously send an HTTP request.
     *
     * @param RequestInterface $request Request to send
     * @param array            $options Request options to apply to the given
     *                                  request and to the transfer.
     */
    public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface;

    /**
     * Create and send an HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string              $method  HTTP method.
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function request(string $method, $uri, array $options = []): ResponseInterface;

    /**
     * Create and send an asynchronous HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string              $method  HTTP method
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;

    /**
     * Get a client configuration option.
     *
     * These options include default request options of the client, a "handler"
     * (if utilized by the concrete client), and a "base_uri" if utilized by
     * the concrete client.
     *
     * @param string|null $option The config option to retrieve.
     *
     * @return mixed
     *
     * @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
     */
    public function getConfig(?string $option = null);
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
 * Client interface for sending HTTP requests.
 */
trait ClientTrait
{
    /**
     * Create and send an HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string              $method  HTTP method.
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    abstract public function request(string $method, $uri, array $options = []): ResponseInterface;

    /**
     * Create and send an HTTP GET request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function get($uri, array $options = []): ResponseInterface
    {
        return $this->request('GET', $uri, $options);
    }

    /**
     * Create and send an HTTP HEAD request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function head($uri, array $options = []): ResponseInterface
    {
        return $this->request('HEAD', $uri, $options);
    }

    /**
     * Create and send an HTTP PUT request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function put($uri, array $options = []): ResponseInterface
    {
        return $this->request('PUT', $uri, $options);
    }

    /**
     * Create and send an HTTP POST request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function post($uri, array $options = []): ResponseInterface
    {
        return $this->request('POST', $uri, $options);
    }

    /**
     * Create and send an HTTP PATCH request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function patch($uri, array $options = []): ResponseInterface
    {
        return $this->request('PATCH', $uri, $options);
    }

    /**
     * Create and send an HTTP DELETE request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     *
     * @throws GuzzleException
     */
    public function delete($uri, array $options = []): ResponseInterface
    {
        return $this->request('DELETE', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string              $method  HTTP method
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    abstract public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;

    /**
     * Create and send an asynchronous HTTP GET request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function getAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('GET', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP HEAD request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function headAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('HEAD', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP PUT request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function putAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('PUT', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP POST request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function postAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('POST', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP PATCH request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function patchAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('PATCH', $uri, $options);
    }

    /**
     * Create and send an asynchronous HTTP DELETE request.
     *
     * Use an absolute path to override the base path of the client, or a
     * relative path to append to the base path of the client. The URL can
     * contain the query string as well. Use an array to provide a URL
     * template and additional variables to use in the URL template expansion.
     *
     * @param string|UriInterface $uri     URI object or string.
     * @param array               $options Request options to apply.
     */
    public function deleteAsync($uri, array $options = []): PromiseInterface
    {
        return $this->requestAsync('DELETE', $uri, $options);
    }
}
<?php

namespace GuzzleHttp\Cookie;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Cookie jar that stores cookies as an array
 */
class CookieJar implements CookieJarInterface
{
    /**
     * @var SetCookie[] Loaded cookie data
     */
    private $cookies = [];

    /**
     * @var bool
     */
    private $strictMode;

    /**
     * @param bool  $strictMode  Set to true to throw exceptions when invalid
     *                           cookies are added to the cookie jar.
     * @param array $cookieArray Array of SetCookie objects or a hash of
     *                           arrays that can be used with the SetCookie
     *                           constructor
     */
    public function __construct(bool $strictMode = false, array $cookieArray = [])
    {
        $this->strictMode = $strictMode;

        foreach ($cookieArray as $cookie) {
            if (!($cookie instanceof SetCookie)) {
                $cookie = new SetCookie($cookie);
            }
            $this->setCookie($cookie);
        }
    }

    /**
     * Create a new Cookie jar from an associative array and domain.
     *
     * @param array  $cookies Cookies to create the jar from
     * @param string $domain  Domain to set the cookies to
     */
    public static function fromArray(array $cookies, string $domain): self
    {
        $cookieJar = new self();
        foreach ($cookies as $name => $value) {
            $cookieJar->setCookie(new SetCookie([
                'Domain' => $domain,
                'Name' => $name,
                'Value' => $value,
                'Discard' => true,
            ]));
        }

        return $cookieJar;
    }

    /**
     * Evaluate if this cookie should be persisted to storage
     * that survives between requests.
     *
     * @param SetCookie $cookie              Being evaluated.
     * @param bool      $allowSessionCookies If we should persist session cookies
     */
    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
    {
        if ($cookie->getExpires() || $allowSessionCookies) {
            if (!$cookie->getDiscard()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Finds and returns the cookie based on the name
     *
     * @param string $name cookie name to search for
     *
     * @return SetCookie|null cookie that was found or null if not found
     */
    public function getCookieByName(string $name): ?SetCookie
    {
        foreach ($this->cookies as $cookie) {
            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
                return $cookie;
            }
        }

        return null;
    }

    public function toArray(): array
    {
        return \array_map(static function (SetCookie $cookie): array {
            return $cookie->toArray();
        }, $this->getIterator()->getArrayCopy());
    }

    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
    {
        if (!$domain) {
            $this->cookies = [];

            return;
        } elseif (!$path) {
            $this->cookies = \array_filter(
                $this->cookies,
                static function (SetCookie $cookie) use ($domain): bool {
                    return !$cookie->matchesDomain($domain);
                }
            );
        } elseif (!$name) {
            $this->cookies = \array_filter(
                $this->cookies,
                static function (SetCookie $cookie) use ($path, $domain): bool {
                    return !($cookie->matchesPath($path)
                        && $cookie->matchesDomain($domain));
                }
            );
        } else {
            $this->cookies = \array_filter(
                $this->cookies,
                static function (SetCookie $cookie) use ($path, $domain, $name) {
                    return !($cookie->getName() == $name
                        && $cookie->matchesPath($path)
                        && $cookie->matchesDomain($domain));
                }
            );
        }
    }

    public function clearSessionCookies(): void
    {
        $this->cookies = \array_filter(
            $this->cookies,
            static function (SetCookie $cookie): bool {
                return !$cookie->getDiscard() && $cookie->getExpires();
            }
        );
    }

    public function setCookie(SetCookie $cookie): bool
    {
        // If the name string is empty (but not 0), ignore the set-cookie
        // string entirely.
        $name = $cookie->getName();
        if (!$name && $name !== '0') {
            return false;
        }

        // Only allow cookies with set and valid domain, name, value
        $result = $cookie->validate();
        if ($result !== true) {
            if ($this->strictMode) {
                throw new \RuntimeException('Invalid cookie: '.$result);
            }
            $this->removeCookieIfEmpty($cookie);

            return false;
        }

        // Resolve conflicts with previously set cookies
        foreach ($this->cookies as $i => $c) {
            // Two cookies are identical, when their path, and domain are
            // identical.
            if ($c->getPath() != $cookie->getPath()
                || $c->getDomain() != $cookie->getDomain()
                || $c->getName() != $cookie->getName()
            ) {
                continue;
            }

            // The previously set cookie is a discard cookie and this one is
            // not so allow the new cookie to be set
            if (!$cookie->getDiscard() && $c->getDiscard()) {
                unset($this->cookies[$i]);
                continue;
            }

            // If the new cookie's expiration is further into the future, then
            // replace the old cookie
            if ($cookie->getExpires() > $c->getExpires()) {
                unset($this->cookies[$i]);
                continue;
            }

            // If the value has changed, we better change it
            if ($cookie->getValue() !== $c->getValue()) {
                unset($this->cookies[$i]);
                continue;
            }

            // The cookie exists, so no need to continue
            return false;
        }

        $this->cookies[] = $cookie;

        return true;
    }

    public function count(): int
    {
        return \count($this->cookies);
    }

    /**
     * @return \ArrayIterator<int, SetCookie>
     */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator(\array_values($this->cookies));
    }

    public function extractCookies(RequestInterface $request, ResponseInterface $response): void
    {
        if ($cookieHeader = $response->getHeader('Set-Cookie')) {
            foreach ($cookieHeader as $cookie) {
                $sc = SetCookie::fromString($cookie);
                if (!$sc->getDomain()) {
                    $sc->setDomain($request->getUri()->getHost());
                }
                if (0 !== \strpos($sc->getPath(), '/')) {
                    $sc->setPath($this->getCookiePathFromRequest($request));
                }
                if (!$sc->matchesDomain($request->getUri()->getHost())) {
                    continue;
                }
                // Note: At this point `$sc->getDomain()` being a public suffix should
                // be rejected, but we don't want to pull in the full PSL dependency.
                $this->setCookie($sc);
            }
        }
    }

    /**
     * Computes cookie path following RFC 6265 section 5.1.4
     *
     * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
     */
    private function getCookiePathFromRequest(RequestInterface $request): string
    {
        $uriPath = $request->getUri()->getPath();
        if ('' === $uriPath) {
            return '/';
        }
        if (0 !== \strpos($uriPath, '/')) {
            return '/';
        }
        if ('/' === $uriPath) {
            return '/';
        }
        $lastSlashPos = \strrpos($uriPath, '/');
        if (0 === $lastSlashPos || false === $lastSlashPos) {
            return '/';
        }

        return \substr($uriPath, 0, $lastSlashPos);
    }

    public function withCookieHeader(RequestInterface $request): RequestInterface
    {
        $values = [];
        $uri = $request->getUri();
        $scheme = $uri->getScheme();
        $host = $uri->getHost();
        $path = $uri->getPath() ?: '/';

        foreach ($this->cookies as $cookie) {
            if ($cookie->matchesPath($path)
                && $cookie->matchesDomain($host)
                && !$cookie->isExpired()
                && (!$cookie->getSecure() || $scheme === 'https')
            ) {
                $values[] = $cookie->getName().'='
                    .$cookie->getValue();
            }
        }

        return $values
            ? $request->withHeader('Cookie', \implode('; ', $values))
            : $request;
    }

    /**
     * If a cookie already exists and the server asks to set it again with a
     * null value, the cookie must be deleted.
     */
    private function removeCookieIfEmpty(SetCookie $cookie): void
    {
        $cookieValue = $cookie->getValue();
        if ($cookieValue === null || $cookieValue === '') {
            $this->clear(
                $cookie->getDomain(),
                $cookie->getPath(),
                $cookie->getName()
            );
        }
    }
}
<?php

namespace GuzzleHttp\Cookie;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Stores HTTP cookies.
 *
 * It extracts cookies from HTTP requests, and returns them in HTTP responses.
 * CookieJarInterface instances automatically expire contained cookies when
 * necessary. Subclasses are also responsible for storing and retrieving
 * cookies from a file, database, etc.
 *
 * @see https://docs.python.org/2/library/cookielib.html Inspiration
 *
 * @extends \IteratorAggregate<SetCookie>
 */
interface CookieJarInterface extends \Countable, \IteratorAggregate
{
    /**
     * Create a request with added cookie headers.
     *
     * If no matching cookies are found in the cookie jar, then no Cookie
     * header is added to the request and the same request is returned.
     *
     * @param RequestInterface $request Request object to modify.
     *
     * @return RequestInterface returns the modified request.
     */
    public function withCookieHeader(RequestInterface $request): RequestInterface;

    /**
     * Extract cookies from an HTTP response and store them in the CookieJar.
     *
     * @param RequestInterface  $request  Request that was sent
     * @param ResponseInterface $response Response that was received
     */
    public function extractCookies(RequestInterface $request, ResponseInterface $response): void;

    /**
     * Sets a cookie in the cookie jar.
     *
     * @param SetCookie $cookie Cookie to set.
     *
     * @return bool Returns true on success or false on failure
     */
    public function setCookie(SetCookie $cookie): bool;

    /**
     * Remove cookies currently held in the cookie jar.
     *
     * Invoking this method without arguments will empty the whole cookie jar.
     * If given a $domain argument only cookies belonging to that domain will
     * be removed. If given a $domain and $path argument, cookies belonging to
     * the specified path within that domain are removed. If given all three
     * arguments, then the cookie with the specified name, path and domain is
     * removed.
     *
     * @param string|null $domain Clears cookies matching a domain
     * @param string|null $path   Clears cookies matching a domain and path
     * @param string|null $name   Clears cookies matching a domain, path, and name
     */
    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;

    /**
     * Discard all sessions cookies.
     *
     * Removes cookies that don't have an expire field or a have a discard
     * field set to true. To be called when the user agent shuts down according
     * to RFC 2965.
     */
    public function clearSessionCookies(): void;

    /**
     * Converts the cookie jar to an array.
     */
    public function toArray(): array;
}
<?php

namespace GuzzleHttp\Cookie;

use GuzzleHttp\Utils;

/**
 * Persists non-session cookies using a JSON formatted file
 */
class FileCookieJar extends CookieJar
{
    /**
     * @var string filename
     */
    private $filename;

    /**
     * @var bool Control whether to persist session cookies or not.
     */
    private $storeSessionCookies;

    /**
     * Create a new FileCookieJar object
     *
     * @param string $cookieFile          File to store the cookie data
     * @param bool   $storeSessionCookies Set to true to store session cookies
     *                                    in the cookie jar.
     *
     * @throws \RuntimeException if the file cannot be found or created
     */
    public function __construct(string $cookieFile, bool $storeSessionCookies = false)
    {
        parent::__construct();
        $this->filename = $cookieFile;
        $this->storeSessionCookies = $storeSessionCookies;

        if (\file_exists($cookieFile)) {
            $this->load($cookieFile);
        }
    }

    /**
     * Saves the file when shutting down
     */
    public function __destruct()
    {
        $this->save($this->filename);
    }

    /**
     * Saves the cookies to a file.
     *
     * @param string $filename File to save
     *
     * @throws \RuntimeException if the file cannot be found or created
     */
    public function save(string $filename): void
    {
        $json = [];
        /** @var SetCookie $cookie */
        foreach ($this as $cookie) {
            if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
                $json[] = $cookie->toArray();
            }
        }

        $jsonStr = Utils::jsonEncode($json);
        if (false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) {
            throw new \RuntimeException("Unable to save file {$filename}");
        }
    }

    /**
     * Load cookies from a JSON formatted file.
     *
     * Old cookies are kept unless overwritten by newly loaded ones.
     *
     * @param string $filename Cookie file to load.
     *
     * @throws \RuntimeException if the file cannot be loaded.
     */
    public function load(string $filename): void
    {
        $json = \file_get_contents($filename);
        if (false === $json) {
            throw new \RuntimeException("Unable to load file {$filename}");
        }
        if ($json === '') {
            return;
        }

        $data = Utils::jsonDecode($json, true);
        if (\is_array($data)) {
            foreach ($data as $cookie) {
                $this->setCookie(new SetCookie($cookie));
            }
        } elseif (\is_scalar($data) && !empty($data)) {
            throw new \RuntimeException("Invalid cookie file: {$filename}");
        }
    }
}
<?php

namespace GuzzleHttp\Cookie;

/**
 * Persists cookies in the client session
 */
class SessionCookieJar extends CookieJar
{
    /**
     * @var string session key
     */
    private $sessionKey;

    /**
     * @var bool Control whether to persist session cookies or not.
     */
    private $storeSessionCookies;

    /**
     * Create a new SessionCookieJar object
     *
     * @param string $sessionKey          Session key name to store the cookie
     *                                    data in session
     * @param bool   $storeSessionCookies Set to true to store session cookies
     *                                    in the cookie jar.
     */
    public function __construct(string $sessionKey, bool $storeSessionCookies = false)
    {
        parent::__construct();
        $this->sessionKey = $sessionKey;
        $this->storeSessionCookies = $storeSessionCookies;
        $this->load();
    }

    /**
     * Saves cookies to session when shutting down
     */
    public function __destruct()
    {
        $this->save();
    }

    /**
     * Save cookies to the client session
     */
    public function save(): void
    {
        $json = [];
        /** @var SetCookie $cookie */
        foreach ($this as $cookie) {
            if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
                $json[] = $cookie->toArray();
            }
        }

        $_SESSION[$this->sessionKey] = \json_encode($json);
    }

    /**
     * Load the contents of the client session into the data array
     */
    protected function load(): void
    {
        if (!isset($_SESSION[$this->sessionKey])) {
            return;
        }
        $data = \json_decode($_SESSION[$this->sessionKey], true);
        if (\is_array($data)) {
            foreach ($data as $cookie) {
                $this->setCookie(new SetCookie($cookie));
            }
        } elseif (\strlen($data)) {
            throw new \RuntimeException('Invalid cookie data');
        }
    }
}
<?php

namespace GuzzleHttp\Cookie;

/**
 * Set-Cookie object
 */
class SetCookie
{
    /**
     * @var array
     */
    private static $defaults = [
        'Name' => null,
        'Value' => null,
        'Domain' => null,
        'Path' => '/',
        'Max-Age' => null,
        'Expires' => null,
        'Secure' => false,
        'Discard' => false,
        'HttpOnly' => false,
    ];

    /**
     * @var array Cookie data
     */
    private $data;

    /**
     * Create a new SetCookie object from a string.
     *
     * @param string $cookie Set-Cookie header string
     */
    public static function fromString(string $cookie): self
    {
        // Create the default return array
        $data = self::$defaults;
        // Explode the cookie string using a series of semicolons
        $pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
        // The name of the cookie (first kvp) must exist and include an equal sign.
        if (!isset($pieces[0]) || \strpos($pieces[0], '=') === false) {
            return new self($data);
        }

        // Add the cookie pieces into the parsed data array
        foreach ($pieces as $part) {
            $cookieParts = \explode('=', $part, 2);
            $key = \trim($cookieParts[0]);
            $value = isset($cookieParts[1])
                ? \trim($cookieParts[1], " \n\r\t\0\x0B")
                : true;

            // Only check for non-cookies when cookies have been found
            if (!isset($data['Name'])) {
                $data['Name'] = $key;
                $data['Value'] = $value;
            } else {
                foreach (\array_keys(self::$defaults) as $search) {
                    if (!\strcasecmp($search, $key)) {
                        if ($search === 'Max-Age') {
                            if (is_numeric($value)) {
                                $data[$search] = (int) $value;
                            }
                        } elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') {
                            if ($value) {
                                $data[$search] = true;
                            }
                        } else {
                            $data[$search] = $value;
                        }
                        continue 2;
                    }
                }
                $data[$key] = $value;
            }
        }

        return new self($data);
    }

    /**
     * @param array $data Array of cookie data provided by a Cookie parser
     */
    public function __construct(array $data = [])
    {
        $this->data = self::$defaults;

        if (isset($data['Name'])) {
            $this->setName($data['Name']);
        }

        if (isset($data['Value'])) {
            $this->setValue($data['Value']);
        }

        if (isset($data['Domain'])) {
            $this->setDomain($data['Domain']);
        }

        if (isset($data['Path'])) {
            $this->setPath($data['Path']);
        }

        if (isset($data['Max-Age'])) {
            $this->setMaxAge($data['Max-Age']);
        }

        if (isset($data['Expires'])) {
            $this->setExpires($data['Expires']);
        }

        if (isset($data['Secure'])) {
            $this->setSecure($data['Secure']);
        }

        if (isset($data['Discard'])) {
            $this->setDiscard($data['Discard']);
        }

        if (isset($data['HttpOnly'])) {
            $this->setHttpOnly($data['HttpOnly']);
        }

        // Set the remaining values that don't have extra validation logic
        foreach (array_diff(array_keys($data), array_keys(self::$defaults)) as $key) {
            $this->data[$key] = $data[$key];
        }

        // Extract the Expires value and turn it into a UNIX timestamp if needed
        if (!$this->getExpires() && $this->getMaxAge()) {
            // Calculate the Expires date
            $this->setExpires(\time() + $this->getMaxAge());
        } elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
            $this->setExpires($expires);
        }
    }

    public function __toString()
    {
        $str = $this->data['Name'].'='.($this->data['Value'] ?? '').'; ';
        foreach ($this->data as $k => $v) {
            if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
                if ($k === 'Expires') {
                    $str .= 'Expires='.\gmdate('D, d M Y H:i:s \G\M\T', $v).'; ';
                } else {
                    $str .= ($v === true ? $k : "{$k}={$v}").'; ';
                }
            }
        }

        return \rtrim($str, '; ');
    }

    public function toArray(): array
    {
        return $this->data;
    }

    /**
     * Get the cookie name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->data['Name'];
    }

    /**
     * Set the cookie name.
     *
     * @param string $name Cookie name
     */
    public function setName($name): void
    {
        if (!is_string($name)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Name'] = (string) $name;
    }

    /**
     * Get the cookie value.
     *
     * @return string|null
     */
    public function getValue()
    {
        return $this->data['Value'];
    }

    /**
     * Set the cookie value.
     *
     * @param string $value Cookie value
     */
    public function setValue($value): void
    {
        if (!is_string($value)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Value'] = (string) $value;
    }

    /**
     * Get the domain.
     *
     * @return string|null
     */
    public function getDomain()
    {
        return $this->data['Domain'];
    }

    /**
     * Set the domain of the cookie.
     *
     * @param string|null $domain
     */
    public function setDomain($domain): void
    {
        if (!is_string($domain) && null !== $domain) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Domain'] = null === $domain ? null : (string) $domain;
    }

    /**
     * Get the path.
     *
     * @return string
     */
    public function getPath()
    {
        return $this->data['Path'];
    }

    /**
     * Set the path of the cookie.
     *
     * @param string $path Path of the cookie
     */
    public function setPath($path): void
    {
        if (!is_string($path)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Path'] = (string) $path;
    }

    /**
     * Maximum lifetime of the cookie in seconds.
     *
     * @return int|null
     */
    public function getMaxAge()
    {
        return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
    }

    /**
     * Set the max-age of the cookie.
     *
     * @param int|null $maxAge Max age of the cookie in seconds
     */
    public function setMaxAge($maxAge): void
    {
        if (!is_int($maxAge) && null !== $maxAge) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
    }

    /**
     * The UNIX timestamp when the cookie Expires.
     *
     * @return string|int|null
     */
    public function getExpires()
    {
        return $this->data['Expires'];
    }

    /**
     * Set the unix timestamp for which the cookie will expire.
     *
     * @param int|string|null $timestamp Unix timestamp or any English textual datetime description.
     */
    public function setExpires($timestamp): void
    {
        if (!is_int($timestamp) && !is_string($timestamp) && null !== $timestamp) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
    }

    /**
     * Get whether or not this is a secure cookie.
     *
     * @return bool
     */
    public function getSecure()
    {
        return $this->data['Secure'];
    }

    /**
     * Set whether or not the cookie is secure.
     *
     * @param bool $secure Set to true or false if secure
     */
    public function setSecure($secure): void
    {
        if (!is_bool($secure)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Secure'] = (bool) $secure;
    }

    /**
     * Get whether or not this is a session cookie.
     *
     * @return bool|null
     */
    public function getDiscard()
    {
        return $this->data['Discard'];
    }

    /**
     * Set whether or not this is a session cookie.
     *
     * @param bool $discard Set to true or false if this is a session cookie
     */
    public function setDiscard($discard): void
    {
        if (!is_bool($discard)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['Discard'] = (bool) $discard;
    }

    /**
     * Get whether or not this is an HTTP only cookie.
     *
     * @return bool
     */
    public function getHttpOnly()
    {
        return $this->data['HttpOnly'];
    }

    /**
     * Set whether or not this is an HTTP only cookie.
     *
     * @param bool $httpOnly Set to true or false if this is HTTP only
     */
    public function setHttpOnly($httpOnly): void
    {
        if (!is_bool($httpOnly)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->data['HttpOnly'] = (bool) $httpOnly;
    }

    /**
     * Check if the cookie matches a path value.
     *
     * A request-path path-matches a given cookie-path if at least one of
     * the following conditions holds:
     *
     * - The cookie-path and the request-path are identical.
     * - The cookie-path is a prefix of the request-path, and the last
     *   character of the cookie-path is %x2F ("/").
     * - The cookie-path is a prefix of the request-path, and the first
     *   character of the request-path that is not included in the cookie-
     *   path is a %x2F ("/") character.
     *
     * @param string $requestPath Path to check against
     */
    public function matchesPath(string $requestPath): bool
    {
        $cookiePath = $this->getPath();

        // Match on exact matches or when path is the default empty "/"
        if ($cookiePath === '/' || $cookiePath == $requestPath) {
            return true;
        }

        // Ensure that the cookie-path is a prefix of the request path.
        if (0 !== \strpos($requestPath, $cookiePath)) {
            return false;
        }

        // Match if the last character of the cookie-path is "/"
        if (\substr($cookiePath, -1, 1) === '/') {
            return true;
        }

        // Match if the first character not included in cookie path is "/"
        return \substr($requestPath, \strlen($cookiePath), 1) === '/';
    }

    /**
     * Check if the cookie matches a domain value.
     *
     * @param string $domain Domain to check against
     */
    public function matchesDomain(string $domain): bool
    {
        $cookieDomain = $this->getDomain();
        if (null === $cookieDomain) {
            return true;
        }

        // Remove the leading '.' as per spec in RFC 6265.
        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
        $cookieDomain = \ltrim(\strtolower($cookieDomain), '.');

        $domain = \strtolower($domain);

        // Domain not set or exact match.
        if ('' === $cookieDomain || $domain === $cookieDomain) {
            return true;
        }

        // Matching the subdomain according to RFC 6265.
        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
        if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
            return false;
        }

        return (bool) \preg_match('/\.'.\preg_quote($cookieDomain, '/').'$/', $domain);
    }

    /**
     * Check if the cookie is expired.
     */
    public function isExpired(): bool
    {
        return $this->getExpires() !== null && \time() > $this->getExpires();
    }

    /**
     * Check if the cookie is valid according to RFC 6265.
     *
     * @return bool|string Returns true if valid or an error message if invalid
     */
    public function validate()
    {
        $name = $this->getName();
        if ($name === '') {
            return 'The cookie name must not be empty';
        }

        // Check if any of the invalid characters are present in the cookie name
        if (\preg_match(
            '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
            $name
        )) {
            return 'Cookie name must not contain invalid characters: ASCII '
                .'Control characters (0-31;127), space, tab and the '
                .'following characters: ()<>@,;:\"/?={}';
        }

        // Value must not be null. 0 and empty string are valid. Empty strings
        // are technically against RFC 6265, but known to happen in the wild.
        $value = $this->getValue();
        if ($value === null) {
            return 'The cookie value must not be empty';
        }

        // Domains must not be empty, but can be 0. "0" is not a valid internet
        // domain, but may be used as server name in a private network.
        $domain = $this->getDomain();
        if ($domain === null || $domain === '') {
            return 'The cookie domain must not be empty';
        }

        return true;
    }
}
<?php

namespace GuzzleHttp\Exception;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Exception when an HTTP error occurs (4xx or 5xx error)
 */
class BadResponseException extends RequestException
{
    public function __construct(
        string $message,
        RequestInterface $request,
        ResponseInterface $response,
        ?\Throwable $previous = null,
        array $handlerContext = []
    ) {
        parent::__construct($message, $request, $response, $previous, $handlerContext);
    }

    /**
     * Current exception and the ones that extend it will always have a response.
     */
    public function hasResponse(): bool
    {
        return true;
    }

    /**
     * This function narrows the return type from the parent class and does not allow it to be nullable.
     */
    public function getResponse(): ResponseInterface
    {
        /** @var ResponseInterface */
        return parent::getResponse();
    }
}
<?php

namespace GuzzleHttp\Exception;

/**
 * Exception when a client error is encountered (4xx codes)
 */
class ClientException extends BadResponseException
{
}
<?php

namespace GuzzleHttp\Exception;

use Psr\Http\Client\NetworkExceptionInterface;
use Psr\Http\Message\RequestInterface;

/**
 * Exception thrown when a connection cannot be established.
 *
 * Note that no response is present for a ConnectException
 */
class ConnectException extends TransferException implements NetworkExceptionInterface
{
    /**
     * @var RequestInterface
     */
    private $request;

    /**
     * @var array
     */
    private $handlerContext;

    public function __construct(
        string $message,
        RequestInterface $request,
        ?\Throwable $previous = null,
        array $handlerContext = []
    ) {
        parent::__construct($message, 0, $previous);
        $this->request = $request;
        $this->handlerContext = $handlerContext;
    }

    /**
     * Get the request that caused the exception
     */
    public function getRequest(): RequestInterface
    {
        return $this->request;
    }

    /**
     * Get contextual information about the error from the underlying handler.
     *
     * The contents of this array will vary depending on which handler you are
     * using. It may also be just an empty array. Relying on this data will
     * couple you to a specific handler, but can give more debug information
     * when needed.
     */
    public function getHandlerContext(): array
    {
        return $this->handlerContext;
    }
}
<?php

namespace GuzzleHttp\Exception;

use Psr\Http\Client\ClientExceptionInterface;

interface GuzzleException extends ClientExceptionInterface
{
}
<?php

namespace GuzzleHttp\Exception;

final class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException
{
}
<?php

namespace GuzzleHttp\Exception;

use GuzzleHttp\BodySummarizer;
use GuzzleHttp\BodySummarizerInterface;
use Psr\Http\Client\RequestExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * HTTP Request exception
 */
class RequestException extends TransferException implements RequestExceptionInterface
{
    /**
     * @var RequestInterface
     */
    private $request;

    /**
     * @var ResponseInterface|null
     */
    private $response;

    /**
     * @var array
     */
    private $handlerContext;

    public function __construct(
        string $message,
        RequestInterface $request,
        ?ResponseInterface $response = null,
        ?\Throwable $previous = null,
        array $handlerContext = []
    ) {
        // Set the code of the exception if the response is set and not future.
        $code = $response ? $response->getStatusCode() : 0;
        parent::__construct($message, $code, $previous);
        $this->request = $request;
        $this->response = $response;
        $this->handlerContext = $handlerContext;
    }

    /**
     * Wrap non-RequestExceptions with a RequestException
     */
    public static function wrapException(RequestInterface $request, \Throwable $e): RequestException
    {
        return $e instanceof RequestException ? $e : new RequestException($e->getMessage(), $request, null, $e);
    }

    /**
     * Factory method to create a new exception with a normalized error message
     *
     * @param RequestInterface             $request        Request sent
     * @param ResponseInterface            $response       Response received
     * @param \Throwable|null              $previous       Previous exception
     * @param array                        $handlerContext Optional handler context
     * @param BodySummarizerInterface|null $bodySummarizer Optional body summarizer
     */
    public static function create(
        RequestInterface $request,
        ?ResponseInterface $response = null,
        ?\Throwable $previous = null,
        array $handlerContext = [],
        ?BodySummarizerInterface $bodySummarizer = null
    ): self {
        if (!$response) {
            return new self(
                'Error completing request',
                $request,
                null,
                $previous,
                $handlerContext
            );
        }

        $level = (int) \floor($response->getStatusCode() / 100);
        if ($level === 4) {
            $label = 'Client error';
            $className = ClientException::class;
        } elseif ($level === 5) {
            $label = 'Server error';
            $className = ServerException::class;
        } else {
            $label = 'Unsuccessful request';
            $className = __CLASS__;
        }

        $uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());

        // Client Error: `GET /` resulted in a `404 Not Found` response:
        // <html> ... (truncated)
        $message = \sprintf(
            '%s: `%s %s` resulted in a `%s %s` response',
            $label,
            $request->getMethod(),
            $uri->__toString(),
            $response->getStatusCode(),
            $response->getReasonPhrase()
        );

        $summary = ($bodySummarizer ?? new BodySummarizer())->summarize($response);

        if ($summary !== null) {
            $message .= ":\n{$summary}\n";
        }

        return new $className($message, $request, $response, $previous, $handlerContext);
    }

    /**
     * Get the request that caused the exception
     */
    public function getRequest(): RequestInterface
    {
        return $this->request;
    }

    /**
     * Get the associated response
     */
    public function getResponse(): ?ResponseInterface
    {
        return $this->response;
    }

    /**
     * Check if a response was received
     */
    public function hasResponse(): bool
    {
        return $this->response !== null;
    }

    /**
     * Get contextual information about the error from the underlying handler.
     *
     * The contents of this array will vary depending on which handler you are
     * using. It may also be just an empty array. Relying on this data will
     * couple you to a specific handler, but can give more debug information
     * when needed.
     */
    public function getHandlerContext(): array
    {
        return $this->handlerContext;
    }
}
<?php

namespace GuzzleHttp\Exception;

/**
 * Exception when a server error is encountered (5xx codes)
 */
class ServerException extends BadResponseException
{
}
<?php

namespace GuzzleHttp\Exception;

class TooManyRedirectsException extends RequestException
{
}
<?php

namespace GuzzleHttp\Exception;

class TransferException extends \RuntimeException implements GuzzleException
{
}
<?php

namespace GuzzleHttp;

/**
 * Debug function used to describe the provided value type and class.
 *
 * @param mixed $input Any type of variable to describe the type of. This
 *                     parameter misses a typehint because of that.
 *
 * @return string Returns a string containing the type of the variable and
 *                if a class is provided, the class name.
 *
 * @deprecated describe_type will be removed in guzzlehttp/guzzle:8.0. Use Utils::describeType instead.
 */
function describe_type($input): string
{
    return Utils::describeType($input);
}

/**
 * Parses an array of header lines into an associative array of headers.
 *
 * @param iterable $lines Header lines array of strings in the following
 *                        format: "Name: Value"
 *
 * @deprecated headers_from_lines will be removed in guzzlehttp/guzzle:8.0. Use Utils::headersFromLines instead.
 */
function headers_from_lines(iterable $lines): array
{
    return Utils::headersFromLines($lines);
}

/**
 * Returns a debug stream based on the provided variable.
 *
 * @param mixed $value Optional value
 *
 * @return resource
 *
 * @deprecated debug_resource will be removed in guzzlehttp/guzzle:8.0. Use Utils::debugResource instead.
 */
function debug_resource($value = null)
{
    return Utils::debugResource($value);
}

/**
 * Chooses and creates a default handler to use based on the environment.
 *
 * The returned handler is not wrapped by any default middlewares.
 *
 * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
 *
 * @throws \RuntimeException if no viable Handler is available.
 *
 * @deprecated choose_handler will be removed in guzzlehttp/guzzle:8.0. Use Utils::chooseHandler instead.
 */
function choose_handler(): callable
{
    return Utils::chooseHandler();
}

/**
 * Get the default User-Agent string to use with Guzzle.
 *
 * @deprecated default_user_agent will be removed in guzzlehttp/guzzle:8.0. Use Utils::defaultUserAgent instead.
 */
function default_user_agent(): string
{
    return Utils::defaultUserAgent();
}

/**
 * Returns the default cacert bundle for the current system.
 *
 * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
 * If those settings are not configured, then the common locations for
 * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
 * and Windows are checked. If any of these file locations are found on
 * disk, they will be utilized.
 *
 * Note: the result of this function is cached for subsequent calls.
 *
 * @throws \RuntimeException if no bundle can be found.
 *
 * @deprecated default_ca_bundle will be removed in guzzlehttp/guzzle:8.0. This function is not needed in PHP 5.6+.
 */
function default_ca_bundle(): string
{
    return Utils::defaultCaBundle();
}

/**
 * Creates an associative array of lowercase header names to the actual
 * header casing.
 *
 * @deprecated normalize_header_keys will be removed in guzzlehttp/guzzle:8.0. Use Utils::normalizeHeaderKeys instead.
 */
function normalize_header_keys(array $headers): array
{
    return Utils::normalizeHeaderKeys($headers);
}

/**
 * Returns true if the provided host matches any of the no proxy areas.
 *
 * This method will strip a port from the host if it is present. Each pattern
 * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
 * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
 * "baz.foo.com", but ".foo.com" != "foo.com").
 *
 * Areas are matched in the following cases:
 * 1. "*" (without quotes) always matches any hosts.
 * 2. An exact match.
 * 3. The area starts with "." and the area is the last part of the host. e.g.
 *    '.mit.edu' will match any host that ends with '.mit.edu'.
 *
 * @param string   $host         Host to check against the patterns.
 * @param string[] $noProxyArray An array of host patterns.
 *
 * @throws Exception\InvalidArgumentException
 *
 * @deprecated is_host_in_noproxy will be removed in guzzlehttp/guzzle:8.0. Use Utils::isHostInNoProxy instead.
 */
function is_host_in_noproxy(string $host, array $noProxyArray): bool
{
    return Utils::isHostInNoProxy($host, $noProxyArray);
}

/**
 * Wrapper for json_decode that throws when an error occurs.
 *
 * @param string $json    JSON data to parse
 * @param bool   $assoc   When true, returned objects will be converted
 *                        into associative arrays.
 * @param int    $depth   User specified recursion depth.
 * @param int    $options Bitmask of JSON decode options.
 *
 * @return object|array|string|int|float|bool|null
 *
 * @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
 *
 * @see https://www.php.net/manual/en/function.json-decode.php
 * @deprecated json_decode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonDecode instead.
 */
function json_decode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
{
    return Utils::jsonDecode($json, $assoc, $depth, $options);
}

/**
 * Wrapper for JSON encoding that throws when an error occurs.
 *
 * @param mixed $value   The value being encoded
 * @param int   $options JSON encode option bitmask
 * @param int   $depth   Set the maximum depth. Must be greater than zero.
 *
 * @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
 *
 * @see https://www.php.net/manual/en/function.json-encode.php
 * @deprecated json_encode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonEncode instead.
 */
function json_encode($value, int $options = 0, int $depth = 512): string
{
    return Utils::jsonEncode($value, $options, $depth);
}
<?php

// Don't redefine the functions if included multiple times.
if (!\function_exists('GuzzleHttp\describe_type')) {
    require __DIR__.'/functions.php';
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\LazyOpenStream;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;

/**
 * Creates curl resources from a request
 *
 * @final
 */
class CurlFactory implements CurlFactoryInterface
{
    public const CURL_VERSION_STR = 'curl_version';

    /**
     * @deprecated
     */
    public const LOW_CURL_VERSION_NUMBER = '7.21.2';

    /**
     * @var resource[]|\CurlHandle[]
     */
    private $handles = [];

    /**
     * @var int Total number of idle handles to keep in cache
     */
    private $maxHandles;

    /**
     * @param int $maxHandles Maximum number of idle handles.
     */
    public function __construct(int $maxHandles)
    {
        $this->maxHandles = $maxHandles;
    }

    public function create(RequestInterface $request, array $options): EasyHandle
    {
        $protocolVersion = $request->getProtocolVersion();

        if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
            if (!self::supportsHttp2()) {
                throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);
            }
        } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
            throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);
        }

        if (isset($options['curl']['body_as_string'])) {
            $options['_body_as_string'] = $options['curl']['body_as_string'];
            unset($options['curl']['body_as_string']);
        }

        $easy = new EasyHandle();
        $easy->request = $request;
        $easy->options = $options;
        $conf = $this->getDefaultConf($easy);
        $this->applyMethod($easy, $conf);
        $this->applyHandlerOptions($easy, $conf);
        $this->applyHeaders($easy, $conf);
        unset($conf['_headers']);

        // Add handler options from the request configuration options
        if (isset($options['curl'])) {
            $conf = \array_replace($conf, $options['curl']);
        }

        $conf[\CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
        $easy->handle = $this->handles ? \array_pop($this->handles) : \curl_init();
        curl_setopt_array($easy->handle, $conf);

        return $easy;
    }

    private static function supportsHttp2(): bool
    {
        static $supportsHttp2 = null;

        if (null === $supportsHttp2) {
            $supportsHttp2 = self::supportsTls12()
                && defined('CURL_VERSION_HTTP2')
                && (\CURL_VERSION_HTTP2 & \curl_version()['features']);
        }

        return $supportsHttp2;
    }

    private static function supportsTls12(): bool
    {
        static $supportsTls12 = null;

        if (null === $supportsTls12) {
            $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features'];
        }

        return $supportsTls12;
    }

    private static function supportsTls13(): bool
    {
        static $supportsTls13 = null;

        if (null === $supportsTls13) {
            $supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3')
                && (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']);
        }

        return $supportsTls13;
    }

    public function release(EasyHandle $easy): void
    {
        $resource = $easy->handle;
        unset($easy->handle);

        if (\count($this->handles) >= $this->maxHandles) {
            if (PHP_VERSION_ID < 80000) {
                \curl_close($resource);
            }
        } else {
            // Remove all callback functions as they can hold onto references
            // and are not cleaned up by curl_reset. Using curl_setopt_array
            // does not work for some reason, so removing each one
            // individually.
            \curl_setopt($resource, \CURLOPT_HEADERFUNCTION, null);
            \curl_setopt($resource, \CURLOPT_READFUNCTION, null);
            \curl_setopt($resource, \CURLOPT_WRITEFUNCTION, null);
            \curl_setopt($resource, \CURLOPT_PROGRESSFUNCTION, null);
            \curl_reset($resource);
            $this->handles[] = $resource;
        }
    }

    /**
     * Completes a cURL transaction, either returning a response promise or a
     * rejected promise.
     *
     * @param callable(RequestInterface, array): PromiseInterface $handler
     * @param CurlFactoryInterface                                $factory Dictates how the handle is released
     */
    public static function finish(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface
    {
        if (isset($easy->options['on_stats'])) {
            self::invokeStats($easy);
        }

        if (!$easy->response || $easy->errno) {
            return self::finishError($handler, $easy, $factory);
        }

        // Return the response if it is present and there is no error.
        $factory->release($easy);

        // Rewind the body of the response if possible.
        $body = $easy->response->getBody();
        if ($body->isSeekable()) {
            $body->rewind();
        }

        return new FulfilledPromise($easy->response);
    }

    private static function invokeStats(EasyHandle $easy): void
    {
        $curlStats = \curl_getinfo($easy->handle);
        $curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
        $stats = new TransferStats(
            $easy->request,
            $easy->response,
            $curlStats['total_time'],
            $easy->errno,
            $curlStats
        );
        ($easy->options['on_stats'])($stats);
    }

    /**
     * @param callable(RequestInterface, array): PromiseInterface $handler
     */
    private static function finishError(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface
    {
        // Get error information and release the handle to the factory.
        $ctx = [
            'errno' => $easy->errno,
            'error' => \curl_error($easy->handle),
            'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME),
        ] + \curl_getinfo($easy->handle);
        $ctx[self::CURL_VERSION_STR] = self::getCurlVersion();
        $factory->release($easy);

        // Retry when nothing is present or when curl failed to rewind.
        if (empty($easy->options['_err_message']) && (!$easy->errno || $easy->errno == 65)) {
            return self::retryFailedRewind($handler, $easy, $ctx);
        }

        return self::createRejection($easy, $ctx);
    }

    private static function getCurlVersion(): string
    {
        static $curlVersion = null;

        if (null === $curlVersion) {
            $curlVersion = \curl_version()['version'];
        }

        return $curlVersion;
    }

    private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
    {
        static $connectionErrors = [
            \CURLE_OPERATION_TIMEOUTED => true,
            \CURLE_COULDNT_RESOLVE_HOST => true,
            \CURLE_COULDNT_CONNECT => true,
            \CURLE_SSL_CONNECT_ERROR => true,
            \CURLE_GOT_NOTHING => true,
        ];

        if ($easy->createResponseException) {
            return P\Create::rejectionFor(
                new RequestException(
                    'An error was encountered while creating the response',
                    $easy->request,
                    $easy->response,
                    $easy->createResponseException,
                    $ctx
                )
            );
        }

        // If an exception was encountered during the onHeaders event, then
        // return a rejected promise that wraps that exception.
        if ($easy->onHeadersException) {
            return P\Create::rejectionFor(
                new RequestException(
                    'An error was encountered during the on_headers event',
                    $easy->request,
                    $easy->response,
                    $easy->onHeadersException,
                    $ctx
                )
            );
        }

        $uri = $easy->request->getUri();

        $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);

        $message = \sprintf(
            'cURL error %s: %s (%s)',
            $ctx['errno'],
            $sanitizedError,
            'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
        );

        if ('' !== $sanitizedError) {
            $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
            if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
                $message .= \sprintf(' for %s', $redactedUriString);
            }
        }

        // Create a connection exception if it was a specific error code.
        $error = isset($connectionErrors[$easy->errno])
            ? new ConnectException($message, $easy->request, null, $ctx)
            : new RequestException($message, $easy->request, $easy->response, null, $ctx);

        return P\Create::rejectionFor($error);
    }

    private static function sanitizeCurlError(string $error, UriInterface $uri): string
    {
        if ('' === $error) {
            return $error;
        }

        $baseUri = $uri->withQuery('')->withFragment('');
        $baseUriString = $baseUri->__toString();

        if ('' === $baseUriString) {
            return $error;
        }

        $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();

        return str_replace($baseUriString, $redactedUriString, $error);
    }

    /**
     * @return array<int|string, mixed>
     */
    private function getDefaultConf(EasyHandle $easy): array
    {
        $conf = [
            '_headers' => $easy->request->getHeaders(),
            \CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
            \CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
            \CURLOPT_RETURNTRANSFER => false,
            \CURLOPT_HEADER => false,
            \CURLOPT_CONNECTTIMEOUT => 300,
        ];

        if (\defined('CURLOPT_PROTOCOLS')) {
            $conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS;
        }

        $version = $easy->request->getProtocolVersion();

        if ('2' === $version || '2.0' === $version) {
            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
        } elseif ('1.1' === $version) {
            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
        } else {
            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
        }

        return $conf;
    }

    private function applyMethod(EasyHandle $easy, array &$conf): void
    {
        $body = $easy->request->getBody();
        $size = $body->getSize();

        if ($size === null || $size > 0) {
            $this->applyBody($easy->request, $easy->options, $conf);

            return;
        }

        $method = $easy->request->getMethod();
        if ($method === 'PUT' || $method === 'POST') {
            // See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
            if (!$easy->request->hasHeader('Content-Length')) {
                $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
            }
        } elseif ($method === 'HEAD') {
            $conf[\CURLOPT_NOBODY] = true;
            unset(
                $conf[\CURLOPT_WRITEFUNCTION],
                $conf[\CURLOPT_READFUNCTION],
                $conf[\CURLOPT_FILE],
                $conf[\CURLOPT_INFILE]
            );
        }
    }

    private function applyBody(RequestInterface $request, array $options, array &$conf): void
    {
        $size = $request->hasHeader('Content-Length')
            ? (int) $request->getHeaderLine('Content-Length')
            : null;

        // Send the body as a string if the size is less than 1MB OR if the
        // [curl][body_as_string] request value is set.
        if (($size !== null && $size < 1000000) || !empty($options['_body_as_string'])) {
            $conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody();
            // Don't duplicate the Content-Length header
            $this->removeHeader('Content-Length', $conf);
            $this->removeHeader('Transfer-Encoding', $conf);
        } else {
            $conf[\CURLOPT_UPLOAD] = true;
            if ($size !== null) {
                $conf[\CURLOPT_INFILESIZE] = $size;
                $this->removeHeader('Content-Length', $conf);
            }
            $body = $request->getBody();
            if ($body->isSeekable()) {
                $body->rewind();
            }
            $conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) {
                return $body->read($length);
            };
        }

        // If the Expect header is not present, prevent curl from adding it
        if (!$request->hasHeader('Expect')) {
            $conf[\CURLOPT_HTTPHEADER][] = 'Expect:';
        }

        // cURL sometimes adds a content-type by default. Prevent this.
        if (!$request->hasHeader('Content-Type')) {
            $conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:';
        }
    }

    private function applyHeaders(EasyHandle $easy, array &$conf): void
    {
        foreach ($conf['_headers'] as $name => $values) {
            foreach ($values as $value) {
                $value = (string) $value;
                if ($value === '') {
                    // cURL requires a special format for empty headers.
                    // See https://github.com/guzzle/guzzle/issues/1882 for more details.
                    $conf[\CURLOPT_HTTPHEADER][] = "$name;";
                } else {
                    $conf[\CURLOPT_HTTPHEADER][] = "$name: $value";
                }
            }
        }

        // Remove the Accept header if one was not set
        if (!$easy->request->hasHeader('Accept')) {
            $conf[\CURLOPT_HTTPHEADER][] = 'Accept:';
        }
    }

    /**
     * Remove a header from the options array.
     *
     * @param string $name    Case-insensitive header to remove
     * @param array  $options Array of options to modify
     */
    private function removeHeader(string $name, array &$options): void
    {
        foreach (\array_keys($options['_headers']) as $key) {
            if (!\strcasecmp($key, $name)) {
                unset($options['_headers'][$key]);

                return;
            }
        }
    }

    private function applyHandlerOptions(EasyHandle $easy, array &$conf): void
    {
        $options = $easy->options;
        if (isset($options['verify'])) {
            if ($options['verify'] === false) {
                unset($conf[\CURLOPT_CAINFO]);
                $conf[\CURLOPT_SSL_VERIFYHOST] = 0;
                $conf[\CURLOPT_SSL_VERIFYPEER] = false;
            } else {
                $conf[\CURLOPT_SSL_VERIFYHOST] = 2;
                $conf[\CURLOPT_SSL_VERIFYPEER] = true;
                if (\is_string($options['verify'])) {
                    // Throw an error if the file/folder/link path is not valid or doesn't exist.
                    if (!\file_exists($options['verify'])) {
                        throw new \InvalidArgumentException("SSL CA bundle not found: {$options['verify']}");
                    }
                    // If it's a directory or a link to a directory use CURLOPT_CAPATH.
                    // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
                    if (
                        \is_dir($options['verify'])
                        || (
                            \is_link($options['verify']) === true
                            && ($verifyLink = \readlink($options['verify'])) !== false
                            && \is_dir($verifyLink)
                        )
                    ) {
                        $conf[\CURLOPT_CAPATH] = $options['verify'];
                    } else {
                        $conf[\CURLOPT_CAINFO] = $options['verify'];
                    }
                }
            }
        }

        if (!isset($options['curl'][\CURLOPT_ENCODING]) && !empty($options['decode_content'])) {
            $accept = $easy->request->getHeaderLine('Accept-Encoding');
            if ($accept) {
                $conf[\CURLOPT_ENCODING] = $accept;
            } else {
                // The empty string enables all available decoders and implicitly
                // sets a matching 'Accept-Encoding' header.
                $conf[\CURLOPT_ENCODING] = '';
                // But as the user did not specify any encoding preference,
                // let's leave it up to server by preventing curl from sending
                // the header, which will be interpreted as 'Accept-Encoding: *'.
                // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding
                $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
            }
        }

        if (!isset($options['sink'])) {
            // Use a default temp stream if no sink was set.
            $options['sink'] = \GuzzleHttp\Psr7\Utils::tryFopen('php://temp', 'w+');
        }
        $sink = $options['sink'];
        if (!\is_string($sink)) {
            $sink = \GuzzleHttp\Psr7\Utils::streamFor($sink);
        } elseif (!\is_dir(\dirname($sink))) {
            // Ensure that the directory exists before failing in curl.
            throw new \RuntimeException(\sprintf('Directory %s does not exist for sink value of %s', \dirname($sink), $sink));
        } else {
            $sink = new LazyOpenStream($sink, 'w+');
        }
        $easy->sink = $sink;
        $conf[\CURLOPT_WRITEFUNCTION] = static function ($ch, $write) use ($sink): int {
            return $sink->write($write);
        };

        $timeoutRequiresNoSignal = false;
        if (isset($options['timeout'])) {
            $timeoutRequiresNoSignal |= $options['timeout'] < 1;
            $conf[\CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
        }

        // CURL default value is CURL_IPRESOLVE_WHATEVER
        if (isset($options['force_ip_resolve'])) {
            if ('v4' === $options['force_ip_resolve']) {
                $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4;
            } elseif ('v6' === $options['force_ip_resolve']) {
                $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V6;
            }
        }

        if (isset($options['connect_timeout'])) {
            $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
            $conf[\CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
        }

        if ($timeoutRequiresNoSignal && \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN') {
            $conf[\CURLOPT_NOSIGNAL] = true;
        }

        if (isset($options['proxy'])) {
            if (!\is_array($options['proxy'])) {
                $conf[\CURLOPT_PROXY] = $options['proxy'];
            } else {
                $scheme = $easy->request->getUri()->getScheme();
                if (isset($options['proxy'][$scheme])) {
                    $host = $easy->request->getUri()->getHost();
                    if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
                        unset($conf[\CURLOPT_PROXY]);
                    } else {
                        $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
                    }
                }
            }
        }

        if (isset($options['crypto_method'])) {
            $protocolVersion = $easy->request->getProtocolVersion();

            // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2
            if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
                if (
                    \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']
                    || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']
                    || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']
                ) {
                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
                } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
                    if (!self::supportsTls13()) {
                        throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
                    }
                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
                } else {
                    throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
                }
            } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
                $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0;
            } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {
                $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1;
            } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {
                if (!self::supportsTls12()) {
                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL');
                }
                $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
            } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
                if (!self::supportsTls13()) {
                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
                }
                $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
            } else {
                throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
            }
        }

        if (isset($options['cert'])) {
            $cert = $options['cert'];
            if (\is_array($cert)) {
                $conf[\CURLOPT_SSLCERTPASSWD] = $cert[1];
                $cert = $cert[0];
            }
            if (!\file_exists($cert)) {
                throw new \InvalidArgumentException("SSL certificate not found: {$cert}");
            }
            // OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files.
            // see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html
            $ext = pathinfo($cert, \PATHINFO_EXTENSION);
            if (preg_match('#^(der|p12)$#i', $ext)) {
                $conf[\CURLOPT_SSLCERTTYPE] = strtoupper($ext);
            }
            $conf[\CURLOPT_SSLCERT] = $cert;
        }

        if (isset($options['ssl_key'])) {
            if (\is_array($options['ssl_key'])) {
                if (\count($options['ssl_key']) === 2) {
                    [$sslKey, $conf[\CURLOPT_SSLKEYPASSWD]] = $options['ssl_key'];
                } else {
                    [$sslKey] = $options['ssl_key'];
                }
            }

            $sslKey = $sslKey ?? $options['ssl_key'];

            if (!\file_exists($sslKey)) {
                throw new \InvalidArgumentException("SSL private key not found: {$sslKey}");
            }
            $conf[\CURLOPT_SSLKEY] = $sslKey;
        }

        if (isset($options['progress'])) {
            $progress = $options['progress'];
            if (!\is_callable($progress)) {
                throw new \InvalidArgumentException('progress client option must be callable');
            }
            $conf[\CURLOPT_NOPROGRESS] = false;
            $conf[\CURLOPT_PROGRESSFUNCTION] = static function ($resource, int $downloadSize, int $downloaded, int $uploadSize, int $uploaded) use ($progress) {
                $progress($downloadSize, $downloaded, $uploadSize, $uploaded);
            };
        }

        if (!empty($options['debug'])) {
            $conf[\CURLOPT_STDERR] = Utils::debugResource($options['debug']);
            $conf[\CURLOPT_VERBOSE] = true;
        }
    }

    /**
     * This function ensures that a response was set on a transaction. If one
     * was not set, then the request is retried if possible. This error
     * typically means you are sending a payload, curl encountered a
     * "Connection died, retrying a fresh connect" error, tried to rewind the
     * stream, and then encountered a "necessary data rewind wasn't possible"
     * error, causing the request to be sent through curl_multi_info_read()
     * without an error status.
     *
     * @param callable(RequestInterface, array): PromiseInterface $handler
     */
    private static function retryFailedRewind(callable $handler, EasyHandle $easy, array $ctx): PromiseInterface
    {
        try {
            // Only rewind if the body has been read from.
            $body = $easy->request->getBody();
            if ($body->tell() > 0) {
                $body->rewind();
            }
        } catch (\RuntimeException $e) {
            $ctx['error'] = 'The connection unexpectedly failed without '
                .'providing an error. The request would have been retried, '
                .'but attempting to rewind the request body failed. '
                .'Exception: '.$e;

            return self::createRejection($easy, $ctx);
        }

        // Retry no more than 3 times before giving up.
        if (!isset($easy->options['_curl_retries'])) {
            $easy->options['_curl_retries'] = 1;
        } elseif ($easy->options['_curl_retries'] == 2) {
            $ctx['error'] = 'The cURL request was retried 3 times '
                .'and did not succeed. The most likely reason for the failure '
                .'is that cURL was unable to rewind the body of the request '
                .'and subsequent retries resulted in the same error. Turn on '
                .'the debug option to see what went wrong. See '
                .'https://bugs.php.net/bug.php?id=47204 for more information.';

            return self::createRejection($easy, $ctx);
        } else {
            ++$easy->options['_curl_retries'];
        }

        return $handler($easy->request, $easy->options);
    }

    private function createHeaderFn(EasyHandle $easy): callable
    {
        if (isset($easy->options['on_headers'])) {
            $onHeaders = $easy->options['on_headers'];

            if (!\is_callable($onHeaders)) {
                throw new \InvalidArgumentException('on_headers must be callable');
            }
        } else {
            $onHeaders = null;
        }

        return static function ($ch, $h) use (
            $onHeaders,
            $easy,
            &$startingResponse
        ) {
            $value = \trim($h);
            if ($value === '') {
                $startingResponse = true;
                try {
                    $easy->createResponse();
                } catch (\Exception $e) {
                    $easy->createResponseException = $e;

                    return -1;
                }
                if ($onHeaders !== null) {
                    try {
                        $onHeaders($easy->response);
                    } catch (\Exception $e) {
                        // Associate the exception with the handle and trigger
                        // a curl header write error by returning 0.
                        $easy->onHeadersException = $e;

                        return -1;
                    }
                }
            } elseif ($startingResponse) {
                $startingResponse = false;
                $easy->headers = [$value];
            } else {
                $easy->headers[] = $value;
            }

            return \strlen($h);
        };
    }

    public function __destruct()
    {
        foreach ($this->handles as $id => $handle) {
            if (PHP_VERSION_ID < 80000) {
                \curl_close($handle);
            }

            unset($this->handles[$id]);
        }
    }
}
<?php

namespace GuzzleHttp\Handler;

use Psr\Http\Message\RequestInterface;

interface CurlFactoryInterface
{
    /**
     * Creates a cURL handle resource.
     *
     * @param RequestInterface $request Request
     * @param array            $options Transfer options
     *
     * @throws \RuntimeException when an option cannot be applied
     */
    public function create(RequestInterface $request, array $options): EasyHandle;

    /**
     * Release an easy handle, allowing it to be reused or closed.
     *
     * This function must call unset on the easy handle's "handle" property.
     */
    public function release(EasyHandle $easy): void;
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;

/**
 * HTTP handler that uses cURL easy handles as a transport layer.
 *
 * When using the CurlHandler, custom curl options can be specified as an
 * associative array of curl option constants mapping to values in the
 * **curl** key of the "client" key of the request.
 *
 * @final
 */
class CurlHandler
{
    /**
     * @var CurlFactoryInterface
     */
    private $factory;

    /**
     * Accepts an associative array of options:
     *
     * - handle_factory: Optional curl factory used to create cURL handles.
     *
     * @param array{handle_factory?: ?CurlFactoryInterface} $options Array of options to use with the handler
     */
    public function __construct(array $options = [])
    {
        $this->factory = $options['handle_factory']
            ?? new CurlFactory(3);
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        if (isset($options['delay'])) {
            \usleep($options['delay'] * 1000);
        }

        $easy = $this->factory->create($request, $options);
        \curl_exec($easy->handle);
        $easy->errno = \curl_errno($easy->handle);

        return CurlFactory::finish($this, $easy, $this->factory);
    }
}
<?php

namespace GuzzleHttp\Handler;

use Closure;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;

/**
 * Returns an asynchronous response using curl_multi_* functions.
 *
 * When using the CurlMultiHandler, custom curl options can be specified as an
 * associative array of curl option constants mapping to values in the
 * **curl** key of the provided request options.
 *
 * @final
 */
class CurlMultiHandler
{
    /**
     * @var CurlFactoryInterface
     */
    private $factory;

    /**
     * @var int
     */
    private $selectTimeout;

    /**
     * @var int Will be higher than 0 when `curl_multi_exec` is still running.
     */
    private $active = 0;

    /**
     * @var array Request entry handles, indexed by handle id in `addRequest`.
     *
     * @see CurlMultiHandler::addRequest
     */
    private $handles = [];

    /**
     * @var array<int, float> An array of delay times, indexed by handle id in `addRequest`.
     *
     * @see CurlMultiHandler::addRequest
     */
    private $delays = [];

    /**
     * @var array<mixed> An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
     */
    private $options = [];

    /** @var resource|\CurlMultiHandle */
    private $_mh;

    /**
     * This handler accepts the following options:
     *
     * - handle_factory: An optional factory  used to create curl handles
     * - select_timeout: Optional timeout (in seconds) to block before timing
     *   out while selecting curl handles. Defaults to 1 second.
     * - options: An associative array of CURLMOPT_* options and
     *   corresponding values for curl_multi_setopt()
     */
    public function __construct(array $options = [])
    {
        $this->factory = $options['handle_factory'] ?? new CurlFactory(50);

        if (isset($options['select_timeout'])) {
            $this->selectTimeout = $options['select_timeout'];
        } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
            @trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
            $this->selectTimeout = (int) $selectTimeout;
        } else {
            $this->selectTimeout = 1;
        }

        $this->options = $options['options'] ?? [];

        // unsetting the property forces the first access to go through
        // __get().
        unset($this->_mh);
    }

    /**
     * @param string $name
     *
     * @return resource|\CurlMultiHandle
     *
     * @throws \BadMethodCallException when another field as `_mh` will be gotten
     * @throws \RuntimeException       when curl can not initialize a multi handle
     */
    public function __get($name)
    {
        if ($name !== '_mh') {
            throw new \BadMethodCallException("Can not get other property as '_mh'.");
        }

        $multiHandle = \curl_multi_init();

        if (false === $multiHandle) {
            throw new \RuntimeException('Can not initialize curl multi handle.');
        }

        $this->_mh = $multiHandle;

        foreach ($this->options as $option => $value) {
            // A warning is raised in case of a wrong option.
            curl_multi_setopt($this->_mh, $option, $value);
        }

        return $this->_mh;
    }

    public function __destruct()
    {
        if (isset($this->_mh)) {
            \curl_multi_close($this->_mh);
            unset($this->_mh);
        }
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        $easy = $this->factory->create($request, $options);
        $id = (int) $easy->handle;

        $promise = new Promise(
            [$this, 'execute'],
            function () use ($id) {
                return $this->cancel($id);
            }
        );

        $this->addRequest(['easy' => $easy, 'deferred' => $promise]);

        return $promise;
    }

    /**
     * Ticks the curl event loop.
     */
    public function tick(): void
    {
        // Add any delayed handles if needed.
        if ($this->delays) {
            $currentTime = Utils::currentTime();
            foreach ($this->delays as $id => $delay) {
                if ($currentTime >= $delay) {
                    unset($this->delays[$id]);
                    \curl_multi_add_handle(
                        $this->_mh,
                        $this->handles[$id]['easy']->handle
                    );
                }
            }
        }

        // Run curl_multi_exec in the queue to enable other async tasks to run
        P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));

        // Step through the task queue which may add additional requests.
        P\Utils::queue()->run();

        if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
            // Perform a usleep if a select returns -1.
            // See: https://bugs.php.net/bug.php?id=61141
            \usleep(250);
        }

        while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
            // Prevent busy looping for slow HTTP requests.
            \curl_multi_select($this->_mh, $this->selectTimeout);
        }

        $this->processMessages();
    }

    /**
     * Runs \curl_multi_exec() inside the event loop, to prevent busy looping
     */
    private function tickInQueue(): void
    {
        if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
            \curl_multi_select($this->_mh, 0);
            P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
        }
    }

    /**
     * Runs until all outstanding connections have completed.
     */
    public function execute(): void
    {
        $queue = P\Utils::queue();

        while ($this->handles || !$queue->isEmpty()) {
            // If there are no transfers, then sleep for the next delay
            if (!$this->active && $this->delays) {
                \usleep($this->timeToNext());
            }
            $this->tick();
        }
    }

    private function addRequest(array $entry): void
    {
        $easy = $entry['easy'];
        $id = (int) $easy->handle;
        $this->handles[$id] = $entry;
        if (empty($easy->options['delay'])) {
            \curl_multi_add_handle($this->_mh, $easy->handle);
        } else {
            $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
        }
    }

    /**
     * Cancels a handle from sending and removes references to it.
     *
     * @param int $id Handle ID to cancel and remove.
     *
     * @return bool True on success, false on failure.
     */
    private function cancel($id): bool
    {
        if (!is_int($id)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        // Cannot cancel if it has been processed.
        if (!isset($this->handles[$id])) {
            return false;
        }

        $handle = $this->handles[$id]['easy']->handle;
        unset($this->delays[$id], $this->handles[$id]);
        \curl_multi_remove_handle($this->_mh, $handle);

        if (PHP_VERSION_ID < 80000) {
            \curl_close($handle);
        }

        return true;
    }

    private function processMessages(): void
    {
        while ($done = \curl_multi_info_read($this->_mh)) {
            if ($done['msg'] !== \CURLMSG_DONE) {
                // if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
                continue;
            }
            $id = (int) $done['handle'];
            \curl_multi_remove_handle($this->_mh, $done['handle']);

            if (!isset($this->handles[$id])) {
                // Probably was cancelled.
                continue;
            }

            $entry = $this->handles[$id];
            unset($this->handles[$id], $this->delays[$id]);
            $entry['easy']->errno = $done['result'];
            $entry['deferred']->resolve(
                CurlFactory::finish($this, $entry['easy'], $this->factory)
            );
        }
    }

    private function timeToNext(): int
    {
        $currentTime = Utils::currentTime();
        $nextTime = \PHP_INT_MAX;
        foreach ($this->delays as $time) {
            if ($time < $nextTime) {
                $nextTime = $time;
            }
        }

        return ((int) \max(0, $nextTime - $currentTime)) * 1000000;
    }
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

/**
 * Represents a cURL easy handle and the data it populates.
 *
 * @internal
 */
final class EasyHandle
{
    /**
     * @var resource|\CurlHandle cURL resource
     */
    public $handle;

    /**
     * @var StreamInterface Where data is being written
     */
    public $sink;

    /**
     * @var array Received HTTP headers so far
     */
    public $headers = [];

    /**
     * @var ResponseInterface|null Received response (if any)
     */
    public $response;

    /**
     * @var RequestInterface Request being sent
     */
    public $request;

    /**
     * @var array Request options
     */
    public $options = [];

    /**
     * @var int cURL error number (if any)
     */
    public $errno = 0;

    /**
     * @var \Throwable|null Exception during on_headers (if any)
     */
    public $onHeadersException;

    /**
     * @var \Exception|null Exception during createResponse (if any)
     */
    public $createResponseException;

    /**
     * Attach a response to the easy handle based on the received headers.
     *
     * @throws \RuntimeException if no headers have been received or the first
     *                           header line is invalid.
     */
    public function createResponse(): void
    {
        [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($this->headers);

        $normalizedKeys = Utils::normalizeHeaderKeys($headers);

        if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) {
            $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
            unset($headers[$normalizedKeys['content-encoding']]);
            if (isset($normalizedKeys['content-length'])) {
                $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];

                $bodyLength = (int) $this->sink->getSize();
                if ($bodyLength) {
                    $headers[$normalizedKeys['content-length']] = $bodyLength;
                } else {
                    unset($headers[$normalizedKeys['content-length']]);
                }
            }
        }

        // Attach a response to the easy handle with the parsed headers.
        $this->response = new Response(
            $status,
            $headers,
            $this->sink,
            $ver,
            $reason
        );
    }

    /**
     * @param string $name
     *
     * @return void
     *
     * @throws \BadMethodCallException
     */
    public function __get($name)
    {
        $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: '.$name;
        throw new \BadMethodCallException($msg);
    }
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Utils;

/**
 * @internal
 */
final class HeaderProcessor
{
    /**
     * Returns the HTTP version, status code, reason phrase, and headers.
     *
     * @param string[] $headers
     *
     * @return array{0:string, 1:int, 2:?string, 3:array}
     *
     * @throws \RuntimeException
     */
    public static function parseHeaders(array $headers): array
    {
        if ($headers === []) {
            throw new \RuntimeException('Expected a non-empty array of header data');
        }

        $parts = \explode(' ', \array_shift($headers), 3);
        $version = \explode('/', $parts[0])[1] ?? null;

        if ($version === null) {
            throw new \RuntimeException('HTTP version missing from header data');
        }

        $status = $parts[1] ?? null;

        if ($status === null) {
            throw new \RuntimeException('HTTP status code missing from header data');
        }

        return [$version, (int) $status, $parts[2] ?? null, Utils::headersFromLines($headers)];
    }
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

/**
 * Handler that returns responses or throw exceptions from a queue.
 *
 * @final
 */
class MockHandler implements \Countable
{
    /**
     * @var array
     */
    private $queue = [];

    /**
     * @var RequestInterface|null
     */
    private $lastRequest;

    /**
     * @var array
     */
    private $lastOptions = [];

    /**
     * @var callable|null
     */
    private $onFulfilled;

    /**
     * @var callable|null
     */
    private $onRejected;

    /**
     * Creates a new MockHandler that uses the default handler stack list of
     * middlewares.
     *
     * @param array|null    $queue       Array of responses, callables, or exceptions.
     * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
     * @param callable|null $onRejected  Callback to invoke when the return value is rejected.
     */
    public static function createWithMiddleware(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null): HandlerStack
    {
        return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
    }

    /**
     * The passed in value must be an array of
     * {@see ResponseInterface} objects, Exceptions,
     * callables, or Promises.
     *
     * @param array<int, mixed>|null $queue       The parameters to be passed to the append function, as an indexed array.
     * @param callable|null          $onFulfilled Callback to invoke when the return value is fulfilled.
     * @param callable|null          $onRejected  Callback to invoke when the return value is rejected.
     */
    public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null)
    {
        $this->onFulfilled = $onFulfilled;
        $this->onRejected = $onRejected;

        if ($queue) {
            // array_values included for BC
            $this->append(...array_values($queue));
        }
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        if (!$this->queue) {
            throw new \OutOfBoundsException('Mock queue is empty');
        }

        if (isset($options['delay']) && \is_numeric($options['delay'])) {
            \usleep((int) $options['delay'] * 1000);
        }

        $this->lastRequest = $request;
        $this->lastOptions = $options;
        $response = \array_shift($this->queue);

        if (isset($options['on_headers'])) {
            if (!\is_callable($options['on_headers'])) {
                throw new \InvalidArgumentException('on_headers must be callable');
            }
            try {
                $options['on_headers']($response);
            } catch (\Exception $e) {
                $msg = 'An error was encountered during the on_headers event';
                $response = new RequestException($msg, $request, $response, $e);
            }
        }

        if (\is_callable($response)) {
            $response = $response($request, $options);
        }

        $response = $response instanceof \Throwable
            ? P\Create::rejectionFor($response)
            : P\Create::promiseFor($response);

        return $response->then(
            function (?ResponseInterface $value) use ($request, $options) {
                $this->invokeStats($request, $options, $value);
                if ($this->onFulfilled) {
                    ($this->onFulfilled)($value);
                }

                if ($value !== null && isset($options['sink'])) {
                    $contents = (string) $value->getBody();
                    $sink = $options['sink'];

                    if (\is_resource($sink)) {
                        \fwrite($sink, $contents);
                    } elseif (\is_string($sink)) {
                        \file_put_contents($sink, $contents);
                    } elseif ($sink instanceof StreamInterface) {
                        $sink->write($contents);
                    }
                }

                return $value;
            },
            function ($reason) use ($request, $options) {
                $this->invokeStats($request, $options, null, $reason);
                if ($this->onRejected) {
                    ($this->onRejected)($reason);
                }

                return P\Create::rejectionFor($reason);
            }
        );
    }

    /**
     * Adds one or more variadic requests, exceptions, callables, or promises
     * to the queue.
     *
     * @param mixed ...$values
     */
    public function append(...$values): void
    {
        foreach ($values as $value) {
            if ($value instanceof ResponseInterface
                || $value instanceof \Throwable
                || $value instanceof PromiseInterface
                || \is_callable($value)
            ) {
                $this->queue[] = $value;
            } else {
                throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found '.Utils::describeType($value));
            }
        }
    }

    /**
     * Get the last received request.
     */
    public function getLastRequest(): ?RequestInterface
    {
        return $this->lastRequest;
    }

    /**
     * Get the last received request options.
     */
    public function getLastOptions(): array
    {
        return $this->lastOptions;
    }

    /**
     * Returns the number of remaining items in the queue.
     */
    public function count(): int
    {
        return \count($this->queue);
    }

    public function reset(): void
    {
        $this->queue = [];
    }

    /**
     * @param mixed $reason Promise or reason.
     */
    private function invokeStats(
        RequestInterface $request,
        array $options,
        ?ResponseInterface $response = null,
        $reason = null
    ): void {
        if (isset($options['on_stats'])) {
            $transferTime = $options['transfer_time'] ?? 0;
            $stats = new TransferStats($request, $response, $transferTime, $reason);
            ($options['on_stats'])($stats);
        }
    }
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;

/**
 * Provides basic proxies for handlers.
 *
 * @final
 */
class Proxy
{
    /**
     * Sends synchronous requests to a specific handler while sending all other
     * requests to another handler.
     *
     * @param callable(RequestInterface, array): PromiseInterface $default Handler used for normal responses
     * @param callable(RequestInterface, array): PromiseInterface $sync    Handler used for synchronous responses.
     *
     * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
     */
    public static function wrapSync(callable $default, callable $sync): callable
    {
        return static function (RequestInterface $request, array $options) use ($default, $sync): PromiseInterface {
            return empty($options[RequestOptions::SYNCHRONOUS]) ? $default($request, $options) : $sync($request, $options);
        };
    }

    /**
     * Sends streaming requests to a streaming compatible handler while sending
     * all other requests to a default handler.
     *
     * This, for example, could be useful for taking advantage of the
     * performance benefits of curl while still supporting true streaming
     * through the StreamHandler.
     *
     * @param callable(RequestInterface, array): PromiseInterface $default   Handler used for non-streaming responses
     * @param callable(RequestInterface, array): PromiseInterface $streaming Handler used for streaming responses
     *
     * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
     */
    public static function wrapStreaming(callable $default, callable $streaming): callable
    {
        return static function (RequestInterface $request, array $options) use ($default, $streaming): PromiseInterface {
            return empty($options['stream']) ? $default($request, $options) : $streaming($request, $options);
        };
    }
}
<?php

namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

/**
 * HTTP handler that uses PHP's HTTP stream wrapper.
 *
 * @final
 */
class StreamHandler
{
    /**
     * @var array
     */
    private $lastHeaders = [];

    /**
     * Sends an HTTP request.
     *
     * @param RequestInterface $request Request to send.
     * @param array            $options Request transfer options.
     */
    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        // Sleep if there is a delay specified.
        if (isset($options['delay'])) {
            \usleep($options['delay'] * 1000);
        }

        $protocolVersion = $request->getProtocolVersion();

        if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
            throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
        }

        $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;

        try {
            // Does not support the expect header.
            $request = $request->withoutHeader('Expect');

            // Append a content-length header if body size is zero to match
            // the behavior of `CurlHandler`
            if (
                (
                    0 === \strcasecmp('PUT', $request->getMethod())
                    || 0 === \strcasecmp('POST', $request->getMethod())
                )
                && 0 === $request->getBody()->getSize()
            ) {
                $request = $request->withHeader('Content-Length', '0');
            }

            return $this->createResponse(
                $request,
                $options,
                $this->createStream($request, $options),
                $startTime
            );
        } catch (\InvalidArgumentException $e) {
            throw $e;
        } catch (\Exception $e) {
            // Determine if the error was a networking error.
            $message = $e->getMessage();
            // This list can probably get more comprehensive.
            if (false !== \strpos($message, 'getaddrinfo') // DNS lookup failed
                || false !== \strpos($message, 'Connection refused')
                || false !== \strpos($message, "couldn't connect to host") // error on HHVM
                || false !== \strpos($message, 'connection attempt failed')
            ) {
                $e = new ConnectException($e->getMessage(), $request, $e);
            } else {
                $e = RequestException::wrapException($request, $e);
            }
            $this->invokeStats($options, $request, $startTime, null, $e);

            return P\Create::rejectionFor($e);
        }
    }

    private function invokeStats(
        array $options,
        RequestInterface $request,
        ?float $startTime,
        ?ResponseInterface $response = null,
        ?\Throwable $error = null
    ): void {
        if (isset($options['on_stats'])) {
            $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
            ($options['on_stats'])($stats);
        }
    }

    /**
     * @param resource $stream
     */
    private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime): PromiseInterface
    {
        $hdrs = $this->lastHeaders;
        $this->lastHeaders = [];

        try {
            [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs);
        } catch (\Exception $e) {
            return P\Create::rejectionFor(
                new RequestException('An error was encountered while creating the response', $request, null, $e)
            );
        }

        [$stream, $headers] = $this->checkDecode($options, $headers, $stream);
        $stream = Psr7\Utils::streamFor($stream);
        $sink = $stream;

        if (\strcasecmp('HEAD', $request->getMethod())) {
            $sink = $this->createSink($stream, $options);
        }

        try {
            $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
        } catch (\Exception $e) {
            return P\Create::rejectionFor(
                new RequestException('An error was encountered while creating the response', $request, null, $e)
            );
        }

        if (isset($options['on_headers'])) {
            try {
                $options['on_headers']($response);
            } catch (\Exception $e) {
                return P\Create::rejectionFor(
                    new RequestException('An error was encountered during the on_headers event', $request, $response, $e)
                );
            }
        }

        // Do not drain when the request is a HEAD request because they have
        // no body.
        if ($sink !== $stream) {
            $this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
        }

        $this->invokeStats($options, $request, $startTime, $response, null);

        return new FulfilledPromise($response);
    }

    private function createSink(StreamInterface $stream, array $options): StreamInterface
    {
        if (!empty($options['stream'])) {
            return $stream;
        }

        $sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+');

        return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink);
    }

    /**
     * @param resource $stream
     */
    private function checkDecode(array $options, array $headers, $stream): array
    {
        // Automatically decode responses when instructed.
        if (!empty($options['decode_content'])) {
            $normalizedKeys = Utils::normalizeHeaderKeys($headers);
            if (isset($normalizedKeys['content-encoding'])) {
                $encoding = $headers[$normalizedKeys['content-encoding']];
                if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
                    $stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream));
                    $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];

                    // Remove content-encoding header
                    unset($headers[$normalizedKeys['content-encoding']]);

                    // Fix content-length header
                    if (isset($normalizedKeys['content-length'])) {
                        $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
                        $length = (int) $stream->getSize();
                        if ($length === 0) {
                            unset($headers[$normalizedKeys['content-length']]);
                        } else {
                            $headers[$normalizedKeys['content-length']] = [$length];
                        }
                    }
                }
            }
        }

        return [$stream, $headers];
    }

    /**
     * Drains the source stream into the "sink" client option.
     *
     * @param string $contentLength Header specifying the amount of
     *                              data to read.
     *
     * @throws \RuntimeException when the sink option is invalid.
     */
    private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength): StreamInterface
    {
        // If a content-length header is provided, then stop reading once
        // that number of bytes has been read. This can prevent infinitely
        // reading from a stream when dealing with servers that do not honor
        // Connection: Close headers.
        Psr7\Utils::copyToStream(
            $source,
            $sink,
            (\strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
        );

        $sink->seek(0);
        $source->close();

        return $sink;
    }

    /**
     * Create a resource and check to ensure it was created successfully
     *
     * @param callable $callback Callable that returns stream resource
     *
     * @return resource
     *
     * @throws \RuntimeException on error
     */
    private function createResource(callable $callback)
    {
        $errors = [];
        \set_error_handler(static function ($_, $msg, $file, $line) use (&$errors): bool {
            $errors[] = [
                'message' => $msg,
                'file' => $file,
                'line' => $line,
            ];

            return true;
        });

        try {
            $resource = $callback();
        } finally {
            \restore_error_handler();
        }

        if (!$resource) {
            $message = 'Error creating resource: ';
            foreach ($errors as $err) {
                foreach ($err as $key => $value) {
                    $message .= "[$key] $value".\PHP_EOL;
                }
            }
            throw new \RuntimeException(\trim($message));
        }

        return $resource;
    }

    /**
     * @return resource
     */
    private function createStream(RequestInterface $request, array $options)
    {
        static $methods;
        if (!$methods) {
            $methods = \array_flip(\get_class_methods(__CLASS__));
        }

        if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
            throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
        }

        // HTTP/1.1 streams using the PHP stream wrapper require a
        // Connection: close header
        if ($request->getProtocolVersion() === '1.1'
            && !$request->hasHeader('Connection')
        ) {
            $request = $request->withHeader('Connection', 'close');
        }

        // Ensure SSL is verified by default
        if (!isset($options['verify'])) {
            $options['verify'] = true;
        }

        $params = [];
        $context = $this->getDefaultContext($request);

        if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
            throw new \InvalidArgumentException('on_headers must be callable');
        }

        if (!empty($options)) {
            foreach ($options as $key => $value) {
                $method = "add_{$key}";
                if (isset($methods[$method])) {
                    $this->{$method}($request, $context, $value, $params);
                }
            }
        }

        if (isset($options['stream_context'])) {
            if (!\is_array($options['stream_context'])) {
                throw new \InvalidArgumentException('stream_context must be an array');
            }
            $context = \array_replace_recursive($context, $options['stream_context']);
        }

        // Microsoft NTLM authentication only supported with curl handler
        if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
            throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
        }

        $uri = $this->resolveHost($request, $options);

        $contextResource = $this->createResource(
            static function () use ($context, $params) {
                return \stream_context_create($context, $params);
            }
        );

        return $this->createResource(
            function () use ($uri, $contextResource, $context, $options, $request) {
                $resource = @\fopen((string) $uri, 'r', false, $contextResource);

                // See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable
                if (function_exists('http_get_last_response_headers')) {
                    /** @var array|null */
                    $http_response_header = \http_get_last_response_headers();
                }

                $this->lastHeaders = $http_response_header ?? [];

                if (false === $resource) {
                    throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context);
                }

                if (isset($options['read_timeout'])) {
                    $readTimeout = $options['read_timeout'];
                    $sec = (int) $readTimeout;
                    $usec = ($readTimeout - $sec) * 100000;
                    \stream_set_timeout($resource, $sec, $usec);
                }

                return $resource;
            }
        );
    }

    private function resolveHost(RequestInterface $request, array $options): UriInterface
    {
        $uri = $request->getUri();

        if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
            if ('v4' === $options['force_ip_resolve']) {
                $records = \dns_get_record($uri->getHost(), \DNS_A);
                if (false === $records || !isset($records[0]['ip'])) {
                    throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
                }

                return $uri->withHost($records[0]['ip']);
            }
            if ('v6' === $options['force_ip_resolve']) {
                $records = \dns_get_record($uri->getHost(), \DNS_AAAA);
                if (false === $records || !isset($records[0]['ipv6'])) {
                    throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
                }

                return $uri->withHost('['.$records[0]['ipv6'].']');
            }
        }

        return $uri;
    }

    private function getDefaultContext(RequestInterface $request): array
    {
        $headers = '';
        foreach ($request->getHeaders() as $name => $value) {
            foreach ($value as $val) {
                $headers .= "$name: $val\r\n";
            }
        }

        $context = [
            'http' => [
                'method' => $request->getMethod(),
                'header' => $headers,
                'protocol_version' => $request->getProtocolVersion(),
                'ignore_errors' => true,
                'follow_location' => 0,
            ],
            'ssl' => [
                'peer_name' => $request->getUri()->getHost(),
            ],
        ];

        $body = (string) $request->getBody();

        if ('' !== $body) {
            $context['http']['content'] = $body;
            // Prevent the HTTP handler from adding a Content-Type header.
            if (!$request->hasHeader('Content-Type')) {
                $context['http']['header'] .= "Content-Type:\r\n";
            }
        }

        $context['http']['header'] = \rtrim($context['http']['header']);

        return $context;
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_proxy(RequestInterface $request, array &$options, $value, array &$params): void
    {
        $uri = null;

        if (!\is_array($value)) {
            $uri = $value;
        } else {
            $scheme = $request->getUri()->getScheme();
            if (isset($value[$scheme])) {
                if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) {
                    $uri = $value[$scheme];
                }
            }
        }

        if (!$uri) {
            return;
        }

        $parsed = $this->parse_proxy($uri);
        $options['http']['proxy'] = $parsed['proxy'];

        if ($parsed['auth']) {
            if (!isset($options['http']['header'])) {
                $options['http']['header'] = [];
            }
            $options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}";
        }
    }

    /**
     * Parses the given proxy URL to make it compatible with the format PHP's stream context expects.
     */
    private function parse_proxy(string $url): array
    {
        $parsed = \parse_url($url);

        if ($parsed !== false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') {
            if (isset($parsed['host']) && isset($parsed['port'])) {
                $auth = null;
                if (isset($parsed['user']) && isset($parsed['pass'])) {
                    $auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}");
                }

                return [
                    'proxy' => "tcp://{$parsed['host']}:{$parsed['port']}",
                    'auth' => $auth ? "Basic {$auth}" : null,
                ];
            }
        }

        // Return proxy as-is.
        return [
            'proxy' => $url,
            'auth' => null,
        ];
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_timeout(RequestInterface $request, array &$options, $value, array &$params): void
    {
        if ($value > 0) {
            $options['http']['timeout'] = $value;
        }
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params): void
    {
        if (
            $value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
            || $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
            || $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
            || (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT)
        ) {
            $options['http']['crypto_method'] = $value;

            return;
        }

        throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_verify(RequestInterface $request, array &$options, $value, array &$params): void
    {
        if ($value === false) {
            $options['ssl']['verify_peer'] = false;
            $options['ssl']['verify_peer_name'] = false;

            return;
        }

        if (\is_string($value)) {
            $options['ssl']['cafile'] = $value;
            if (!\file_exists($value)) {
                throw new \RuntimeException("SSL CA bundle not found: $value");
            }
        } elseif ($value !== true) {
            throw new \InvalidArgumentException('Invalid verify request option');
        }

        $options['ssl']['verify_peer'] = true;
        $options['ssl']['verify_peer_name'] = true;
        $options['ssl']['allow_self_signed'] = false;
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_cert(RequestInterface $request, array &$options, $value, array &$params): void
    {
        if (\is_array($value)) {
            $options['ssl']['passphrase'] = $value[1];
            $value = $value[0];
        }

        if (!\file_exists($value)) {
            throw new \RuntimeException("SSL certificate not found: {$value}");
        }

        $options['ssl']['local_cert'] = $value;
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_progress(RequestInterface $request, array &$options, $value, array &$params): void
    {
        self::addNotification(
            $params,
            static function ($code, $a, $b, $c, $transferred, $total) use ($value) {
                if ($code == \STREAM_NOTIFY_PROGRESS) {
                    // The upload progress cannot be determined. Use 0 for cURL compatibility:
                    // https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
                    $value($total, $transferred, 0, 0);
                }
            }
        );
    }

    /**
     * @param mixed $value as passed via Request transfer options.
     */
    private function add_debug(RequestInterface $request, array &$options, $value, array &$params): void
    {
        if ($value === false) {
            return;
        }

        static $map = [
            \STREAM_NOTIFY_CONNECT => 'CONNECT',
            \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
            \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
            \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
            \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
            \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
            \STREAM_NOTIFY_PROGRESS => 'PROGRESS',
            \STREAM_NOTIFY_FAILURE => 'FAILURE',
            \STREAM_NOTIFY_COMPLETED => 'COMPLETED',
            \STREAM_NOTIFY_RESOLVE => 'RESOLVE',
        ];
        static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];

        $value = Utils::debugResource($value);
        $ident = $request->getMethod().' '.$request->getUri()->withFragment('');
        self::addNotification(
            $params,
            static function (int $code, ...$passed) use ($ident, $value, $map, $args): void {
                \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
                foreach (\array_filter($passed) as $i => $v) {
                    \fwrite($value, $args[$i].': "'.$v.'" ');
                }
                \fwrite($value, "\n");
            }
        );
    }

    private static function addNotification(array &$params, callable $notify): void
    {
        // Wrap the existing function if needed.
        if (!isset($params['notification'])) {
            $params['notification'] = $notify;
        } else {
            $params['notification'] = self::callArray([
                $params['notification'],
                $notify,
            ]);
        }
    }

    private static function callArray(array $functions): callable
    {
        return static function (...$args) use ($functions) {
            foreach ($functions as $fn) {
                $fn(...$args);
            }
        };
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Creates a composed Guzzle handler function by stacking middlewares on top of
 * an HTTP handler function.
 *
 * @final
 */
class HandlerStack
{
    /**
     * @var (callable(RequestInterface, array): PromiseInterface)|null
     */
    private $handler;

    /**
     * @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[]
     */
    private $stack = [];

    /**
     * @var (callable(RequestInterface, array): PromiseInterface)|null
     */
    private $cached;

    /**
     * Creates a default handler stack that can be used by clients.
     *
     * The returned handler will wrap the provided handler or use the most
     * appropriate default handler for your system. The returned HandlerStack has
     * support for cookies, redirects, HTTP error exceptions, and preparing a body
     * before sending.
     *
     * The returned handler stack can be passed to a client in the "handler"
     * option.
     *
     * @param (callable(RequestInterface, array): PromiseInterface)|null $handler HTTP handler function to use with the stack. If no
     *                                                                            handler is provided, the best handler for your
     *                                                                            system will be utilized.
     */
    public static function create(?callable $handler = null): self
    {
        $stack = new self($handler ?: Utils::chooseHandler());
        $stack->push(Middleware::httpErrors(), 'http_errors');
        $stack->push(Middleware::redirect(), 'allow_redirects');
        $stack->push(Middleware::cookies(), 'cookies');
        $stack->push(Middleware::prepareBody(), 'prepare_body');

        return $stack;
    }

    /**
     * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
     */
    public function __construct(?callable $handler = null)
    {
        $this->handler = $handler;
    }

    /**
     * Invokes the handler stack as a composed handler
     *
     * @return ResponseInterface|PromiseInterface
     */
    public function __invoke(RequestInterface $request, array $options)
    {
        $handler = $this->resolve();

        return $handler($request, $options);
    }

    /**
     * Dumps a string representation of the stack.
     *
     * @return string
     */
    public function __toString()
    {
        $depth = 0;
        $stack = [];

        if ($this->handler !== null) {
            $stack[] = '0) Handler: '.$this->debugCallable($this->handler);
        }

        $result = '';
        foreach (\array_reverse($this->stack) as $tuple) {
            ++$depth;
            $str = "{$depth}) Name: '{$tuple[1]}', ";
            $str .= 'Function: '.$this->debugCallable($tuple[0]);
            $result = "> {$str}\n{$result}";
            $stack[] = $str;
        }

        foreach (\array_keys($stack) as $k) {
            $result .= "< {$stack[$k]}\n";
        }

        return $result;
    }

    /**
     * Set the HTTP handler that actually returns a promise.
     *
     * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and
     *                                                                     returns a Promise.
     */
    public function setHandler(callable $handler): void
    {
        $this->handler = $handler;
        $this->cached = null;
    }

    /**
     * Returns true if the builder has a handler.
     */
    public function hasHandler(): bool
    {
        return $this->handler !== null;
    }

    /**
     * Unshift a middleware to the bottom of the stack.
     *
     * @param callable(callable): callable $middleware Middleware function
     * @param string                       $name       Name to register for this middleware.
     */
    public function unshift(callable $middleware, ?string $name = null): void
    {
        \array_unshift($this->stack, [$middleware, $name]);
        $this->cached = null;
    }

    /**
     * Push a middleware to the top of the stack.
     *
     * @param callable(callable): callable $middleware Middleware function
     * @param string                       $name       Name to register for this middleware.
     */
    public function push(callable $middleware, string $name = ''): void
    {
        $this->stack[] = [$middleware, $name];
        $this->cached = null;
    }

    /**
     * Add a middleware before another middleware by name.
     *
     * @param string                       $findName   Middleware to find
     * @param callable(callable): callable $middleware Middleware function
     * @param string                       $withName   Name to register for this middleware.
     */
    public function before(string $findName, callable $middleware, string $withName = ''): void
    {
        $this->splice($findName, $withName, $middleware, true);
    }

    /**
     * Add a middleware after another middleware by name.
     *
     * @param string                       $findName   Middleware to find
     * @param callable(callable): callable $middleware Middleware function
     * @param string                       $withName   Name to register for this middleware.
     */
    public function after(string $findName, callable $middleware, string $withName = ''): void
    {
        $this->splice($findName, $withName, $middleware, false);
    }

    /**
     * Remove a middleware by instance or name from the stack.
     *
     * @param callable|string $remove Middleware to remove by instance or name.
     */
    public function remove($remove): void
    {
        if (!is_string($remove) && !is_callable($remove)) {
            trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
        }

        $this->cached = null;
        $idx = \is_callable($remove) ? 0 : 1;
        $this->stack = \array_values(\array_filter(
            $this->stack,
            static function ($tuple) use ($idx, $remove) {
                return $tuple[$idx] !== $remove;
            }
        ));
    }

    /**
     * Compose the middleware and handler into a single callable function.
     *
     * @return callable(RequestInterface, array): PromiseInterface
     */
    public function resolve(): callable
    {
        if ($this->cached === null) {
            if (($prev = $this->handler) === null) {
                throw new \LogicException('No handler has been specified');
            }

            foreach (\array_reverse($this->stack) as $fn) {
                /** @var callable(RequestInterface, array): PromiseInterface $prev */
                $prev = $fn[0]($prev);
            }

            $this->cached = $prev;
        }

        return $this->cached;
    }

    private function findByName(string $name): int
    {
        foreach ($this->stack as $k => $v) {
            if ($v[1] === $name) {
                return $k;
            }
        }

        throw new \InvalidArgumentException("Middleware not found: $name");
    }

    /**
     * Splices a function into the middleware list at a specific position.
     */
    private function splice(string $findName, string $withName, callable $middleware, bool $before): void
    {
        $this->cached = null;
        $idx = $this->findByName($findName);
        $tuple = [$middleware, $withName];

        if ($before) {
            if ($idx === 0) {
                \array_unshift($this->stack, $tuple);
            } else {
                $replacement = [$tuple, $this->stack[$idx]];
                \array_splice($this->stack, $idx, 1, $replacement);
            }
        } elseif ($idx === \count($this->stack) - 1) {
            $this->stack[] = $tuple;
        } else {
            $replacement = [$this->stack[$idx], $tuple];
            \array_splice($this->stack, $idx, 1, $replacement);
        }
    }

    /**
     * Provides a debug string for a given callable.
     *
     * @param callable|string $fn Function to write as a string.
     */
    private function debugCallable($fn): string
    {
        if (\is_string($fn)) {
            return "callable({$fn})";
        }

        if (\is_array($fn)) {
            return \is_string($fn[0])
                ? "callable({$fn[0]}::{$fn[1]})"
                : "callable(['".\get_class($fn[0])."', '{$fn[1]}'])";
        }

        /** @var object $fn */
        return 'callable('.\spl_object_hash($fn).')';
    }
}
<?php

namespace GuzzleHttp;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Formats log messages using variable substitutions for requests, responses,
 * and other transactional data.
 *
 * The following variable substitutions are supported:
 *
 * - {request}:        Full HTTP request message
 * - {response}:       Full HTTP response message
 * - {ts}:             ISO 8601 date in GMT
 * - {date_iso_8601}   ISO 8601 date in GMT
 * - {date_common_log} Apache common log date using the configured timezone.
 * - {host}:           Host of the request
 * - {method}:         Method of the request
 * - {uri}:            URI of the request
 * - {version}:        Protocol version
 * - {target}:         Request target of the request (path + query + fragment)
 * - {hostname}:       Hostname of the machine that sent the request
 * - {code}:           Status code of the response (if available)
 * - {phrase}:         Reason phrase of the response  (if available)
 * - {error}:          Any error messages (if available)
 * - {req_header_*}:   Replace `*` with the lowercased name of a request header to add to the message
 * - {res_header_*}:   Replace `*` with the lowercased name of a response header to add to the message
 * - {req_headers}:    Request headers
 * - {res_headers}:    Response headers
 * - {req_body}:       Request body
 * - {res_body}:       Response body
 *
 * @final
 */
class MessageFormatter implements MessageFormatterInterface
{
    /**
     * Apache Common Log Format.
     *
     * @see https://httpd.apache.org/docs/2.4/logs.html#common
     *
     * @var string
     */
    public const CLF = '{hostname} {req_header_User-Agent} - [{date_common_log}] "{method} {target} HTTP/{version}" {code} {res_header_Content-Length}';
    public const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
    public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';

    /**
     * @var string Template used to format log messages
     */
    private $template;

    /**
     * @param string $template Log message template
     */
    public function __construct(?string $template = self::CLF)
    {
        $this->template = $template ?: self::CLF;
    }

    /**
     * Returns a formatted message string.
     *
     * @param RequestInterface       $request  Request that was sent
     * @param ResponseInterface|null $response Response that was received
     * @param \Throwable|null        $error    Exception that was received
     */
    public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string
    {
        $cache = [];

        /** @var string */
        return \preg_replace_callback(
            '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
            function (array $matches) use ($request, $response, $error, &$cache) {
                if (isset($cache[$matches[1]])) {
                    return $cache[$matches[1]];
                }

                $result = '';
                switch ($matches[1]) {
                    case 'request':
                        $result = Psr7\Message::toString($request);
                        break;
                    case 'response':
                        $result = $response ? Psr7\Message::toString($response) : '';
                        break;
                    case 'req_headers':
                        $result = \trim($request->getMethod()
                                .' '.$request->getRequestTarget())
                            .' HTTP/'.$request->getProtocolVersion()."\r\n"
                            .$this->headers($request);
                        break;
                    case 'res_headers':
                        $result = $response ?
                            \sprintf(
                                'HTTP/%s %d %s',
                                $response->getProtocolVersion(),
                                $response->getStatusCode(),
                                $response->getReasonPhrase()
                            )."\r\n".$this->headers($response)
                            : 'NULL';
                        break;
                    case 'req_body':
                        $result = $request->getBody()->__toString();
                        break;
                    case 'res_body':
                        if (!$response instanceof ResponseInterface) {
                            $result = 'NULL';
                            break;
                        }

                        $body = $response->getBody();

                        if (!$body->isSeekable()) {
                            $result = 'RESPONSE_NOT_LOGGEABLE';
                            break;
                        }

                        $result = $response->getBody()->__toString();
                        break;
                    case 'ts':
                    case 'date_iso_8601':
                        $result = \gmdate('c');
                        break;
                    case 'date_common_log':
                        $result = \date('d/M/Y:H:i:s O');
                        break;
                    case 'method':
                        $result = $request->getMethod();
                        break;
                    case 'version':
                        $result = $request->getProtocolVersion();
                        break;
                    case 'uri':
                    case 'url':
                        $result = $request->getUri()->__toString();
                        break;
                    case 'target':
                        $result = $request->getRequestTarget();
                        break;
                    case 'req_version':
                        $result = $request->getProtocolVersion();
                        break;
                    case 'res_version':
                        $result = $response
                            ? $response->getProtocolVersion()
                            : 'NULL';
                        break;
                    case 'host':
                        $result = $request->getHeaderLine('Host');
                        break;
                    case 'hostname':
                        $result = \gethostname();
                        break;
                    case 'code':
                        $result = $response ? $response->getStatusCode() : 'NULL';
                        break;
                    case 'phrase':
                        $result = $response ? $response->getReasonPhrase() : 'NULL';
                        break;
                    case 'error':
                        $result = $error ? $error->getMessage() : 'NULL';
                        break;
                    default:
                        // handle prefixed dynamic headers
                        if (\strpos($matches[1], 'req_header_') === 0) {
                            $result = $request->getHeaderLine(\substr($matches[1], 11));
                        } elseif (\strpos($matches[1], 'res_header_') === 0) {
                            $result = $response
                                ? $response->getHeaderLine(\substr($matches[1], 11))
                                : 'NULL';
                        }
                }

                $cache[$matches[1]] = $result;

                return $result;
            },
            $this->template
        );
    }

    /**
     * Get headers from message as string
     */
    private function headers(MessageInterface $message): string
    {
        $result = '';
        foreach ($message->getHeaders() as $name => $values) {
            $result .= $name.': '.\implode(', ', $values)."\r\n";
        }

        return \trim($result);
    }
}
<?php

namespace GuzzleHttp;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface MessageFormatterInterface
{
    /**
     * Returns a formatted message string.
     *
     * @param RequestInterface       $request  Request that was sent
     * @param ResponseInterface|null $response Response that was received
     * @param \Throwable|null        $error    Exception that was received
     */
    public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string;
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;

/**
 * Functions used to create and wrap handlers with handler middleware.
 */
final class Middleware
{
    /**
     * Middleware that adds cookies to requests.
     *
     * The options array must be set to a CookieJarInterface in order to use
     * cookies. This is typically handled for you by a client.
     *
     * @return callable Returns a function that accepts the next handler.
     */
    public static function cookies(): callable
    {
        return static function (callable $handler): callable {
            return static function ($request, array $options) use ($handler) {
                if (empty($options['cookies'])) {
                    return $handler($request, $options);
                } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
                    throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
                }
                $cookieJar = $options['cookies'];
                $request = $cookieJar->withCookieHeader($request);

                return $handler($request, $options)
                    ->then(
                        static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface {
                            $cookieJar->extractCookies($request, $response);

                            return $response;
                        }
                    );
            };
        };
    }

    /**
     * Middleware that throws exceptions for 4xx or 5xx responses when the
     * "http_errors" request option is set to true.
     *
     * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages.
     *
     * @return callable(callable): callable Returns a function that accepts the next handler.
     */
    public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable
    {
        return static function (callable $handler) use ($bodySummarizer): callable {
            return static function ($request, array $options) use ($handler, $bodySummarizer) {
                if (empty($options['http_errors'])) {
                    return $handler($request, $options);
                }

                return $handler($request, $options)->then(
                    static function (ResponseInterface $response) use ($request, $bodySummarizer) {
                        $code = $response->getStatusCode();
                        if ($code < 400) {
                            return $response;
                        }
                        throw RequestException::create($request, $response, null, [], $bodySummarizer);
                    }
                );
            };
        };
    }

    /**
     * Middleware that pushes history data to an ArrayAccess container.
     *
     * @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference).
     *
     * @return callable(callable): callable Returns a function that accepts the next handler.
     *
     * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
     */
    public static function history(&$container): callable
    {
        if (!\is_array($container) && !$container instanceof \ArrayAccess) {
            throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
        }

        return static function (callable $handler) use (&$container): callable {
            return static function (RequestInterface $request, array $options) use ($handler, &$container) {
                return $handler($request, $options)->then(
                    static function ($value) use ($request, &$container, $options) {
                        $container[] = [
                            'request' => $request,
                            'response' => $value,
                            'error' => null,
                            'options' => $options,
                        ];

                        return $value;
                    },
                    static function ($reason) use ($request, &$container, $options) {
                        $container[] = [
                            'request' => $request,
                            'response' => null,
                            'error' => $reason,
                            'options' => $options,
                        ];

                        return P\Create::rejectionFor($reason);
                    }
                );
            };
        };
    }

    /**
     * Middleware that invokes a callback before and after sending a request.
     *
     * The provided listener cannot modify or alter the response. It simply
     * "taps" into the chain to be notified before returning the promise. The
     * before listener accepts a request and options array, and the after
     * listener accepts a request, options array, and response promise.
     *
     * @param callable $before Function to invoke before forwarding the request.
     * @param callable $after  Function invoked after forwarding.
     *
     * @return callable Returns a function that accepts the next handler.
     */
    public static function tap(?callable $before = null, ?callable $after = null): callable
    {
        return static function (callable $handler) use ($before, $after): callable {
            return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
                if ($before) {
                    $before($request, $options);
                }
                $response = $handler($request, $options);
                if ($after) {
                    $after($request, $options, $response);
                }

                return $response;
            };
        };
    }

    /**
     * Middleware that handles request redirects.
     *
     * @return callable Returns a function that accepts the next handler.
     */
    public static function redirect(): callable
    {
        return static function (callable $handler): RedirectMiddleware {
            return new RedirectMiddleware($handler);
        };
    }

    /**
     * Middleware that retries requests based on the boolean result of
     * invoking the provided "decider" function.
     *
     * If no delay function is provided, a simple implementation of exponential
     * backoff will be utilized.
     *
     * @param callable $decider Function that accepts the number of retries,
     *                          a request, [response], and [exception] and
     *                          returns true if the request is to be retried.
     * @param callable $delay   Function that accepts the number of retries and
     *                          returns the number of milliseconds to delay.
     *
     * @return callable Returns a function that accepts the next handler.
     */
    public static function retry(callable $decider, ?callable $delay = null): callable
    {
        return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
            return new RetryMiddleware($decider, $handler, $delay);
        };
    }

    /**
     * Middleware that logs requests, responses, and errors using a message
     * formatter.
     *
     * @param LoggerInterface                            $logger    Logs messages.
     * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings.
     * @param string                                     $logLevel  Level at which to log requests.
     *
     * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.
     *
     * @return callable Returns a function that accepts the next handler.
     */
    public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable
    {
        // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter
        if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) {
            throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class));
        }

        return static function (callable $handler) use ($logger, $formatter, $logLevel): callable {
            return static function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) {
                return $handler($request, $options)->then(
                    static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface {
                        $message = $formatter->format($request, $response);
                        $logger->log($logLevel, $message);

                        return $response;
                    },
                    static function ($reason) use ($logger, $request, $formatter): PromiseInterface {
                        $response = $reason instanceof RequestException ? $reason->getResponse() : null;
                        $message = $formatter->format($request, $response, P\Create::exceptionFor($reason));
                        $logger->error($message);

                        return P\Create::rejectionFor($reason);
                    }
                );
            };
        };
    }

    /**
     * This middleware adds a default content-type if possible, a default
     * content-length or transfer-encoding header, and the expect header.
     */
    public static function prepareBody(): callable
    {
        return static function (callable $handler): PrepareBodyMiddleware {
            return new PrepareBodyMiddleware($handler);
        };
    }

    /**
     * Middleware that applies a map function to the request before passing to
     * the next handler.
     *
     * @param callable $fn Function that accepts a RequestInterface and returns
     *                     a RequestInterface.
     */
    public static function mapRequest(callable $fn): callable
    {
        return static function (callable $handler) use ($fn): callable {
            return static function (RequestInterface $request, array $options) use ($handler, $fn) {
                return $handler($fn($request), $options);
            };
        };
    }

    /**
     * Middleware that applies a map function to the resolved promise's
     * response.
     *
     * @param callable $fn Function that accepts a ResponseInterface and
     *                     returns a ResponseInterface.
     */
    public static function mapResponse(callable $fn): callable
    {
        return static function (callable $handler) use ($fn): callable {
            return static function (RequestInterface $request, array $options) use ($handler, $fn) {
                return $handler($request, $options)->then($fn);
            };
        };
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\PromisorInterface;
use Psr\Http\Message\RequestInterface;

/**
 * Sends an iterator of requests concurrently using a capped pool size.
 *
 * The pool will read from an iterator until it is cancelled or until the
 * iterator is consumed. When a request is yielded, the request is sent after
 * applying the "request_options" request options (if provided in the ctor).
 *
 * When a function is yielded by the iterator, the function is provided the
 * "request_options" array that should be merged on top of any existing
 * options, and the function MUST then return a wait-able promise.
 *
 * @final
 */
class Pool implements PromisorInterface
{
    /**
     * @var EachPromise
     */
    private $each;

    /**
     * @param ClientInterface $client   Client used to send the requests.
     * @param array|\Iterator $requests Requests or functions that return
     *                                  requests to send concurrently.
     * @param array           $config   Associative array of options
     *                                  - concurrency: (int) Maximum number of requests to send concurrently
     *                                  - options: Array of request options to apply to each request.
     *                                  - fulfilled: (callable) Function to invoke when a request completes.
     *                                  - rejected: (callable) Function to invoke when a request is rejected.
     */
    public function __construct(ClientInterface $client, $requests, array $config = [])
    {
        if (!isset($config['concurrency'])) {
            $config['concurrency'] = 25;
        }

        if (isset($config['options'])) {
            $opts = $config['options'];
            unset($config['options']);
        } else {
            $opts = [];
        }

        $iterable = P\Create::iterFor($requests);
        $requests = static function () use ($iterable, $client, $opts) {
            foreach ($iterable as $key => $rfn) {
                if ($rfn instanceof RequestInterface) {
                    yield $key => $client->sendAsync($rfn, $opts);
                } elseif (\is_callable($rfn)) {
                    yield $key => $rfn($opts);
                } else {
                    throw new \InvalidArgumentException('Each value yielded by the iterator must be a Psr7\Http\Message\RequestInterface or a callable that returns a promise that fulfills with a Psr7\Message\Http\ResponseInterface object.');
                }
            }
        };

        $this->each = new EachPromise($requests(), $config);
    }

    /**
     * Get promise
     */
    public function promise(): PromiseInterface
    {
        return $this->each->promise();
    }

    /**
     * Sends multiple requests concurrently and returns an array of responses
     * and exceptions that uses the same ordering as the provided requests.
     *
     * IMPORTANT: This method keeps every request and response in memory, and
     * as such, is NOT recommended when sending a large number or an
     * indeterminate number of requests concurrently.
     *
     * @param ClientInterface $client   Client used to send the requests
     * @param array|\Iterator $requests Requests to send concurrently.
     * @param array           $options  Passes through the options available in
     *                                  {@see Pool::__construct}
     *
     * @return array Returns an array containing the response or an exception
     *               in the same order that the requests were sent.
     *
     * @throws \InvalidArgumentException if the event format is incorrect.
     */
    public static function batch(ClientInterface $client, $requests, array $options = []): array
    {
        $res = [];
        self::cmpCallback($options, 'fulfilled', $res);
        self::cmpCallback($options, 'rejected', $res);
        $pool = new static($client, $requests, $options);
        $pool->promise()->wait();
        \ksort($res);

        return $res;
    }

    /**
     * Execute callback(s)
     */
    private static function cmpCallback(array &$options, string $name, array &$results): void
    {
        if (!isset($options[$name])) {
            $options[$name] = static function ($v, $k) use (&$results) {
                $results[$k] = $v;
            };
        } else {
            $currentFn = $options[$name];
            $options[$name] = static function ($v, $k) use (&$results, $currentFn) {
                $currentFn($v, $k);
                $results[$k] = $v;
            };
        }
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;

/**
 * Prepares requests that contain a body, adding the Content-Length,
 * Content-Type, and Expect headers.
 *
 * @final
 */
class PrepareBodyMiddleware
{
    /**
     * @var callable(RequestInterface, array): PromiseInterface
     */
    private $nextHandler;

    /**
     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
     */
    public function __construct(callable $nextHandler)
    {
        $this->nextHandler = $nextHandler;
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        $fn = $this->nextHandler;

        // Don't do anything if the request has no body.
        if ($request->getBody()->getSize() === 0) {
            return $fn($request, $options);
        }

        $modify = [];

        // Add a default content-type if possible.
        if (!$request->hasHeader('Content-Type')) {
            if ($uri = $request->getBody()->getMetadata('uri')) {
                if (is_string($uri) && $type = Psr7\MimeType::fromFilename($uri)) {
                    $modify['set_headers']['Content-Type'] = $type;
                }
            }
        }

        // Add a default content-length or transfer-encoding header.
        if (!$request->hasHeader('Content-Length')
            && !$request->hasHeader('Transfer-Encoding')
        ) {
            $size = $request->getBody()->getSize();
            if ($size !== null) {
                $modify['set_headers']['Content-Length'] = $size;
            } else {
                $modify['set_headers']['Transfer-Encoding'] = 'chunked';
            }
        }

        // Add the expect header if needed.
        $this->addExpectHeader($request, $options, $modify);

        return $fn(Psr7\Utils::modifyRequest($request, $modify), $options);
    }

    /**
     * Add expect header
     */
    private function addExpectHeader(RequestInterface $request, array $options, array &$modify): void
    {
        // Determine if the Expect header should be used
        if ($request->hasHeader('Expect')) {
            return;
        }

        $expect = $options['expect'] ?? null;

        // Return if disabled or using HTTP/1.0
        if ($expect === false || $request->getProtocolVersion() === '1.0') {
            return;
        }

        // The expect header is unconditionally enabled
        if ($expect === true) {
            $modify['set_headers']['Expect'] = '100-Continue';

            return;
        }

        // By default, send the expect header when the payload is > 1mb
        if ($expect === null) {
            $expect = 1048576;
        }

        // Always add if the body cannot be rewound, the size cannot be
        // determined, or the size is greater than the cutoff threshold
        $body = $request->getBody();
        $size = $body->getSize();

        if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
            $modify['set_headers']['Expect'] = '100-Continue';
        }
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\TooManyRedirectsException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
 * Request redirect middleware.
 *
 * Apply this middleware like other middleware using
 * {@see \GuzzleHttp\Middleware::redirect()}.
 *
 * @final
 */
class RedirectMiddleware
{
    public const HISTORY_HEADER = 'X-Guzzle-Redirect-History';

    public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';

    /**
     * @var array
     */
    public static $defaultSettings = [
        'max' => 5,
        'protocols' => ['http', 'https'],
        'strict' => false,
        'referer' => false,
        'track_redirects' => false,
    ];

    /**
     * @var callable(RequestInterface, array): PromiseInterface
     */
    private $nextHandler;

    /**
     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
     */
    public function __construct(callable $nextHandler)
    {
        $this->nextHandler = $nextHandler;
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        $fn = $this->nextHandler;

        if (empty($options['allow_redirects'])) {
            return $fn($request, $options);
        }

        if ($options['allow_redirects'] === true) {
            $options['allow_redirects'] = self::$defaultSettings;
        } elseif (!\is_array($options['allow_redirects'])) {
            throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
        } else {
            // Merge the default settings with the provided settings
            $options['allow_redirects'] += self::$defaultSettings;
        }

        if (empty($options['allow_redirects']['max'])) {
            return $fn($request, $options);
        }

        return $fn($request, $options)
            ->then(function (ResponseInterface $response) use ($request, $options) {
                return $this->checkRedirect($request, $options, $response);
            });
    }

    /**
     * @return ResponseInterface|PromiseInterface
     */
    public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response)
    {
        if (\strpos((string) $response->getStatusCode(), '3') !== 0
            || !$response->hasHeader('Location')
        ) {
            return $response;
        }

        $this->guardMax($request, $response, $options);
        $nextRequest = $this->modifyRequest($request, $options, $response);

        // If authorization is handled by curl, unset it if URI is cross-origin.
        if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\CURLOPT_HTTPAUTH')) {
            unset(
                $options['curl'][\CURLOPT_HTTPAUTH],
                $options['curl'][\CURLOPT_USERPWD]
            );
        }

        if (isset($options['allow_redirects']['on_redirect'])) {
            ($options['allow_redirects']['on_redirect'])(
                $request,
                $response,
                $nextRequest->getUri()
            );
        }

        $promise = $this($nextRequest, $options);

        // Add headers to be able to track history of redirects.
        if (!empty($options['allow_redirects']['track_redirects'])) {
            return $this->withTracking(
                $promise,
                (string) $nextRequest->getUri(),
                $response->getStatusCode()
            );
        }

        return $promise;
    }

    /**
     * Enable tracking on promise.
     */
    private function withTracking(PromiseInterface $promise, string $uri, int $statusCode): PromiseInterface
    {
        return $promise->then(
            static function (ResponseInterface $response) use ($uri, $statusCode) {
                // Note that we are pushing to the front of the list as this
                // would be an earlier response than what is currently present
                // in the history header.
                $historyHeader = $response->getHeader(self::HISTORY_HEADER);
                $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
                \array_unshift($historyHeader, $uri);
                \array_unshift($statusHeader, (string) $statusCode);

                return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
                                ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
            }
        );
    }

    /**
     * Check for too many redirects.
     *
     * @throws TooManyRedirectsException Too many redirects.
     */
    private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options): void
    {
        $current = $options['__redirect_count']
            ?? 0;
        $options['__redirect_count'] = $current + 1;
        $max = $options['allow_redirects']['max'];

        if ($options['__redirect_count'] > $max) {
            throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response);
        }
    }

    public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response): RequestInterface
    {
        // Request modifications to apply.
        $modify = [];
        $protocols = $options['allow_redirects']['protocols'];

        // Use a GET request if this is an entity enclosing request and we are
        // not forcing RFC compliance, but rather emulating what all browsers
        // would do.
        $statusCode = $response->getStatusCode();
        if ($statusCode == 303
            || ($statusCode <= 302 && !$options['allow_redirects']['strict'])
        ) {
            $safeMethods = ['GET', 'HEAD', 'OPTIONS'];
            $requestMethod = $request->getMethod();

            $modify['method'] = in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET';
            $modify['body'] = '';
        }

        $uri = self::redirectUri($request, $response, $protocols);
        if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
            $idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion'];
            $uri = Utils::idnUriConvert($uri, $idnOptions);
        }

        $modify['uri'] = $uri;
        Psr7\Message::rewindBody($request);

        // Add the Referer header if it is told to do so and only
        // add the header if we are not redirecting from https to http.
        if ($options['allow_redirects']['referer']
            && $modify['uri']->getScheme() === $request->getUri()->getScheme()
        ) {
            $uri = $request->getUri()->withUserInfo('');
            $modify['set_headers']['Referer'] = (string) $uri;
        } else {
            $modify['remove_headers'][] = 'Referer';
        }

        // Remove Authorization and Cookie headers if URI is cross-origin.
        if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) {
            $modify['remove_headers'][] = 'Authorization';
            $modify['remove_headers'][] = 'Cookie';
        }

        return Psr7\Utils::modifyRequest($request, $modify);
    }

    /**
     * Set the appropriate URL on the request based on the location header.
     */
    private static function redirectUri(
        RequestInterface $request,
        ResponseInterface $response,
        array $protocols
    ): UriInterface {
        $location = Psr7\UriResolver::resolve(
            $request->getUri(),
            new Psr7\Uri($response->getHeaderLine('Location'))
        );

        // Ensure that the redirect URI is allowed based on the protocols.
        if (!\in_array($location->getScheme(), $protocols)) {
            throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response);
        }

        return $location;
    }
}
<?php

namespace GuzzleHttp;

/**
 * This class contains a list of built-in Guzzle request options.
 *
 * @see https://docs.guzzlephp.org/en/latest/request-options.html
 */
final class RequestOptions
{
    /**
     * allow_redirects: (bool|array) Controls redirect behavior. Pass false
     * to disable redirects, pass true to enable redirects, pass an
     * associative to provide custom redirect settings. Defaults to "false".
     * This option only works if your handler has the RedirectMiddleware. When
     * passing an associative array, you can provide the following key value
     * pairs:
     *
     * - max: (int, default=5) maximum number of allowed redirects.
     * - strict: (bool, default=false) Set to true to use strict redirects
     *   meaning redirect POST requests with POST requests vs. doing what most
     *   browsers do which is redirect POST requests with GET requests
     * - referer: (bool, default=false) Set to true to enable the Referer
     *   header.
     * - protocols: (array, default=['http', 'https']) Allowed redirect
     *   protocols.
     * - on_redirect: (callable) PHP callable that is invoked when a redirect
     *   is encountered. The callable is invoked with the request, the redirect
     *   response that was received, and the effective URI. Any return value
     *   from the on_redirect function is ignored.
     */
    public const ALLOW_REDIRECTS = 'allow_redirects';

    /**
     * auth: (array) Pass an array of HTTP authentication parameters to use
     * with the request. The array must contain the username in index [0],
     * the password in index [1], and you can optionally provide a built-in
     * authentication type in index [2]. Pass null to disable authentication
     * for a request.
     */
    public const AUTH = 'auth';

    /**
     * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
     * Body to send in the request.
     */
    public const BODY = 'body';

    /**
     * cert: (string|array) Set to a string to specify the path to a file
     * containing a PEM formatted SSL client side certificate. If a password
     * is required, then set cert to an array containing the path to the PEM
     * file in the first array element followed by the certificate password
     * in the second array element.
     */
    public const CERT = 'cert';

    /**
     * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
     * Specifies whether or not cookies are used in a request or what cookie
     * jar to use or what cookies to send. This option only works if your
     * handler has the `cookie` middleware. Valid values are `false` and
     * an instance of {@see Cookie\CookieJarInterface}.
     */
    public const COOKIES = 'cookies';

    /**
     * connect_timeout: (float, default=0) Float describing the number of
     * seconds to wait while trying to connect to a server. Use 0 to wait
     * 300 seconds (the default behavior).
     */
    public const CONNECT_TIMEOUT = 'connect_timeout';

    /**
     * crypto_method: (int) A value describing the minimum TLS protocol
     * version to use.
     *
     * This setting must be set to one of the
     * ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is
     * required in order to use TLS 1.3, and cURL 7.34.0 or higher is required
     * in order to specify a crypto method, with cURL 7.52.0 or higher being
     * required to use TLS 1.3.
     */
    public const CRYPTO_METHOD = 'crypto_method';

    /**
     * debug: (bool|resource) Set to true or set to a PHP stream returned by
     * fopen()  enable debug output with the HTTP handler used to send a
     * request.
     */
    public const DEBUG = 'debug';

    /**
     * decode_content: (bool, default=true) Specify whether or not
     * Content-Encoding responses (gzip, deflate, etc.) are automatically
     * decoded.
     */
    public const DECODE_CONTENT = 'decode_content';

    /**
     * delay: (int) The amount of time to delay before sending in milliseconds.
     */
    public const DELAY = 'delay';

    /**
     * expect: (bool|integer) Controls the behavior of the
     * "Expect: 100-Continue" header.
     *
     * Set to `true` to enable the "Expect: 100-Continue" header for all
     * requests that sends a body. Set to `false` to disable the
     * "Expect: 100-Continue" header for all requests. Set to a number so that
     * the size of the payload must be greater than the number in order to send
     * the Expect header. Setting to a number will send the Expect header for
     * all requests in which the size of the payload cannot be determined or
     * where the body is not rewindable.
     *
     * By default, Guzzle will add the "Expect: 100-Continue" header when the
     * size of the body of a request is greater than 1 MB and a request is
     * using HTTP/1.1.
     */
    public const EXPECT = 'expect';

    /**
     * form_params: (array) Associative array of form field names to values
     * where each value is a string or array of strings. Sets the Content-Type
     * header to application/x-www-form-urlencoded when no Content-Type header
     * is already present.
     */
    public const FORM_PARAMS = 'form_params';

    /**
     * headers: (array) Associative array of HTTP headers. Each value MUST be
     * a string or array of strings.
     */
    public const HEADERS = 'headers';

    /**
     * http_errors: (bool, default=true) Set to false to disable exceptions
     * when a non- successful HTTP response is received. By default,
     * exceptions will be thrown for 4xx and 5xx responses. This option only
     * works if your handler has the `httpErrors` middleware.
     */
    public const HTTP_ERRORS = 'http_errors';

    /**
     * idn: (bool|int, default=true) A combination of IDNA_* constants for
     * idn_to_ascii() PHP's function (see "options" parameter). Set to false to
     * disable IDN support completely, or to true to use the default
     * configuration (IDNA_DEFAULT constant).
     */
    public const IDN_CONVERSION = 'idn_conversion';

    /**
     * json: (mixed) Adds JSON data to a request. The provided value is JSON
     * encoded and a Content-Type header of application/json will be added to
     * the request if no Content-Type header is already present.
     */
    public const JSON = 'json';

    /**
     * multipart: (array) Array of associative arrays, each containing a
     * required "name" key mapping to the form field, name, a required
     * "contents" key mapping to a StreamInterface|resource|string, an
     * optional "headers" associative array of custom headers, and an
     * optional "filename" key mapping to a string to send as the filename in
     * the part. If no "filename" key is present, then no "filename" attribute
     * will be added to the part.
     */
    public const MULTIPART = 'multipart';

    /**
     * on_headers: (callable) A callable that is invoked when the HTTP headers
     * of the response have been received but the body has not yet begun to
     * download.
     */
    public const ON_HEADERS = 'on_headers';

    /**
     * on_stats: (callable) allows you to get access to transfer statistics of
     * a request and access the lower level transfer details of the handler
     * associated with your client. ``on_stats`` is a callable that is invoked
     * when a handler has finished sending a request. The callback is invoked
     * with transfer statistics about the request, the response received, or
     * the error encountered. Included in the data is the total amount of time
     * taken to send the request.
     */
    public const ON_STATS = 'on_stats';

    /**
     * progress: (callable) Defines a function to invoke when transfer
     * progress is made. The function accepts the following positional
     * arguments: the total number of bytes expected to be downloaded, the
     * number of bytes downloaded so far, the number of bytes expected to be
     * uploaded, the number of bytes uploaded so far.
     */
    public const PROGRESS = 'progress';

    /**
     * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
     * array to specify different proxies for different protocols (where the
     * key is the protocol and the value is a proxy string).
     */
    public const PROXY = 'proxy';

    /**
     * query: (array|string) Associative array of query string values to add
     * to the request. This option uses PHP's http_build_query() to create
     * the string representation. Pass a string value if you need more
     * control than what this method provides
     */
    public const QUERY = 'query';

    /**
     * sink: (resource|string|StreamInterface) Where the data of the
     * response is written to. Defaults to a PHP temp stream. Providing a
     * string will write data to a file by the given name.
     */
    public const SINK = 'sink';

    /**
     * synchronous: (bool) Set to true to inform HTTP handlers that you intend
     * on waiting on the response. This can be useful for optimizations. Note
     * that a promise is still returned if you are using one of the async
     * client methods.
     */
    public const SYNCHRONOUS = 'synchronous';

    /**
     * ssl_key: (array|string) Specify the path to a file containing a private
     * SSL key in PEM format. If a password is required, then set to an array
     * containing the path to the SSL key in the first array element followed
     * by the password required for the certificate in the second element.
     */
    public const SSL_KEY = 'ssl_key';

    /**
     * stream: Set to true to attempt to stream a response rather than
     * download it all up-front.
     */
    public const STREAM = 'stream';

    /**
     * verify: (bool|string, default=true) Describes the SSL certificate
     * verification behavior of a request. Set to true to enable SSL
     * certificate verification using the system CA bundle when available
     * (the default). Set to false to disable certificate verification (this
     * is insecure!). Set to a string to provide the path to a CA bundle on
     * disk to enable verification using a custom certificate.
     */
    public const VERIFY = 'verify';

    /**
     * timeout: (float, default=0) Float describing the timeout of the
     * request in seconds. Use 0 to wait indefinitely (the default behavior).
     */
    public const TIMEOUT = 'timeout';

    /**
     * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
     * the body read timeout, for stream requests.
     */
    public const READ_TIMEOUT = 'read_timeout';

    /**
     * version: (float) Specifies the HTTP protocol version to attempt to use.
     */
    public const VERSION = 'version';

    /**
     * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
     */
    public const FORCE_IP_RESOLVE = 'force_ip_resolve';
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Middleware that retries requests based on the boolean result of
 * invoking the provided "decider" function.
 *
 * @final
 */
class RetryMiddleware
{
    /**
     * @var callable(RequestInterface, array): PromiseInterface
     */
    private $nextHandler;

    /**
     * @var callable
     */
    private $decider;

    /**
     * @var callable(int)
     */
    private $delay;

    /**
     * @param callable                                            $decider     Function that accepts the number of retries,
     *                                                                         a request, [response], and [exception] and
     *                                                                         returns true if the request is to be
     *                                                                         retried.
     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
     * @param (callable(int): int)|null                           $delay       Function that accepts the number of retries
     *                                                                         and returns the number of
     *                                                                         milliseconds to delay.
     */
    public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)
    {
        $this->decider = $decider;
        $this->nextHandler = $nextHandler;
        $this->delay = $delay ?: __CLASS__.'::exponentialDelay';
    }

    /**
     * Default exponential backoff delay function.
     *
     * @return int milliseconds.
     */
    public static function exponentialDelay(int $retries): int
    {
        return (int) 2 ** ($retries - 1) * 1000;
    }

    public function __invoke(RequestInterface $request, array $options): PromiseInterface
    {
        if (!isset($options['retries'])) {
            $options['retries'] = 0;
        }

        $fn = $this->nextHandler;

        return $fn($request, $options)
            ->then(
                $this->onFulfilled($request, $options),
                $this->onRejected($request, $options)
            );
    }

    /**
     * Execute fulfilled closure
     */
    private function onFulfilled(RequestInterface $request, array $options): callable
    {
        return function ($value) use ($request, $options) {
            if (!($this->decider)(
                $options['retries'],
                $request,
                $value,
                null
            )) {
                return $value;
            }

            return $this->doRetry($request, $options, $value);
        };
    }

    /**
     * Execute rejected closure
     */
    private function onRejected(RequestInterface $req, array $options): callable
    {
        return function ($reason) use ($req, $options) {
            if (!($this->decider)(
                $options['retries'],
                $req,
                null,
                $reason
            )) {
                return P\Create::rejectionFor($reason);
            }

            return $this->doRetry($req, $options);
        };
    }

    private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface
    {
        $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);

        return $this($request, $options);
    }
}
<?php

namespace GuzzleHttp;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
 * Represents data at the point after it was transferred either successfully
 * or after a network error.
 */
final class TransferStats
{
    /**
     * @var RequestInterface
     */
    private $request;

    /**
     * @var ResponseInterface|null
     */
    private $response;

    /**
     * @var float|null
     */
    private $transferTime;

    /**
     * @var array
     */
    private $handlerStats;

    /**
     * @var mixed|null
     */
    private $handlerErrorData;

    /**
     * @param RequestInterface       $request          Request that was sent.
     * @param ResponseInterface|null $response         Response received (if any)
     * @param float|null             $transferTime     Total handler transfer time.
     * @param mixed                  $handlerErrorData Handler error data.
     * @param array                  $handlerStats     Handler specific stats.
     */
    public function __construct(
        RequestInterface $request,
        ?ResponseInterface $response = null,
        ?float $transferTime = null,
        $handlerErrorData = null,
        array $handlerStats = []
    ) {
        $this->request = $request;
        $this->response = $response;
        $this->transferTime = $transferTime;
        $this->handlerErrorData = $handlerErrorData;
        $this->handlerStats = $handlerStats;
    }

    public function getRequest(): RequestInterface
    {
        return $this->request;
    }

    /**
     * Returns the response that was received (if any).
     */
    public function getResponse(): ?ResponseInterface
    {
        return $this->response;
    }

    /**
     * Returns true if a response was received.
     */
    public function hasResponse(): bool
    {
        return $this->response !== null;
    }

    /**
     * Gets handler specific error data.
     *
     * This might be an exception, a integer representing an error code, or
     * anything else. Relying on this value assumes that you know what handler
     * you are using.
     *
     * @return mixed
     */
    public function getHandlerErrorData()
    {
        return $this->handlerErrorData;
    }

    /**
     * Get the effective URI the request was sent to.
     */
    public function getEffectiveUri(): UriInterface
    {
        return $this->request->getUri();
    }

    /**
     * Get the estimated time the request was being transferred by the handler.
     *
     * @return float|null Time in seconds.
     */
    public function getTransferTime(): ?float
    {
        return $this->transferTime;
    }

    /**
     * Gets an array of all of the handler specific transfer data.
     */
    public function getHandlerStats(): array
    {
        return $this->handlerStats;
    }

    /**
     * Get a specific handler statistic from the handler by name.
     *
     * @param string $stat Handler specific transfer stat to retrieve.
     *
     * @return mixed|null
     */
    public function getHandlerStat(string $stat)
    {
        return $this->handlerStats[$stat] ?? null;
    }
}
<?php

namespace GuzzleHttp;

use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Handler\CurlMultiHandler;
use GuzzleHttp\Handler\Proxy;
use GuzzleHttp\Handler\StreamHandler;
use Psr\Http\Message\UriInterface;

final class Utils
{
    /**
     * Debug function used to describe the provided value type and class.
     *
     * @param mixed $input
     *
     * @return string Returns a string containing the type of the variable and
     *                if a class is provided, the class name.
     */
    public static function describeType($input): string
    {
        switch (\gettype($input)) {
            case 'object':
                return 'object('.\get_class($input).')';
            case 'array':
                return 'array('.\count($input).')';
            default:
                \ob_start();
                \var_dump($input);
                // normalize float vs double
                /** @var string $varDumpContent */
                $varDumpContent = \ob_get_clean();

                return \str_replace('double(', 'float(', \rtrim($varDumpContent));
        }
    }

    /**
     * Parses an array of header lines into an associative array of headers.
     *
     * @param iterable $lines Header lines array of strings in the following
     *                        format: "Name: Value"
     */
    public static function headersFromLines(iterable $lines): array
    {
        $headers = [];

        foreach ($lines as $line) {
            $parts = \explode(':', $line, 2);
            $headers[\trim($parts[0])][] = isset($parts[1]) ? \trim($parts[1]) : null;
        }

        return $headers;
    }

    /**
     * Returns a debug stream based on the provided variable.
     *
     * @param mixed $value Optional value
     *
     * @return resource
     */
    public static function debugResource($value = null)
    {
        if (\is_resource($value)) {
            return $value;
        }
        if (\defined('STDOUT')) {
            return \STDOUT;
        }

        return Psr7\Utils::tryFopen('php://output', 'w');
    }

    /**
     * Chooses and creates a default handler to use based on the environment.
     *
     * The returned handler is not wrapped by any default middlewares.
     *
     * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
     *
     * @throws \RuntimeException if no viable Handler is available.
     */
    public static function chooseHandler(): callable
    {
        $handler = null;

        if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) {
            if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
                $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
            } elseif (\function_exists('curl_exec')) {
                $handler = new CurlHandler();
            } elseif (\function_exists('curl_multi_exec')) {
                $handler = new CurlMultiHandler();
            }
        }

        if (\ini_get('allow_url_fopen')) {
            $handler = $handler
                ? Proxy::wrapStreaming($handler, new StreamHandler())
                : new StreamHandler();
        } elseif (!$handler) {
            throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.');
        }

        return $handler;
    }

    /**
     * Get the default User-Agent string to use with Guzzle.
     */
    public static function defaultUserAgent(): string
    {
        return sprintf('GuzzleHttp/%d', ClientInterface::MAJOR_VERSION);
    }

    /**
     * Returns the default cacert bundle for the current system.
     *
     * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
     * If those settings are not configured, then the common locations for
     * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
     * and Windows are checked. If any of these file locations are found on
     * disk, they will be utilized.
     *
     * Note: the result of this function is cached for subsequent calls.
     *
     * @throws \RuntimeException if no bundle can be found.
     *
     * @deprecated Utils::defaultCaBundle will be removed in guzzlehttp/guzzle:8.0. This method is not needed in PHP 5.6+.
     */
    public static function defaultCaBundle(): string
    {
        static $cached = null;
        static $cafiles = [
            // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
            '/etc/pki/tls/certs/ca-bundle.crt',
            // Ubuntu, Debian (provided by the ca-certificates package)
            '/etc/ssl/certs/ca-certificates.crt',
            // FreeBSD (provided by the ca_root_nss package)
            '/usr/local/share/certs/ca-root-nss.crt',
            // SLES 12 (provided by the ca-certificates package)
            '/var/lib/ca-certificates/ca-bundle.pem',
            // OS X provided by homebrew (using the default path)
            '/usr/local/etc/openssl/cert.pem',
            // Google app engine
            '/etc/ca-certificates.crt',
            // Windows?
            'C:\\windows\\system32\\curl-ca-bundle.crt',
            'C:\\windows\\curl-ca-bundle.crt',
        ];

        if ($cached) {
            return $cached;
        }

        if ($ca = \ini_get('openssl.cafile')) {
            return $cached = $ca;
        }

        if ($ca = \ini_get('curl.cainfo')) {
            return $cached = $ca;
        }

        foreach ($cafiles as $filename) {
            if (\file_exists($filename)) {
                return $cached = $filename;
            }
        }

        throw new \RuntimeException(
            <<< EOT
No system CA bundle could be found in any of the the common system locations.
PHP versions earlier than 5.6 are not properly configured to use the system's
CA bundle by default. In order to verify peer certificates, you will need to
supply the path on disk to a certificate bundle to the 'verify' request
option: https://docs.guzzlephp.org/en/latest/request-options.html#verify. If
you do not need a specific certificate bundle, then Mozilla provides a commonly
used CA bundle which can be downloaded here (provided by the maintainer of
cURL): https://curl.haxx.se/ca/cacert.pem. Once you have a CA bundle available
on disk, you can set the 'openssl.cafile' PHP ini setting to point to the path
to the file, allowing you to omit the 'verify' request option. See
https://curl.haxx.se/docs/sslcerts.html for more information.
EOT
        );
    }

    /**
     * Creates an associative array of lowercase header names to the actual
     * header casing.
     */
    public static function normalizeHeaderKeys(array $headers): array
    {
        $result = [];
        foreach (\array_keys($headers) as $key) {
            $result[\strtolower($key)] = $key;
        }

        return $result;
    }

    /**
     * Returns true if the provided host matches any of the no proxy areas.
     *
     * This method will strip a port from the host if it is present. Each pattern
     * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
     * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
     * "baz.foo.com", but ".foo.com" != "foo.com").
     *
     * Areas are matched in the following cases:
     * 1. "*" (without quotes) always matches any hosts.
     * 2. An exact match.
     * 3. The area starts with "." and the area is the last part of the host. e.g.
     *    '.mit.edu' will match any host that ends with '.mit.edu'.
     *
     * @param string   $host         Host to check against the patterns.
     * @param string[] $noProxyArray An array of host patterns.
     *
     * @throws InvalidArgumentException
     */
    public static function isHostInNoProxy(string $host, array $noProxyArray): bool
    {
        if (\strlen($host) === 0) {
            throw new InvalidArgumentException('Empty host provided');
        }

        // Strip port if present.
        [$host] = \explode(':', $host, 2);

        foreach ($noProxyArray as $area) {
            // Always match on wildcards.
            if ($area === '*') {
                return true;
            }

            if (empty($area)) {
                // Don't match on empty values.
                continue;
            }

            if ($area === $host) {
                // Exact matches.
                return true;
            }
            // Special match if the area when prefixed with ".". Remove any
            // existing leading "." and add a new leading ".".
            $area = '.'.\ltrim($area, '.');
            if (\substr($host, -\strlen($area)) === $area) {
                return true;
            }
        }

        return false;
    }

    /**
     * Wrapper for json_decode that throws when an error occurs.
     *
     * @param string $json    JSON data to parse
     * @param bool   $assoc   When true, returned objects will be converted
     *                        into associative arrays.
     * @param int    $depth   User specified recursion depth.
     * @param int    $options Bitmask of JSON decode options.
     *
     * @return object|array|string|int|float|bool|null
     *
     * @throws InvalidArgumentException if the JSON cannot be decoded.
     *
     * @see https://www.php.net/manual/en/function.json-decode.php
     */
    public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
    {
        $data = \json_decode($json, $assoc, $depth, $options);
        if (\JSON_ERROR_NONE !== \json_last_error()) {
            throw new InvalidArgumentException('json_decode error: '.\json_last_error_msg());
        }

        return $data;
    }

    /**
     * Wrapper for JSON encoding that throws when an error occurs.
     *
     * @param mixed $value   The value being encoded
     * @param int   $options JSON encode option bitmask
     * @param int   $depth   Set the maximum depth. Must be greater than zero.
     *
     * @throws InvalidArgumentException if the JSON cannot be encoded.
     *
     * @see https://www.php.net/manual/en/function.json-encode.php
     */
    public static function jsonEncode($value, int $options = 0, int $depth = 512): string
    {
        $json = \json_encode($value, $options, $depth);
        if (\JSON_ERROR_NONE !== \json_last_error()) {
            throw new InvalidArgumentException('json_encode error: '.\json_last_error_msg());
        }

        /** @var string */
        return $json;
    }

    /**
     * Wrapper for the hrtime() or microtime() functions
     * (depending on the PHP version, one of the two is used)
     *
     * @return float UNIX timestamp
     *
     * @internal
     */
    public static function currentTime(): float
    {
        return (float) \function_exists('hrtime') ? \hrtime(true) / 1e9 : \microtime(true);
    }

    /**
     * @throws InvalidArgumentException
     *
     * @internal
     */
    public static function idnUriConvert(UriInterface $uri, int $options = 0): UriInterface
    {
        if ($uri->getHost()) {
            $asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
            if ($asciiHost === false) {
                $errorBitSet = $info['errors'] ?? 0;

                $errorConstants = array_filter(array_keys(get_defined_constants()), static function (string $name): bool {
                    return substr($name, 0, 11) === 'IDNA_ERROR_';
                });

                $errors = [];
                foreach ($errorConstants as $errorConstant) {
                    if ($errorBitSet & constant($errorConstant)) {
                        $errors[] = $errorConstant;
                    }
                }

                $errorMessage = 'IDN conversion failed';
                if ($errors) {
                    $errorMessage .= ' (errors: '.implode(', ', $errors).')';
                }

                throw new InvalidArgumentException($errorMessage);
            }
            if ($uri->getHost() !== $asciiHost) {
                // Replace URI only if the ASCII version is different
                $uri = $uri->withHost($asciiHost);
            }
        }

        return $uri;
    }

    /**
     * @internal
     */
    public static function getenv(string $name): ?string
    {
        if (isset($_SERVER[$name])) {
            return (string) $_SERVER[$name];
        }

        if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== false && $value !== null) {
            return (string) $value;
        }

        return null;
    }

    /**
     * @return string|false
     */
    private static function idnToAsci(string $domain, int $options, ?array &$info = [])
    {
        if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) {
            return \idn_to_ascii($domain, $options, \INTL_IDNA_VARIANT_UTS46, $info);
        }

        throw new \Error('ext-idn or symfony/polyfill-intl-idn not loaded or too old');
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * Exception thrown when too many errors occur in the some() or any() methods.
 */
class AggregateException extends RejectionException
{
    public function __construct(string $msg, array $reasons)
    {
        parent::__construct(
            $reasons,
            sprintf('%s; %d rejected promises', $msg, count($reasons))
        );
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * Exception that is set as the reason for a promise that has been cancelled.
 */
class CancellationException extends RejectionException
{
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

use Generator;
use Throwable;

/**
 * Creates a promise that is resolved using a generator that yields values or
 * promises (somewhat similar to C#'s async keyword).
 *
 * When called, the Coroutine::of method will start an instance of the generator
 * and returns a promise that is fulfilled with its final yielded value.
 *
 * Control is returned back to the generator when the yielded promise settles.
 * This can lead to less verbose code when doing lots of sequential async calls
 * with minimal processing in between.
 *
 *     use GuzzleHttp\Promise;
 *
 *     function createPromise($value) {
 *         return new Promise\FulfilledPromise($value);
 *     }
 *
 *     $promise = Promise\Coroutine::of(function () {
 *         $value = (yield createPromise('a'));
 *         try {
 *             $value = (yield createPromise($value . 'b'));
 *         } catch (\Throwable $e) {
 *             // The promise was rejected.
 *         }
 *         yield $value . 'c';
 *     });
 *
 *     // Outputs "abc"
 *     $promise->then(function ($v) { echo $v; });
 *
 * @param callable $generatorFn Generator function to wrap into a promise.
 *
 * @return Promise
 *
 * @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
 */
final class Coroutine implements PromiseInterface
{
    /**
     * @var PromiseInterface|null
     */
    private $currentPromise;

    /**
     * @var Generator
     */
    private $generator;

    /**
     * @var Promise
     */
    private $result;

    public function __construct(callable $generatorFn)
    {
        $this->generator = $generatorFn();
        $this->result = new Promise(function (): void {
            while (isset($this->currentPromise)) {
                $this->currentPromise->wait();
            }
        });
        try {
            $this->nextCoroutine($this->generator->current());
        } catch (Throwable $throwable) {
            $this->result->reject($throwable);
        }
    }

    /**
     * Create a new coroutine.
     */
    public static function of(callable $generatorFn): self
    {
        return new self($generatorFn);
    }

    public function then(
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        return $this->result->then($onFulfilled, $onRejected);
    }

    public function otherwise(callable $onRejected): PromiseInterface
    {
        return $this->result->otherwise($onRejected);
    }

    public function wait(bool $unwrap = true)
    {
        return $this->result->wait($unwrap);
    }

    public function getState(): string
    {
        return $this->result->getState();
    }

    public function resolve($value): void
    {
        $this->result->resolve($value);
    }

    public function reject($reason): void
    {
        $this->result->reject($reason);
    }

    public function cancel(): void
    {
        $this->currentPromise->cancel();
        $this->result->cancel();
    }

    private function nextCoroutine($yielded): void
    {
        $this->currentPromise = Create::promiseFor($yielded)
            ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
    }

    /**
     * @internal
     */
    public function _handleSuccess($value): void
    {
        unset($this->currentPromise);
        try {
            $next = $this->generator->send($value);
            if ($this->generator->valid()) {
                $this->nextCoroutine($next);
            } else {
                $this->result->resolve($value);
            }
        } catch (Throwable $throwable) {
            $this->result->reject($throwable);
        }
    }

    /**
     * @internal
     */
    public function _handleFailure($reason): void
    {
        unset($this->currentPromise);
        try {
            $nextYield = $this->generator->throw(Create::exceptionFor($reason));
            // The throw was caught, so keep iterating on the coroutine
            $this->nextCoroutine($nextYield);
        } catch (Throwable $throwable) {
            $this->result->reject($throwable);
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

final class Create
{
    /**
     * Creates a promise for a value if the value is not a promise.
     *
     * @param mixed $value Promise or value.
     */
    public static function promiseFor($value): PromiseInterface
    {
        if ($value instanceof PromiseInterface) {
            return $value;
        }

        // Return a Guzzle promise that shadows the given promise.
        if (is_object($value) && method_exists($value, 'then')) {
            $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
            $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
            $promise = new Promise($wfn, $cfn);
            $value->then([$promise, 'resolve'], [$promise, 'reject']);

            return $promise;
        }

        return new FulfilledPromise($value);
    }

    /**
     * Creates a rejected promise for a reason if the reason is not a promise.
     * If the provided reason is a promise, then it is returned as-is.
     *
     * @param mixed $reason Promise or reason.
     */
    public static function rejectionFor($reason): PromiseInterface
    {
        if ($reason instanceof PromiseInterface) {
            return $reason;
        }

        return new RejectedPromise($reason);
    }

    /**
     * Create an exception for a rejected promise value.
     *
     * @param mixed $reason
     */
    public static function exceptionFor($reason): \Throwable
    {
        if ($reason instanceof \Throwable) {
            return $reason;
        }

        return new RejectionException($reason);
    }

    /**
     * Returns an iterator for the given value.
     *
     * @param mixed $value
     */
    public static function iterFor($value): \Iterator
    {
        if ($value instanceof \Iterator) {
            return $value;
        }

        if (is_array($value)) {
            return new \ArrayIterator($value);
        }

        return new \ArrayIterator([$value]);
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

final class Each
{
    /**
     * Given an iterator that yields promises or values, returns a promise that
     * is fulfilled with a null value when the iterator has been consumed or
     * the aggregate promise has been fulfilled or rejected.
     *
     * $onFulfilled is a function that accepts the fulfilled value, iterator
     * index, and the aggregate promise. The callback can invoke any necessary
     * side effects and choose to resolve or reject the aggregate if needed.
     *
     * $onRejected is a function that accepts the rejection reason, iterator
     * index, and the aggregate promise. The callback can invoke any necessary
     * side effects and choose to resolve or reject the aggregate if needed.
     *
     * @param mixed $iterable Iterator or array to iterate over.
     */
    public static function of(
        $iterable,
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        return (new EachPromise($iterable, [
            'fulfilled' => $onFulfilled,
            'rejected' => $onRejected,
        ]))->promise();
    }

    /**
     * Like of, but only allows a certain number of outstanding promises at any
     * given time.
     *
     * $concurrency may be an integer or a function that accepts the number of
     * pending promises and returns a numeric concurrency limit value to allow
     * for dynamic a concurrency size.
     *
     * @param mixed        $iterable
     * @param int|callable $concurrency
     */
    public static function ofLimit(
        $iterable,
        $concurrency,
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        return (new EachPromise($iterable, [
            'fulfilled' => $onFulfilled,
            'rejected' => $onRejected,
            'concurrency' => $concurrency,
        ]))->promise();
    }

    /**
     * Like limit, but ensures that no promise in the given $iterable argument
     * is rejected. If any promise is rejected, then the aggregate promise is
     * rejected with the encountered rejection.
     *
     * @param mixed        $iterable
     * @param int|callable $concurrency
     */
    public static function ofLimitAll(
        $iterable,
        $concurrency,
        ?callable $onFulfilled = null
    ): PromiseInterface {
        return self::ofLimit(
            $iterable,
            $concurrency,
            $onFulfilled,
            function ($reason, $idx, PromiseInterface $aggregate): void {
                $aggregate->reject($reason);
            }
        );
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * Represents a promise that iterates over many promises and invokes
 * side-effect functions in the process.
 *
 * @final
 */
class EachPromise implements PromisorInterface
{
    private $pending = [];

    private $nextPendingIndex = 0;

    /** @var \Iterator|null */
    private $iterable;

    /** @var callable|int|null */
    private $concurrency;

    /** @var callable|null */
    private $onFulfilled;

    /** @var callable|null */
    private $onRejected;

    /** @var Promise|null */
    private $aggregate;

    /** @var bool|null */
    private $mutex;

    /**
     * Configuration hash can include the following key value pairs:
     *
     * - fulfilled: (callable) Invoked when a promise fulfills. The function
     *   is invoked with three arguments: the fulfillment value, the index
     *   position from the iterable list of the promise, and the aggregate
     *   promise that manages all of the promises. The aggregate promise may
     *   be resolved from within the callback to short-circuit the promise.
     * - rejected: (callable) Invoked when a promise is rejected. The
     *   function is invoked with three arguments: the rejection reason, the
     *   index position from the iterable list of the promise, and the
     *   aggregate promise that manages all of the promises. The aggregate
     *   promise may be resolved from within the callback to short-circuit
     *   the promise.
     * - concurrency: (integer) Pass this configuration option to limit the
     *   allowed number of outstanding concurrently executing promises,
     *   creating a capped pool of promises. There is no limit by default.
     *
     * @param mixed $iterable Promises or values to iterate.
     * @param array $config   Configuration options
     */
    public function __construct($iterable, array $config = [])
    {
        $this->iterable = Create::iterFor($iterable);

        if (isset($config['concurrency'])) {
            $this->concurrency = $config['concurrency'];
        }

        if (isset($config['fulfilled'])) {
            $this->onFulfilled = $config['fulfilled'];
        }

        if (isset($config['rejected'])) {
            $this->onRejected = $config['rejected'];
        }
    }

    /** @psalm-suppress InvalidNullableReturnType */
    public function promise(): PromiseInterface
    {
        if ($this->aggregate) {
            return $this->aggregate;
        }

        try {
            $this->createPromise();
            /** @psalm-assert Promise $this->aggregate */
            $this->iterable->rewind();
            $this->refillPending();
        } catch (\Throwable $e) {
            $this->aggregate->reject($e);
        }

        /**
         * @psalm-suppress NullableReturnStatement
         */
        return $this->aggregate;
    }

    private function createPromise(): void
    {
        $this->mutex = false;
        $this->aggregate = new Promise(function (): void {
            if ($this->checkIfFinished()) {
                return;
            }
            reset($this->pending);
            // Consume a potentially fluctuating list of promises while
            // ensuring that indexes are maintained (precluding array_shift).
            while ($promise = current($this->pending)) {
                next($this->pending);
                $promise->wait();
                if (Is::settled($this->aggregate)) {
                    return;
                }
            }
        });

        // Clear the references when the promise is resolved.
        $clearFn = function (): void {
            $this->iterable = $this->concurrency = $this->pending = null;
            $this->onFulfilled = $this->onRejected = null;
            $this->nextPendingIndex = 0;
        };

        $this->aggregate->then($clearFn, $clearFn);
    }

    private function refillPending(): void
    {
        if (!$this->concurrency) {
            // Add all pending promises.
            while ($this->addPending() && $this->advanceIterator()) {
            }

            return;
        }

        // Add only up to N pending promises.
        $concurrency = is_callable($this->concurrency)
            ? ($this->concurrency)(count($this->pending))
            : $this->concurrency;
        $concurrency = max($concurrency - count($this->pending), 0);
        // Concurrency may be set to 0 to disallow new promises.
        if (!$concurrency) {
            return;
        }
        // Add the first pending promise.
        $this->addPending();
        // Note this is special handling for concurrency=1 so that we do
        // not advance the iterator after adding the first promise. This
        // helps work around issues with generators that might not have the
        // next value to yield until promise callbacks are called.
        while (--$concurrency
            && $this->advanceIterator()
            && $this->addPending()) {
        }
    }

    private function addPending(): bool
    {
        if (!$this->iterable || !$this->iterable->valid()) {
            return false;
        }

        $promise = Create::promiseFor($this->iterable->current());
        $key = $this->iterable->key();

        // Iterable keys may not be unique, so we use a counter to
        // guarantee uniqueness
        $idx = $this->nextPendingIndex++;

        $this->pending[$idx] = $promise->then(
            function ($value) use ($idx, $key): void {
                if ($this->onFulfilled) {
                    ($this->onFulfilled)(
                        $value,
                        $key,
                        $this->aggregate
                    );
                }
                $this->step($idx);
            },
            function ($reason) use ($idx, $key): void {
                if ($this->onRejected) {
                    ($this->onRejected)(
                        $reason,
                        $key,
                        $this->aggregate
                    );
                }
                $this->step($idx);
            }
        );

        return true;
    }

    private function advanceIterator(): bool
    {
        // Place a lock on the iterator so that we ensure to not recurse,
        // preventing fatal generator errors.
        if ($this->mutex) {
            return false;
        }

        $this->mutex = true;

        try {
            $this->iterable->next();
            $this->mutex = false;

            return true;
        } catch (\Throwable $e) {
            $this->aggregate->reject($e);
            $this->mutex = false;

            return false;
        }
    }

    private function step(int $idx): void
    {
        // If the promise was already resolved, then ignore this step.
        if (Is::settled($this->aggregate)) {
            return;
        }

        unset($this->pending[$idx]);

        // Only refill pending promises if we are not locked, preventing the
        // EachPromise to recursively invoke the provided iterator, which
        // cause a fatal error: "Cannot resume an already running generator"
        if ($this->advanceIterator() && !$this->checkIfFinished()) {
            // Add more pending promises if possible.
            $this->refillPending();
        }
    }

    private function checkIfFinished(): bool
    {
        if (!$this->pending && !$this->iterable->valid()) {
            // Resolve the promise if there's nothing left to do.
            $this->aggregate->resolve(null);

            return true;
        }

        return false;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * A promise that has been fulfilled.
 *
 * Thenning off of this promise will invoke the onFulfilled callback
 * immediately and ignore other callbacks.
 *
 * @final
 */
class FulfilledPromise implements PromiseInterface
{
    private $value;

    /**
     * @param mixed $value
     */
    public function __construct($value)
    {
        if (is_object($value) && method_exists($value, 'then')) {
            throw new \InvalidArgumentException(
                'You cannot create a FulfilledPromise with a promise.'
            );
        }

        $this->value = $value;
    }

    public function then(
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        // Return itself if there is no onFulfilled function.
        if (!$onFulfilled) {
            return $this;
        }

        $queue = Utils::queue();
        $p = new Promise([$queue, 'run']);
        $value = $this->value;
        $queue->add(static function () use ($p, $value, $onFulfilled): void {
            if (Is::pending($p)) {
                try {
                    $p->resolve($onFulfilled($value));
                } catch (\Throwable $e) {
                    $p->reject($e);
                }
            }
        });

        return $p;
    }

    public function otherwise(callable $onRejected): PromiseInterface
    {
        return $this->then(null, $onRejected);
    }

    public function wait(bool $unwrap = true)
    {
        return $unwrap ? $this->value : null;
    }

    public function getState(): string
    {
        return self::FULFILLED;
    }

    public function resolve($value): void
    {
        if ($value !== $this->value) {
            throw new \LogicException('Cannot resolve a fulfilled promise');
        }
    }

    public function reject($reason): void
    {
        throw new \LogicException('Cannot reject a fulfilled promise');
    }

    public function cancel(): void
    {
        // pass
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

final class Is
{
    /**
     * Returns true if a promise is pending.
     */
    public static function pending(PromiseInterface $promise): bool
    {
        return $promise->getState() === PromiseInterface::PENDING;
    }

    /**
     * Returns true if a promise is fulfilled or rejected.
     */
    public static function settled(PromiseInterface $promise): bool
    {
        return $promise->getState() !== PromiseInterface::PENDING;
    }

    /**
     * Returns true if a promise is fulfilled.
     */
    public static function fulfilled(PromiseInterface $promise): bool
    {
        return $promise->getState() === PromiseInterface::FULFILLED;
    }

    /**
     * Returns true if a promise is rejected.
     */
    public static function rejected(PromiseInterface $promise): bool
    {
        return $promise->getState() === PromiseInterface::REJECTED;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * Promises/A+ implementation that avoids recursion when possible.
 *
 * @see https://promisesaplus.com/
 *
 * @final
 */
class Promise implements PromiseInterface
{
    private $state = self::PENDING;
    private $result;
    private $cancelFn;
    private $waitFn;
    private $waitList;
    private $handlers = [];

    /**
     * @param callable $waitFn   Fn that when invoked resolves the promise.
     * @param callable $cancelFn Fn that when invoked cancels the promise.
     */
    public function __construct(
        ?callable $waitFn = null,
        ?callable $cancelFn = null
    ) {
        $this->waitFn = $waitFn;
        $this->cancelFn = $cancelFn;
    }

    public function then(
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        if ($this->state === self::PENDING) {
            $p = new Promise(null, [$this, 'cancel']);
            $this->handlers[] = [$p, $onFulfilled, $onRejected];
            $p->waitList = $this->waitList;
            $p->waitList[] = $this;

            return $p;
        }

        // Return a fulfilled promise and immediately invoke any callbacks.
        if ($this->state === self::FULFILLED) {
            $promise = Create::promiseFor($this->result);

            return $onFulfilled ? $promise->then($onFulfilled) : $promise;
        }

        // It's either cancelled or rejected, so return a rejected promise
        // and immediately invoke any callbacks.
        $rejection = Create::rejectionFor($this->result);

        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
    }

    public function otherwise(callable $onRejected): PromiseInterface
    {
        return $this->then(null, $onRejected);
    }

    public function wait(bool $unwrap = true)
    {
        $this->waitIfPending();

        if ($this->result instanceof PromiseInterface) {
            return $this->result->wait($unwrap);
        }
        if ($unwrap) {
            if ($this->state === self::FULFILLED) {
                return $this->result;
            }
            // It's rejected so "unwrap" and throw an exception.
            throw Create::exceptionFor($this->result);
        }
    }

    public function getState(): string
    {
        return $this->state;
    }

    public function cancel(): void
    {
        if ($this->state !== self::PENDING) {
            return;
        }

        $this->waitFn = $this->waitList = null;

        if ($this->cancelFn) {
            $fn = $this->cancelFn;
            $this->cancelFn = null;
            try {
                $fn();
            } catch (\Throwable $e) {
                $this->reject($e);
            }
        }

        // Reject the promise only if it wasn't rejected in a then callback.
        /** @psalm-suppress RedundantCondition */
        if ($this->state === self::PENDING) {
            $this->reject(new CancellationException('Promise has been cancelled'));
        }
    }

    public function resolve($value): void
    {
        $this->settle(self::FULFILLED, $value);
    }

    public function reject($reason): void
    {
        $this->settle(self::REJECTED, $reason);
    }

    private function settle(string $state, $value): void
    {
        if ($this->state !== self::PENDING) {
            // Ignore calls with the same resolution.
            if ($state === $this->state && $value === $this->result) {
                return;
            }
            throw $this->state === $state
                ? new \LogicException("The promise is already {$state}.")
                : new \LogicException("Cannot change a {$this->state} promise to {$state}");
        }

        if ($value === $this) {
            throw new \LogicException('Cannot fulfill or reject a promise with itself');
        }

        // Clear out the state of the promise but stash the handlers.
        $this->state = $state;
        $this->result = $value;
        $handlers = $this->handlers;
        $this->handlers = null;
        $this->waitList = $this->waitFn = null;
        $this->cancelFn = null;

        if (!$handlers) {
            return;
        }

        // If the value was not a settled promise or a thenable, then resolve
        // it in the task queue using the correct ID.
        if (!is_object($value) || !method_exists($value, 'then')) {
            $id = $state === self::FULFILLED ? 1 : 2;
            // It's a success, so resolve the handlers in the queue.
            Utils::queue()->add(static function () use ($id, $value, $handlers): void {
                foreach ($handlers as $handler) {
                    self::callHandler($id, $value, $handler);
                }
            });
        } elseif ($value instanceof Promise && Is::pending($value)) {
            // We can just merge our handlers onto the next promise.
            $value->handlers = array_merge($value->handlers, $handlers);
        } else {
            // Resolve the handlers when the forwarded promise is resolved.
            $value->then(
                static function ($value) use ($handlers): void {
                    foreach ($handlers as $handler) {
                        self::callHandler(1, $value, $handler);
                    }
                },
                static function ($reason) use ($handlers): void {
                    foreach ($handlers as $handler) {
                        self::callHandler(2, $reason, $handler);
                    }
                }
            );
        }
    }

    /**
     * Call a stack of handlers using a specific callback index and value.
     *
     * @param int   $index   1 (resolve) or 2 (reject).
     * @param mixed $value   Value to pass to the callback.
     * @param array $handler Array of handler data (promise and callbacks).
     */
    private static function callHandler(int $index, $value, array $handler): void
    {
        /** @var PromiseInterface $promise */
        $promise = $handler[0];

        // The promise may have been cancelled or resolved before placing
        // this thunk in the queue.
        if (Is::settled($promise)) {
            return;
        }

        try {
            if (isset($handler[$index])) {
                /*
                 * If $f throws an exception, then $handler will be in the exception
                 * stack trace. Since $handler contains a reference to the callable
                 * itself we get a circular reference. We clear the $handler
                 * here to avoid that memory leak.
                 */
                $f = $handler[$index];
                unset($handler);
                $promise->resolve($f($value));
            } elseif ($index === 1) {
                // Forward resolution values as-is.
                $promise->resolve($value);
            } else {
                // Forward rejections down the chain.
                $promise->reject($value);
            }
        } catch (\Throwable $reason) {
            $promise->reject($reason);
        }
    }

    private function waitIfPending(): void
    {
        if ($this->state !== self::PENDING) {
            return;
        } elseif ($this->waitFn) {
            $this->invokeWaitFn();
        } elseif ($this->waitList) {
            $this->invokeWaitList();
        } else {
            // If there's no wait function, then reject the promise.
            $this->reject('Cannot wait on a promise that has '
                .'no internal wait function. You must provide a wait '
                .'function when constructing the promise to be able to '
                .'wait on a promise.');
        }

        Utils::queue()->run();

        /** @psalm-suppress RedundantCondition */
        if ($this->state === self::PENDING) {
            $this->reject('Invoking the wait callback did not resolve the promise');
        }
    }

    private function invokeWaitFn(): void
    {
        try {
            $wfn = $this->waitFn;
            $this->waitFn = null;
            $wfn(true);
        } catch (\Throwable $reason) {
            if ($this->state === self::PENDING) {
                // The promise has not been resolved yet, so reject the promise
                // with the exception.
                $this->reject($reason);
            } else {
                // The promise was already resolved, so there's a problem in
                // the application.
                throw $reason;
            }
        }
    }

    private function invokeWaitList(): void
    {
        $waitList = $this->waitList;
        $this->waitList = null;

        foreach ($waitList as $result) {
            do {
                $result->waitIfPending();
                $result = $result->result;
            } while ($result instanceof Promise);

            if ($result instanceof PromiseInterface) {
                $result->wait(false);
            }
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * A promise represents the eventual result of an asynchronous operation.
 *
 * The primary way of interacting with a promise is through its then method,
 * which registers callbacks to receive either a promise’s eventual value or
 * the reason why the promise cannot be fulfilled.
 *
 * @see https://promisesaplus.com/
 */
interface PromiseInterface
{
    public const PENDING = 'pending';
    public const FULFILLED = 'fulfilled';
    public const REJECTED = 'rejected';

    /**
     * Appends fulfillment and rejection handlers to the promise, and returns
     * a new promise resolving to the return value of the called handler.
     *
     * @param callable $onFulfilled Invoked when the promise fulfills.
     * @param callable $onRejected  Invoked when the promise is rejected.
     */
    public function then(
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface;

    /**
     * Appends a rejection handler callback to the promise, and returns a new
     * promise resolving to the return value of the callback if it is called,
     * or to its original fulfillment value if the promise is instead
     * fulfilled.
     *
     * @param callable $onRejected Invoked when the promise is rejected.
     */
    public function otherwise(callable $onRejected): PromiseInterface;

    /**
     * Get the state of the promise ("pending", "rejected", or "fulfilled").
     *
     * The three states can be checked against the constants defined on
     * PromiseInterface: PENDING, FULFILLED, and REJECTED.
     */
    public function getState(): string;

    /**
     * Resolve the promise with the given value.
     *
     * @param mixed $value
     *
     * @throws \RuntimeException if the promise is already resolved.
     */
    public function resolve($value): void;

    /**
     * Reject the promise with the given reason.
     *
     * @param mixed $reason
     *
     * @throws \RuntimeException if the promise is already resolved.
     */
    public function reject($reason): void;

    /**
     * Cancels the promise if possible.
     *
     * @see https://github.com/promises-aplus/cancellation-spec/issues/7
     */
    public function cancel(): void;

    /**
     * Waits until the promise completes if possible.
     *
     * Pass $unwrap as true to unwrap the result of the promise, either
     * returning the resolved value or throwing the rejected exception.
     *
     * If the promise cannot be waited on, then the promise will be rejected.
     *
     * @return mixed
     *
     * @throws \LogicException if the promise has no wait function or if the
     *                         promise does not settle after waiting.
     */
    public function wait(bool $unwrap = true);
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * Interface used with classes that return a promise.
 */
interface PromisorInterface
{
    /**
     * Returns a promise.
     */
    public function promise(): PromiseInterface;
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * A promise that has been rejected.
 *
 * Thenning off of this promise will invoke the onRejected callback
 * immediately and ignore other callbacks.
 *
 * @final
 */
class RejectedPromise implements PromiseInterface
{
    private $reason;

    /**
     * @param mixed $reason
     */
    public function __construct($reason)
    {
        if (is_object($reason) && method_exists($reason, 'then')) {
            throw new \InvalidArgumentException(
                'You cannot create a RejectedPromise with a promise.'
            );
        }

        $this->reason = $reason;
    }

    public function then(
        ?callable $onFulfilled = null,
        ?callable $onRejected = null
    ): PromiseInterface {
        // If there's no onRejected callback then just return self.
        if (!$onRejected) {
            return $this;
        }

        $queue = Utils::queue();
        $reason = $this->reason;
        $p = new Promise([$queue, 'run']);
        $queue->add(static function () use ($p, $reason, $onRejected): void {
            if (Is::pending($p)) {
                try {
                    // Return a resolved promise if onRejected does not throw.
                    $p->resolve($onRejected($reason));
                } catch (\Throwable $e) {
                    // onRejected threw, so return a rejected promise.
                    $p->reject($e);
                }
            }
        });

        return $p;
    }

    public function otherwise(callable $onRejected): PromiseInterface
    {
        return $this->then(null, $onRejected);
    }

    public function wait(bool $unwrap = true)
    {
        if ($unwrap) {
            throw Create::exceptionFor($this->reason);
        }

        return null;
    }

    public function getState(): string
    {
        return self::REJECTED;
    }

    public function resolve($value): void
    {
        throw new \LogicException('Cannot resolve a rejected promise');
    }

    public function reject($reason): void
    {
        if ($reason !== $this->reason) {
            throw new \LogicException('Cannot reject a rejected promise');
        }
    }

    public function cancel(): void
    {
        // pass
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * A special exception that is thrown when waiting on a rejected promise.
 *
 * The reason value is available via the getReason() method.
 */
class RejectionException extends \RuntimeException
{
    /** @var mixed Rejection reason. */
    private $reason;

    /**
     * @param mixed       $reason      Rejection reason.
     * @param string|null $description Optional description.
     */
    public function __construct($reason, ?string $description = null)
    {
        $this->reason = $reason;

        $message = 'The promise was rejected';

        if ($description) {
            $message .= ' with reason: '.$description;
        } elseif (is_string($reason)
            || (is_object($reason) && method_exists($reason, '__toString'))
        ) {
            $message .= ' with reason: '.$this->reason;
        } elseif ($reason instanceof \JsonSerializable) {
            $message .= ' with reason: '.json_encode($this->reason, JSON_PRETTY_PRINT);
        }

        parent::__construct($message);
    }

    /**
     * Returns the rejection reason.
     *
     * @return mixed
     */
    public function getReason()
    {
        return $this->reason;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

/**
 * A task queue that executes tasks in a FIFO order.
 *
 * This task queue class is used to settle promises asynchronously and
 * maintains a constant stack size. You can use the task queue asynchronously
 * by calling the `run()` function of the global task queue in an event loop.
 *
 *     GuzzleHttp\Promise\Utils::queue()->run();
 *
 * @final
 */
class TaskQueue implements TaskQueueInterface
{
    private $enableShutdown = true;
    private $queue = [];

    public function __construct(bool $withShutdown = true)
    {
        if ($withShutdown) {
            register_shutdown_function(function (): void {
                if ($this->enableShutdown) {
                    // Only run the tasks if an E_ERROR didn't occur.
                    $err = error_get_last();
                    if (!$err || ($err['type'] ^ E_ERROR)) {
                        $this->run();
                    }
                }
            });
        }
    }

    public function isEmpty(): bool
    {
        return !$this->queue;
    }

    public function add(callable $task): void
    {
        $this->queue[] = $task;
    }

    public function run(): void
    {
        while ($task = array_shift($this->queue)) {
            /** @var callable $task */
            $task();
        }
    }

    /**
     * The task queue will be run and exhausted by default when the process
     * exits IFF the exit is not the result of a PHP E_ERROR error.
     *
     * You can disable running the automatic shutdown of the queue by calling
     * this function. If you disable the task queue shutdown process, then you
     * MUST either run the task queue (as a result of running your event loop
     * or manually using the run() method) or wait on each outstanding promise.
     *
     * Note: This shutdown will occur before any destructors are triggered.
     */
    public function disableShutdown(): void
    {
        $this->enableShutdown = false;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

interface TaskQueueInterface
{
    /**
     * Returns true if the queue is empty.
     */
    public function isEmpty(): bool;

    /**
     * Adds a task to the queue that will be executed the next time run is
     * called.
     */
    public function add(callable $task): void;

    /**
     * Execute all of the pending task in the queue.
     */
    public function run(): void;
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Promise;

final class Utils
{
    /**
     * Get the global task queue used for promise resolution.
     *
     * This task queue MUST be run in an event loop in order for promises to be
     * settled asynchronously. It will be automatically run when synchronously
     * waiting on a promise.
     *
     * <code>
     * while ($eventLoop->isRunning()) {
     *     GuzzleHttp\Promise\Utils::queue()->run();
     * }
     * </code>
     *
     * @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
     */
    public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
    {
        static $queue;

        if ($assign) {
            $queue = $assign;
        } elseif (!$queue) {
            $queue = new TaskQueue();
        }

        return $queue;
    }

    /**
     * Adds a function to run in the task queue when it is next `run()` and
     * returns a promise that is fulfilled or rejected with the result.
     *
     * @param callable $task Task function to run.
     */
    public static function task(callable $task): PromiseInterface
    {
        $queue = self::queue();
        $promise = new Promise([$queue, 'run']);
        $queue->add(function () use ($task, $promise): void {
            try {
                if (Is::pending($promise)) {
                    $promise->resolve($task());
                }
            } catch (\Throwable $e) {
                $promise->reject($e);
            }
        });

        return $promise;
    }

    /**
     * Synchronously waits on a promise to resolve and returns an inspection
     * state array.
     *
     * Returns a state associative array containing a "state" key mapping to a
     * valid promise state. If the state of the promise is "fulfilled", the
     * array will contain a "value" key mapping to the fulfilled value of the
     * promise. If the promise is rejected, the array will contain a "reason"
     * key mapping to the rejection reason of the promise.
     *
     * @param PromiseInterface $promise Promise or value.
     */
    public static function inspect(PromiseInterface $promise): array
    {
        try {
            return [
                'state' => PromiseInterface::FULFILLED,
                'value' => $promise->wait(),
            ];
        } catch (RejectionException $e) {
            return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
        } catch (\Throwable $e) {
            return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
        }
    }

    /**
     * Waits on all of the provided promises, but does not unwrap rejected
     * promises as thrown exception.
     *
     * Returns an array of inspection state arrays.
     *
     * @see inspect for the inspection state array format.
     *
     * @param PromiseInterface[] $promises Traversable of promises to wait upon.
     */
    public static function inspectAll($promises): array
    {
        $results = [];
        foreach ($promises as $key => $promise) {
            $results[$key] = self::inspect($promise);
        }

        return $results;
    }

    /**
     * Waits on all of the provided promises and returns the fulfilled values.
     *
     * Returns an array that contains the value of each promise (in the same
     * order the promises were provided). An exception is thrown if any of the
     * promises are rejected.
     *
     * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
     *
     * @throws \Throwable on error
     */
    public static function unwrap($promises): array
    {
        $results = [];
        foreach ($promises as $key => $promise) {
            $results[$key] = $promise->wait();
        }

        return $results;
    }

    /**
     * Given an array of promises, return a promise that is fulfilled when all
     * the items in the array are fulfilled.
     *
     * The promise's fulfillment value is an array with fulfillment values at
     * respective positions to the original array. If any promise in the array
     * rejects, the returned promise is rejected with the rejection reason.
     *
     * @param mixed $promises  Promises or values.
     * @param bool  $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
     */
    public static function all($promises, bool $recursive = false): PromiseInterface
    {
        $results = [];
        $promise = Each::of(
            $promises,
            function ($value, $idx) use (&$results): void {
                $results[$idx] = $value;
            },
            function ($reason, $idx, Promise $aggregate): void {
                if (Is::pending($aggregate)) {
                    $aggregate->reject($reason);
                }
            }
        )->then(function () use (&$results) {
            ksort($results);

            return $results;
        });

        if (true === $recursive) {
            $promise = $promise->then(function ($results) use ($recursive, &$promises) {
                foreach ($promises as $promise) {
                    if (Is::pending($promise)) {
                        return self::all($promises, $recursive);
                    }
                }

                return $results;
            });
        }

        return $promise;
    }

    /**
     * Initiate a competitive race between multiple promises or values (values
     * will become immediately fulfilled promises).
     *
     * When count amount of promises have been fulfilled, the returned promise
     * is fulfilled with an array that contains the fulfillment values of the
     * winners in order of resolution.
     *
     * This promise is rejected with a {@see AggregateException} if the number
     * of fulfilled promises is less than the desired $count.
     *
     * @param int   $count    Total number of promises.
     * @param mixed $promises Promises or values.
     */
    public static function some(int $count, $promises): PromiseInterface
    {
        $results = [];
        $rejections = [];

        return Each::of(
            $promises,
            function ($value, $idx, PromiseInterface $p) use (&$results, $count): void {
                if (Is::settled($p)) {
                    return;
                }
                $results[$idx] = $value;
                if (count($results) >= $count) {
                    $p->resolve(null);
                }
            },
            function ($reason) use (&$rejections): void {
                $rejections[] = $reason;
            }
        )->then(
            function () use (&$results, &$rejections, $count) {
                if (count($results) !== $count) {
                    throw new AggregateException(
                        'Not enough promises to fulfill count',
                        $rejections
                    );
                }
                ksort($results);

                return array_values($results);
            }
        );
    }

    /**
     * Like some(), with 1 as count. However, if the promise fulfills, the
     * fulfillment value is not an array of 1 but the value directly.
     *
     * @param mixed $promises Promises or values.
     */
    public static function any($promises): PromiseInterface
    {
        return self::some(1, $promises)->then(function ($values) {
            return $values[0];
        });
    }

    /**
     * Returns a promise that is fulfilled when all of the provided promises have
     * been fulfilled or rejected.
     *
     * The returned promise is fulfilled with an array of inspection state arrays.
     *
     * @see inspect for the inspection state array format.
     *
     * @param mixed $promises Promises or values.
     */
    public static function settle($promises): PromiseInterface
    {
        $results = [];

        return Each::of(
            $promises,
            function ($value, $idx) use (&$results): void {
                $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
            },
            function ($reason, $idx) use (&$results): void {
                $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
            }
        )->then(function () use (&$results) {
            ksort($results);

            return $results;
        });
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Reads from multiple streams, one after the other.
 *
 * This is a read-only stream decorator.
 */
final class AppendStream implements StreamInterface
{
    /** @var StreamInterface[] Streams being decorated */
    private $streams = [];

    /** @var bool */
    private $seekable = true;

    /** @var int */
    private $current = 0;

    /** @var int */
    private $pos = 0;

    /**
     * @param StreamInterface[] $streams Streams to decorate. Each stream must
     *                                   be readable.
     */
    public function __construct(array $streams = [])
    {
        foreach ($streams as $stream) {
            $this->addStream($stream);
        }
    }

    public function __toString(): string
    {
        try {
            $this->rewind();

            return $this->getContents();
        } catch (\Throwable $e) {
            if (\PHP_VERSION_ID >= 70400) {
                throw $e;
            }
            trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);

            return '';
        }
    }

    /**
     * Add a stream to the AppendStream
     *
     * @param StreamInterface $stream Stream to append. Must be readable.
     *
     * @throws \InvalidArgumentException if the stream is not readable
     */
    public function addStream(StreamInterface $stream): void
    {
        if (!$stream->isReadable()) {
            throw new \InvalidArgumentException('Each stream must be readable');
        }

        // The stream is only seekable if all streams are seekable
        if (!$stream->isSeekable()) {
            $this->seekable = false;
        }

        $this->streams[] = $stream;
    }

    public function getContents(): string
    {
        return Utils::copyToString($this);
    }

    /**
     * Closes each attached stream.
     */
    public function close(): void
    {
        $this->pos = $this->current = 0;
        $this->seekable = true;

        foreach ($this->streams as $stream) {
            $stream->close();
        }

        $this->streams = [];
    }

    /**
     * Detaches each attached stream.
     *
     * Returns null as it's not clear which underlying stream resource to return.
     */
    public function detach()
    {
        $this->pos = $this->current = 0;
        $this->seekable = true;

        foreach ($this->streams as $stream) {
            $stream->detach();
        }

        $this->streams = [];

        return null;
    }

    public function tell(): int
    {
        return $this->pos;
    }

    /**
     * Tries to calculate the size by adding the size of each stream.
     *
     * If any of the streams do not return a valid number, then the size of the
     * append stream cannot be determined and null is returned.
     */
    public function getSize(): ?int
    {
        $size = 0;

        foreach ($this->streams as $stream) {
            $s = $stream->getSize();
            if ($s === null) {
                return null;
            }
            $size += $s;
        }

        return $size;
    }

    public function eof(): bool
    {
        return !$this->streams
            || ($this->current >= count($this->streams) - 1
             && $this->streams[$this->current]->eof());
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    /**
     * Attempts to seek to the given position. Only supports SEEK_SET.
     */
    public function seek($offset, $whence = SEEK_SET): void
    {
        if (!$this->seekable) {
            throw new \RuntimeException('This AppendStream is not seekable');
        } elseif ($whence !== SEEK_SET) {
            throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
        }

        $this->pos = $this->current = 0;

        // Rewind each stream
        foreach ($this->streams as $i => $stream) {
            try {
                $stream->rewind();
            } catch (\Exception $e) {
                throw new \RuntimeException('Unable to seek stream '
                    .$i.' of the AppendStream', 0, $e);
            }
        }

        // Seek to the actual position by reading from each stream
        while ($this->pos < $offset && !$this->eof()) {
            $result = $this->read(min(8096, $offset - $this->pos));
            if ($result === '') {
                break;
            }
        }
    }

    /**
     * Reads from all of the appended streams until the length is met or EOF.
     */
    public function read($length): string
    {
        $buffer = '';
        $total = count($this->streams) - 1;
        $remaining = $length;
        $progressToNext = false;

        while ($remaining > 0) {
            // Progress to the next stream if needed.
            if ($progressToNext || $this->streams[$this->current]->eof()) {
                $progressToNext = false;
                if ($this->current === $total) {
                    break;
                }
                ++$this->current;
            }

            $result = $this->streams[$this->current]->read($remaining);

            if ($result === '') {
                $progressToNext = true;
                continue;
            }

            $buffer .= $result;
            $remaining = $length - strlen($buffer);
        }

        $this->pos += strlen($buffer);

        return $buffer;
    }

    public function isReadable(): bool
    {
        return true;
    }

    public function isWritable(): bool
    {
        return false;
    }

    public function isSeekable(): bool
    {
        return $this->seekable;
    }

    public function write($string): int
    {
        throw new \RuntimeException('Cannot write to an AppendStream');
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        return $key ? null : [];
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Provides a buffer stream that can be written to to fill a buffer, and read
 * from to remove bytes from the buffer.
 *
 * This stream returns a "hwm" metadata value that tells upstream consumers
 * what the configured high water mark of the stream is, or the maximum
 * preferred size of the buffer.
 */
final class BufferStream implements StreamInterface
{
    /** @var int */
    private $hwm;

    /** @var string */
    private $buffer = '';

    /**
     * @param int $hwm High water mark, representing the preferred maximum
     *                 buffer size. If the size of the buffer exceeds the high
     *                 water mark, then calls to write will continue to succeed
     *                 but will return 0 to inform writers to slow down
     *                 until the buffer has been drained by reading from it.
     */
    public function __construct(int $hwm = 16384)
    {
        $this->hwm = $hwm;
    }

    public function __toString(): string
    {
        return $this->getContents();
    }

    public function getContents(): string
    {
        $buffer = $this->buffer;
        $this->buffer = '';

        return $buffer;
    }

    public function close(): void
    {
        $this->buffer = '';
    }

    public function detach()
    {
        $this->close();

        return null;
    }

    public function getSize(): ?int
    {
        return strlen($this->buffer);
    }

    public function isReadable(): bool
    {
        return true;
    }

    public function isWritable(): bool
    {
        return true;
    }

    public function isSeekable(): bool
    {
        return false;
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        throw new \RuntimeException('Cannot seek a BufferStream');
    }

    public function eof(): bool
    {
        return strlen($this->buffer) === 0;
    }

    public function tell(): int
    {
        throw new \RuntimeException('Cannot determine the position of a BufferStream');
    }

    /**
     * Reads data from the buffer.
     */
    public function read($length): string
    {
        $currentLength = strlen($this->buffer);

        if ($length >= $currentLength) {
            // No need to slice the buffer because we don't have enough data.
            $result = $this->buffer;
            $this->buffer = '';
        } else {
            // Slice up the result to provide a subset of the buffer.
            $result = substr($this->buffer, 0, $length);
            $this->buffer = substr($this->buffer, $length);
        }

        return $result;
    }

    /**
     * Writes data to the buffer.
     */
    public function write($string): int
    {
        $this->buffer .= $string;

        if (strlen($this->buffer) >= $this->hwm) {
            return 0;
        }

        return strlen($string);
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        if ($key === 'hwm') {
            return $this->hwm;
        }

        return $key ? null : [];
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Stream decorator that can cache previously read bytes from a sequentially
 * read stream.
 */
final class CachingStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var StreamInterface Stream being wrapped */
    private $remoteStream;

    /** @var int Number of bytes to skip reading due to a write on the buffer */
    private $skipReadBytes = 0;

    /**
     * @var StreamInterface
     */
    private $stream;

    /**
     * We will treat the buffer object as the body of the stream
     *
     * @param StreamInterface $stream Stream to cache. The cursor is assumed to be at the beginning of the stream.
     * @param StreamInterface $target Optionally specify where data is cached
     */
    public function __construct(
        StreamInterface $stream,
        ?StreamInterface $target = null
    ) {
        $this->remoteStream = $stream;
        $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
    }

    public function getSize(): ?int
    {
        $remoteSize = $this->remoteStream->getSize();

        if (null === $remoteSize) {
            return null;
        }

        return max($this->stream->getSize(), $remoteSize);
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        if ($whence === SEEK_SET) {
            $byte = $offset;
        } elseif ($whence === SEEK_CUR) {
            $byte = $offset + $this->tell();
        } elseif ($whence === SEEK_END) {
            $size = $this->remoteStream->getSize();
            if ($size === null) {
                $size = $this->cacheEntireStream();
            }
            $byte = $size + $offset;
        } else {
            throw new \InvalidArgumentException('Invalid whence');
        }

        $diff = $byte - $this->stream->getSize();

        if ($diff > 0) {
            // Read the remoteStream until we have read in at least the amount
            // of bytes requested, or we reach the end of the file.
            while ($diff > 0 && !$this->remoteStream->eof()) {
                $this->read($diff);
                $diff = $byte - $this->stream->getSize();
            }
        } else {
            // We can just do a normal seek since we've already seen this byte.
            $this->stream->seek($byte);
        }
    }

    public function read($length): string
    {
        // Perform a regular read on any previously read data from the buffer
        $data = $this->stream->read($length);
        $remaining = $length - strlen($data);

        // More data was requested so read from the remote stream
        if ($remaining) {
            // If data was written to the buffer in a position that would have
            // been filled from the remote stream, then we must skip bytes on
            // the remote stream to emulate overwriting bytes from that
            // position. This mimics the behavior of other PHP stream wrappers.
            $remoteData = $this->remoteStream->read(
                $remaining + $this->skipReadBytes
            );

            if ($this->skipReadBytes) {
                $len = strlen($remoteData);
                $remoteData = substr($remoteData, $this->skipReadBytes);
                $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
            }

            $data .= $remoteData;
            $this->stream->write($remoteData);
        }

        return $data;
    }

    public function write($string): int
    {
        // When appending to the end of the currently read stream, you'll want
        // to skip bytes from being read from the remote stream to emulate
        // other stream wrappers. Basically replacing bytes of data of a fixed
        // length.
        $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
        if ($overflow > 0) {
            $this->skipReadBytes += $overflow;
        }

        return $this->stream->write($string);
    }

    public function eof(): bool
    {
        return $this->stream->eof() && $this->remoteStream->eof();
    }

    /**
     * Close both the remote stream and buffer stream
     */
    public function close(): void
    {
        $this->remoteStream->close();
        $this->stream->close();
    }

    private function cacheEntireStream(): int
    {
        $target = new FnStream(['write' => 'strlen']);
        Utils::copyToStream($this, $target);

        return $this->tell();
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Stream decorator that begins dropping data once the size of the underlying
 * stream becomes too full.
 */
final class DroppingStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var int */
    private $maxLength;

    /** @var StreamInterface */
    private $stream;

    /**
     * @param StreamInterface $stream    Underlying stream to decorate.
     * @param int             $maxLength Maximum size before dropping data.
     */
    public function __construct(StreamInterface $stream, int $maxLength)
    {
        $this->stream = $stream;
        $this->maxLength = $maxLength;
    }

    public function write($string): int
    {
        $diff = $this->maxLength - $this->stream->getSize();

        // Begin returning 0 when the underlying stream is too large.
        if ($diff <= 0) {
            return 0;
        }

        // Write the stream or a subset of the stream if needed.
        if (strlen($string) < $diff) {
            return $this->stream->write($string);
        }

        return $this->stream->write(substr($string, 0, $diff));
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7\Exception;

use InvalidArgumentException;

/**
 * Exception thrown if a URI cannot be parsed because it's malformed.
 */
class MalformedUriException extends InvalidArgumentException
{
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Compose stream implementations based on a hash of functions.
 *
 * Allows for easy testing and extension of a provided stream without needing
 * to create a concrete class for a simple extension point.
 */
#[\AllowDynamicProperties]
final class FnStream implements StreamInterface
{
    private const SLOTS = [
        '__toString', 'close', 'detach', 'rewind',
        'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
        'isReadable', 'read', 'getContents', 'getMetadata',
    ];

    /** @var array<string, callable> */
    private $methods;

    /**
     * @param array<string, callable> $methods Hash of method name to a callable.
     */
    public function __construct(array $methods)
    {
        $this->methods = $methods;

        // Create the functions on the class
        foreach ($methods as $name => $fn) {
            $this->{'_fn_'.$name} = $fn;
        }
    }

    /**
     * Lazily determine which methods are not implemented.
     *
     * @throws \BadMethodCallException
     */
    public function __get(string $name): void
    {
        throw new \BadMethodCallException(str_replace('_fn_', '', $name)
            .'() is not implemented in the FnStream');
    }

    /**
     * The close method is called on the underlying stream only if possible.
     */
    public function __destruct()
    {
        if (isset($this->_fn_close)) {
            ($this->_fn_close)();
        }
    }

    /**
     * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
     *
     * @throws \LogicException
     */
    public function __wakeup(): void
    {
        throw new \LogicException('FnStream should never be unserialized');
    }

    /**
     * Adds custom functionality to an underlying stream by intercepting
     * specific method calls.
     *
     * @param StreamInterface         $stream  Stream to decorate
     * @param array<string, callable> $methods Hash of method name to a closure
     *
     * @return FnStream
     */
    public static function decorate(StreamInterface $stream, array $methods)
    {
        // If any of the required methods were not provided, then simply
        // proxy to the decorated stream.
        foreach (array_diff(self::SLOTS, array_keys($methods)) as $diff) {
            /** @var callable $callable */
            $callable = [$stream, $diff];
            $methods[$diff] = $callable;
        }

        return new self($methods);
    }

    public function __toString(): string
    {
        try {
            /** @var string */
            return ($this->_fn___toString)();
        } catch (\Throwable $e) {
            if (\PHP_VERSION_ID >= 70400) {
                throw $e;
            }
            trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);

            return '';
        }
    }

    public function close(): void
    {
        ($this->_fn_close)();
    }

    public function detach()
    {
        return ($this->_fn_detach)();
    }

    public function getSize(): ?int
    {
        return ($this->_fn_getSize)();
    }

    public function tell(): int
    {
        return ($this->_fn_tell)();
    }

    public function eof(): bool
    {
        return ($this->_fn_eof)();
    }

    public function isSeekable(): bool
    {
        return ($this->_fn_isSeekable)();
    }

    public function rewind(): void
    {
        ($this->_fn_rewind)();
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        ($this->_fn_seek)($offset, $whence);
    }

    public function isWritable(): bool
    {
        return ($this->_fn_isWritable)();
    }

    public function write($string): int
    {
        return ($this->_fn_write)($string);
    }

    public function isReadable(): bool
    {
        return ($this->_fn_isReadable)();
    }

    public function read($length): string
    {
        return ($this->_fn_read)($length);
    }

    public function getContents(): string
    {
        return ($this->_fn_getContents)();
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        return ($this->_fn_getMetadata)($key);
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

final class Header
{
    /**
     * Parse an array of header values containing ";" separated data into an
     * array of associative arrays representing the header key value pair data
     * of the header. When a parameter does not contain a value, but just
     * contains a key, this function will inject a key with a '' string value.
     *
     * @param string|array $header Header to parse into components.
     */
    public static function parse($header): array
    {
        static $trimmed = "\"'  \n\t\r";
        $params = $matches = [];

        foreach ((array) $header as $value) {
            foreach (self::splitList($value) as $val) {
                $part = [];
                foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) ?: [] as $kvp) {
                    if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
                        $m = $matches[0];
                        if (isset($m[1])) {
                            $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
                        } else {
                            $part[] = trim($m[0], $trimmed);
                        }
                    }
                }
                if ($part) {
                    $params[] = $part;
                }
            }
        }

        return $params;
    }

    /**
     * Converts an array of header values that may contain comma separated
     * headers into an array of headers with no comma separated values.
     *
     * @param string|array $header Header to normalize.
     *
     * @deprecated Use self::splitList() instead.
     */
    public static function normalize($header): array
    {
        $result = [];
        foreach ((array) $header as $value) {
            foreach (self::splitList($value) as $parsed) {
                $result[] = $parsed;
            }
        }

        return $result;
    }

    /**
     * Splits a HTTP header defined to contain a comma-separated list into
     * each individual value. Empty values will be removed.
     *
     * Example headers include 'accept', 'cache-control' and 'if-none-match'.
     *
     * This method must not be used to parse headers that are not defined as
     * a list, such as 'user-agent' or 'set-cookie'.
     *
     * @param string|string[] $values Header value as returned by MessageInterface::getHeader()
     *
     * @return string[]
     */
    public static function splitList($values): array
    {
        if (!\is_array($values)) {
            $values = [$values];
        }

        $result = [];
        foreach ($values as $value) {
            if (!\is_string($value)) {
                throw new \TypeError('$header must either be a string or an array containing strings.');
            }

            $v = '';
            $isQuoted = false;
            $isEscaped = false;
            for ($i = 0, $max = \strlen($value); $i < $max; ++$i) {
                if ($isEscaped) {
                    $v .= $value[$i];
                    $isEscaped = false;

                    continue;
                }

                if (!$isQuoted && $value[$i] === ',') {
                    $v = \trim($v);
                    if ($v !== '') {
                        $result[] = $v;
                    }

                    $v = '';
                    continue;
                }

                if ($isQuoted && $value[$i] === '\\') {
                    $isEscaped = true;
                    $v .= $value[$i];

                    continue;
                }
                if ($value[$i] === '"') {
                    $isQuoted = !$isQuoted;
                    $v .= $value[$i];

                    continue;
                }

                $v .= $value[$i];
            }

            $v = \trim($v);
            if ($v !== '') {
                $result[] = $v;
            }
        }

        return $result;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriFactoryInterface;
use Psr\Http\Message\UriInterface;

/**
 * Implements all of the PSR-17 interfaces.
 *
 * Note: in consuming code it is recommended to require the implemented interfaces
 * and inject the instance of this class multiple times.
 */
final class HttpFactory implements RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface
{
    public function createUploadedFile(
        StreamInterface $stream,
        ?int $size = null,
        int $error = \UPLOAD_ERR_OK,
        ?string $clientFilename = null,
        ?string $clientMediaType = null
    ): UploadedFileInterface {
        if ($size === null) {
            $size = $stream->getSize();
        }

        return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType);
    }

    public function createStream(string $content = ''): StreamInterface
    {
        return Utils::streamFor($content);
    }

    public function createStreamFromFile(string $file, string $mode = 'r'): StreamInterface
    {
        try {
            $resource = Utils::tryFopen($file, $mode);
        } catch (\RuntimeException $e) {
            if ('' === $mode || false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'], true)) {
                throw new \InvalidArgumentException(sprintf('Invalid file opening mode "%s"', $mode), 0, $e);
            }

            throw $e;
        }

        return Utils::streamFor($resource);
    }

    public function createStreamFromResource($resource): StreamInterface
    {
        return Utils::streamFor($resource);
    }

    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
    {
        if (empty($method)) {
            if (!empty($serverParams['REQUEST_METHOD'])) {
                $method = $serverParams['REQUEST_METHOD'];
            } else {
                throw new \InvalidArgumentException('Cannot determine HTTP method');
            }
        }

        return new ServerRequest($method, $uri, [], null, '1.1', $serverParams);
    }

    public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface
    {
        return new Response($code, [], null, '1.1', $reasonPhrase);
    }

    public function createRequest(string $method, $uri): RequestInterface
    {
        return new Request($method, $uri);
    }

    public function createUri(string $uri = ''): UriInterface
    {
        return new Uri($uri);
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Uses PHP's zlib.inflate filter to inflate zlib (HTTP deflate, RFC1950) or gzipped (RFC1952) content.
 *
 * This stream decorator converts the provided stream to a PHP stream resource,
 * then appends the zlib.inflate filter. The stream is then converted back
 * to a Guzzle stream resource to be used as a Guzzle stream.
 *
 * @see https://datatracker.ietf.org/doc/html/rfc1950
 * @see https://datatracker.ietf.org/doc/html/rfc1952
 * @see https://www.php.net/manual/en/filters.compression.php
 */
final class InflateStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var StreamInterface */
    private $stream;

    public function __construct(StreamInterface $stream)
    {
        $resource = StreamWrapper::getResource($stream);
        // Specify window=15+32, so zlib will use header detection to both gzip (with header) and zlib data
        // See https://www.zlib.net/manual.html#Advanced definition of inflateInit2
        // "Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection"
        // Default window size is 15.
        stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15 + 32]);
        $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Lazily reads or writes to a file that is opened only after an IO operation
 * take place on the stream.
 */
final class LazyOpenStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var string */
    private $filename;

    /** @var string */
    private $mode;

    /**
     * @var StreamInterface
     */
    private $stream;

    /**
     * @param string $filename File to lazily open
     * @param string $mode     fopen mode to use when opening the stream
     */
    public function __construct(string $filename, string $mode)
    {
        $this->filename = $filename;
        $this->mode = $mode;

        // unsetting the property forces the first access to go through
        // __get().
        unset($this->stream);
    }

    /**
     * Creates the underlying stream lazily when required.
     */
    protected function createStream(): StreamInterface
    {
        return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Decorator used to return only a subset of a stream.
 */
final class LimitStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var int Offset to start reading from */
    private $offset;

    /** @var int Limit the number of bytes that can be read */
    private $limit;

    /** @var StreamInterface */
    private $stream;

    /**
     * @param StreamInterface $stream Stream to wrap
     * @param int             $limit  Total number of bytes to allow to be read
     *                                from the stream. Pass -1 for no limit.
     * @param int             $offset Position to seek to before reading (only
     *                                works on seekable streams).
     */
    public function __construct(
        StreamInterface $stream,
        int $limit = -1,
        int $offset = 0
    ) {
        $this->stream = $stream;
        $this->setLimit($limit);
        $this->setOffset($offset);
    }

    public function eof(): bool
    {
        // Always return true if the underlying stream is EOF
        if ($this->stream->eof()) {
            return true;
        }

        // No limit and the underlying stream is not at EOF
        if ($this->limit === -1) {
            return false;
        }

        return $this->stream->tell() >= $this->offset + $this->limit;
    }

    /**
     * Returns the size of the limited subset of data
     */
    public function getSize(): ?int
    {
        if (null === ($length = $this->stream->getSize())) {
            return null;
        } elseif ($this->limit === -1) {
            return $length - $this->offset;
        } else {
            return min($this->limit, $length - $this->offset);
        }
    }

    /**
     * Allow for a bounded seek on the read limited stream
     */
    public function seek($offset, $whence = SEEK_SET): void
    {
        if ($whence !== SEEK_SET || $offset < 0) {
            throw new \RuntimeException(sprintf(
                'Cannot seek to offset %s with whence %s',
                $offset,
                $whence
            ));
        }

        $offset += $this->offset;

        if ($this->limit !== -1) {
            if ($offset > $this->offset + $this->limit) {
                $offset = $this->offset + $this->limit;
            }
        }

        $this->stream->seek($offset);
    }

    /**
     * Give a relative tell()
     */
    public function tell(): int
    {
        return $this->stream->tell() - $this->offset;
    }

    /**
     * Set the offset to start limiting from
     *
     * @param int $offset Offset to seek to and begin byte limiting from
     *
     * @throws \RuntimeException if the stream cannot be seeked.
     */
    public function setOffset(int $offset): void
    {
        $current = $this->stream->tell();

        if ($current !== $offset) {
            // If the stream cannot seek to the offset position, then read to it
            if ($this->stream->isSeekable()) {
                $this->stream->seek($offset);
            } elseif ($current > $offset) {
                throw new \RuntimeException("Could not seek to stream offset $offset");
            } else {
                $this->stream->read($offset - $current);
            }
        }

        $this->offset = $offset;
    }

    /**
     * Set the limit of bytes that the decorator allows to be read from the
     * stream.
     *
     * @param int $limit Number of bytes to allow to be read from the stream.
     *                   Use -1 for no limit.
     */
    public function setLimit(int $limit): void
    {
        $this->limit = $limit;
    }

    public function read($length): string
    {
        if ($this->limit === -1) {
            return $this->stream->read($length);
        }

        // Check if the current position is less than the total allowed
        // bytes + original offset
        $remaining = ($this->offset + $this->limit) - $this->stream->tell();
        if ($remaining > 0) {
            // Only return the amount of requested data, ensuring that the byte
            // limit is not exceeded
            return $this->stream->read(min($remaining, $length));
        }

        return '';
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

final class Message
{
    /**
     * Returns the string representation of an HTTP message.
     *
     * @param MessageInterface $message Message to convert to a string.
     */
    public static function toString(MessageInterface $message): string
    {
        if ($message instanceof RequestInterface) {
            $msg = trim($message->getMethod().' '
                    .$message->getRequestTarget())
                .' HTTP/'.$message->getProtocolVersion();
            if (!$message->hasHeader('host')) {
                $msg .= "\r\nHost: ".$message->getUri()->getHost();
            }
        } elseif ($message instanceof ResponseInterface) {
            $msg = 'HTTP/'.$message->getProtocolVersion().' '
                .$message->getStatusCode().' '
                .$message->getReasonPhrase();
        } else {
            throw new \InvalidArgumentException('Unknown message type');
        }

        foreach ($message->getHeaders() as $name => $values) {
            if (is_string($name) && strtolower($name) === 'set-cookie') {
                foreach ($values as $value) {
                    $msg .= "\r\n{$name}: ".$value;
                }
            } else {
                $msg .= "\r\n{$name}: ".implode(', ', $values);
            }
        }

        return "{$msg}\r\n\r\n".$message->getBody();
    }

    /**
     * Get a short summary of the message body.
     *
     * Will return `null` if the response is not printable.
     *
     * @param MessageInterface $message    The message to get the body summary
     * @param int              $truncateAt The maximum allowed size of the summary
     */
    public static function bodySummary(MessageInterface $message, int $truncateAt = 120): ?string
    {
        $body = $message->getBody();

        if (!$body->isSeekable() || !$body->isReadable()) {
            return null;
        }

        $size = $body->getSize();

        if ($size === 0) {
            return null;
        }

        $body->rewind();
        $summary = $body->read($truncateAt);
        $body->rewind();

        if ($size > $truncateAt) {
            $summary .= ' (truncated...)';
        }

        // Matches any printable character, including unicode characters:
        // letters, marks, numbers, punctuation, spacing, and separators.
        if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary) !== 0) {
            return null;
        }

        return $summary;
    }

    /**
     * Attempts to rewind a message body and throws an exception on failure.
     *
     * The body of the message will only be rewound if a call to `tell()`
     * returns a value other than `0`.
     *
     * @param MessageInterface $message Message to rewind
     *
     * @throws \RuntimeException
     */
    public static function rewindBody(MessageInterface $message): void
    {
        $body = $message->getBody();

        if ($body->tell()) {
            $body->rewind();
        }
    }

    /**
     * Parses an HTTP message into an associative array.
     *
     * The array contains the "start-line" key containing the start line of
     * the message, "headers" key containing an associative array of header
     * array values, and a "body" key containing the body of the message.
     *
     * @param string $message HTTP request or response to parse.
     */
    public static function parseMessage(string $message): array
    {
        if (!$message) {
            throw new \InvalidArgumentException('Invalid message');
        }

        $message = ltrim($message, "\r\n");

        $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);

        if ($messageParts === false || count($messageParts) !== 2) {
            throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
        }

        [$rawHeaders, $body] = $messageParts;
        $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
        $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);

        if ($headerParts === false || count($headerParts) !== 2) {
            throw new \InvalidArgumentException('Invalid message: Missing status line');
        }

        [$startLine, $rawHeaders] = $headerParts;

        if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
            // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
            $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
        }

        /** @var array[] $headerLines */
        $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);

        // If these aren't the same, then one line didn't match and there's an invalid header.
        if ($count !== substr_count($rawHeaders, "\n")) {
            // Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4
            if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
                throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
            }

            throw new \InvalidArgumentException('Invalid header syntax');
        }

        $headers = [];

        foreach ($headerLines as $headerLine) {
            $headers[$headerLine[1]][] = $headerLine[2];
        }

        return [
            'start-line' => $startLine,
            'headers' => $headers,
            'body' => $body,
        ];
    }

    /**
     * Constructs a URI for an HTTP request message.
     *
     * @param string $path    Path from the start-line
     * @param array  $headers Array of headers (each value an array).
     */
    public static function parseRequestUri(string $path, array $headers): string
    {
        $hostKey = array_filter(array_keys($headers), function ($k) {
            // Numeric array keys are converted to int by PHP.
            $k = (string) $k;

            return strtolower($k) === 'host';
        });

        // If no host is found, then a full URI cannot be constructed.
        if (!$hostKey) {
            return $path;
        }

        $host = $headers[reset($hostKey)][0];
        $scheme = substr($host, -4) === ':443' ? 'https' : 'http';

        return $scheme.'://'.$host.'/'.ltrim($path, '/');
    }

    /**
     * Parses a request message string into a request object.
     *
     * @param string $message Request message string.
     */
    public static function parseRequest(string $message): RequestInterface
    {
        $data = self::parseMessage($message);
        $matches = [];
        if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
            throw new \InvalidArgumentException('Invalid request string');
        }
        $parts = explode(' ', $data['start-line'], 3);
        $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';

        $request = new Request(
            $parts[0],
            $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],
            $data['headers'],
            $data['body'],
            $version
        );

        return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
    }

    /**
     * Parses a response message string into a response object.
     *
     * @param string $message Response message string.
     */
    public static function parseResponse(string $message): ResponseInterface
    {
        $data = self::parseMessage($message);
        // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
        // the space between status-code and reason-phrase is required. But
        // browsers accept responses without space and reason as well.
        if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
            throw new \InvalidArgumentException('Invalid response string: '.$data['start-line']);
        }
        $parts = explode(' ', $data['start-line'], 3);

        return new Response(
            (int) $parts[1],
            $data['headers'],
            $data['body'],
            explode('/', $parts[0])[1],
            $parts[2] ?? null
        );
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;

/**
 * Trait implementing functionality common to requests and responses.
 */
trait MessageTrait
{
    /** @var string[][] Map of all registered headers, as original name => array of values */
    private $headers = [];

    /** @var string[] Map of lowercase header name => original name at registration */
    private $headerNames = [];

    /** @var string */
    private $protocol = '1.1';

    /** @var StreamInterface|null */
    private $stream;

    public function getProtocolVersion(): string
    {
        return $this->protocol;
    }

    public function withProtocolVersion($version): MessageInterface
    {
        if ($this->protocol === $version) {
            return $this;
        }

        $new = clone $this;
        $new->protocol = $version;

        return $new;
    }

    public function getHeaders(): array
    {
        return $this->headers;
    }

    public function hasHeader($header): bool
    {
        return isset($this->headerNames[strtolower($header)]);
    }

    public function getHeader($header): array
    {
        $header = strtolower($header);

        if (!isset($this->headerNames[$header])) {
            return [];
        }

        $header = $this->headerNames[$header];

        return $this->headers[$header];
    }

    public function getHeaderLine($header): string
    {
        return implode(', ', $this->getHeader($header));
    }

    public function withHeader($header, $value): MessageInterface
    {
        $this->assertHeader($header);
        $value = $this->normalizeHeaderValue($value);
        $normalized = strtolower($header);

        $new = clone $this;
        if (isset($new->headerNames[$normalized])) {
            unset($new->headers[$new->headerNames[$normalized]]);
        }
        $new->headerNames[$normalized] = $header;
        $new->headers[$header] = $value;

        return $new;
    }

    public function withAddedHeader($header, $value): MessageInterface
    {
        $this->assertHeader($header);
        $value = $this->normalizeHeaderValue($value);
        $normalized = strtolower($header);

        $new = clone $this;
        if (isset($new->headerNames[$normalized])) {
            $header = $this->headerNames[$normalized];
            $new->headers[$header] = array_merge($this->headers[$header], $value);
        } else {
            $new->headerNames[$normalized] = $header;
            $new->headers[$header] = $value;
        }

        return $new;
    }

    public function withoutHeader($header): MessageInterface
    {
        $normalized = strtolower($header);

        if (!isset($this->headerNames[$normalized])) {
            return $this;
        }

        $header = $this->headerNames[$normalized];

        $new = clone $this;
        unset($new->headers[$header], $new->headerNames[$normalized]);

        return $new;
    }

    public function getBody(): StreamInterface
    {
        if (!$this->stream) {
            $this->stream = Utils::streamFor('');
        }

        return $this->stream;
    }

    public function withBody(StreamInterface $body): MessageInterface
    {
        if ($body === $this->stream) {
            return $this;
        }

        $new = clone $this;
        $new->stream = $body;

        return $new;
    }

    /**
     * @param (string|string[])[] $headers
     */
    private function setHeaders(array $headers): void
    {
        $this->headerNames = $this->headers = [];
        foreach ($headers as $header => $value) {
            // Numeric array keys are converted to int by PHP.
            $header = (string) $header;

            $this->assertHeader($header);
            $value = $this->normalizeHeaderValue($value);
            $normalized = strtolower($header);
            if (isset($this->headerNames[$normalized])) {
                $header = $this->headerNames[$normalized];
                $this->headers[$header] = array_merge($this->headers[$header], $value);
            } else {
                $this->headerNames[$normalized] = $header;
                $this->headers[$header] = $value;
            }
        }
    }

    /**
     * @param mixed $value
     *
     * @return string[]
     */
    private function normalizeHeaderValue($value): array
    {
        if (!is_array($value)) {
            return $this->trimAndValidateHeaderValues([$value]);
        }

        return $this->trimAndValidateHeaderValues($value);
    }

    /**
     * Trims whitespace from the header values.
     *
     * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
     *
     * header-field = field-name ":" OWS field-value OWS
     * OWS          = *( SP / HTAB )
     *
     * @param mixed[] $values Header values
     *
     * @return string[] Trimmed header values
     *
     * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4
     */
    private function trimAndValidateHeaderValues(array $values): array
    {
        return array_map(function ($value) {
            if (!is_scalar($value) && null !== $value) {
                throw new \InvalidArgumentException(sprintf(
                    'Header value must be scalar or null but %s provided.',
                    is_object($value) ? get_class($value) : gettype($value)
                ));
            }

            $trimmed = trim((string) $value, " \t");
            $this->assertValue($trimmed);

            return $trimmed;
        }, array_values($values));
    }

    /**
     * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
     *
     * @param mixed $header
     */
    private function assertHeader($header): void
    {
        if (!is_string($header)) {
            throw new \InvalidArgumentException(sprintf(
                'Header name must be a string but %s provided.',
                is_object($header) ? get_class($header) : gettype($header)
            ));
        }

        if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
            throw new \InvalidArgumentException(
                sprintf('"%s" is not valid header name.', $header)
            );
        }
    }

    /**
     * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
     *
     * field-value    = *( field-content / obs-fold )
     * field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
     * field-vchar    = VCHAR / obs-text
     * VCHAR          = %x21-7E
     * obs-text       = %x80-FF
     * obs-fold       = CRLF 1*( SP / HTAB )
     */
    private function assertValue(string $value): void
    {
        // The regular expression intentionally does not support the obs-fold production, because as
        // per RFC 7230#3.2.4:
        //
        // A sender MUST NOT generate a message that includes
        // line folding (i.e., that has any field-value that contains a match to
        // the obs-fold rule) unless the message is intended for packaging
        // within the message/http media type.
        //
        // Clients must not send a request with line folding and a server sending folded headers is
        // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
        // folding is not likely to break any legitimate use case.
        if (!preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
            throw new \InvalidArgumentException(
                sprintf('"%s" is not valid header value.', $value)
            );
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

final class MimeType
{
    private const MIME_TYPES = [
        '1km' => 'application/vnd.1000minds.decision-model+xml',
        '3dml' => 'text/vnd.in3d.3dml',
        '3ds' => 'image/x-3ds',
        '3g2' => 'video/3gpp2',
        '3gp' => 'video/3gp',
        '3gpp' => 'video/3gpp',
        '3mf' => 'model/3mf',
        '7z' => 'application/x-7z-compressed',
        '7zip' => 'application/x-7z-compressed',
        '123' => 'application/vnd.lotus-1-2-3',
        'aab' => 'application/x-authorware-bin',
        'aac' => 'audio/aac',
        'aam' => 'application/x-authorware-map',
        'aas' => 'application/x-authorware-seg',
        'abw' => 'application/x-abiword',
        'ac' => 'application/vnd.nokia.n-gage.ac+xml',
        'ac3' => 'audio/ac3',
        'acc' => 'application/vnd.americandynamics.acc',
        'ace' => 'application/x-ace-compressed',
        'acu' => 'application/vnd.acucobol',
        'acutc' => 'application/vnd.acucorp',
        'adp' => 'audio/adpcm',
        'adts' => 'audio/aac',
        'aep' => 'application/vnd.audiograph',
        'afm' => 'application/x-font-type1',
        'afp' => 'application/vnd.ibm.modcap',
        'age' => 'application/vnd.age',
        'ahead' => 'application/vnd.ahead.space',
        'ai' => 'application/pdf',
        'aif' => 'audio/x-aiff',
        'aifc' => 'audio/x-aiff',
        'aiff' => 'audio/x-aiff',
        'air' => 'application/vnd.adobe.air-application-installer-package+zip',
        'ait' => 'application/vnd.dvb.ait',
        'ami' => 'application/vnd.amiga.ami',
        'aml' => 'application/automationml-aml+xml',
        'amlx' => 'application/automationml-amlx+zip',
        'amr' => 'audio/amr',
        'apk' => 'application/vnd.android.package-archive',
        'apng' => 'image/apng',
        'appcache' => 'text/cache-manifest',
        'appinstaller' => 'application/appinstaller',
        'application' => 'application/x-ms-application',
        'appx' => 'application/appx',
        'appxbundle' => 'application/appxbundle',
        'apr' => 'application/vnd.lotus-approach',
        'arc' => 'application/x-freearc',
        'arj' => 'application/x-arj',
        'asc' => 'application/pgp-signature',
        'asf' => 'video/x-ms-asf',
        'asm' => 'text/x-asm',
        'aso' => 'application/vnd.accpac.simply.aso',
        'asx' => 'video/x-ms-asf',
        'atc' => 'application/vnd.acucorp',
        'atom' => 'application/atom+xml',
        'atomcat' => 'application/atomcat+xml',
        'atomdeleted' => 'application/atomdeleted+xml',
        'atomsvc' => 'application/atomsvc+xml',
        'atx' => 'application/vnd.antix.game-component',
        'au' => 'audio/x-au',
        'avci' => 'image/avci',
        'avcs' => 'image/avcs',
        'avi' => 'video/x-msvideo',
        'avif' => 'image/avif',
        'aw' => 'application/applixware',
        'azf' => 'application/vnd.airzip.filesecure.azf',
        'azs' => 'application/vnd.airzip.filesecure.azs',
        'azv' => 'image/vnd.airzip.accelerator.azv',
        'azw' => 'application/vnd.amazon.ebook',
        'b16' => 'image/vnd.pco.b16',
        'bat' => 'application/x-msdownload',
        'bcpio' => 'application/x-bcpio',
        'bdf' => 'application/x-font-bdf',
        'bdm' => 'application/vnd.syncml.dm+wbxml',
        'bdoc' => 'application/x-bdoc',
        'bed' => 'application/vnd.realvnc.bed',
        'bh2' => 'application/vnd.fujitsu.oasysprs',
        'bin' => 'application/octet-stream',
        'blb' => 'application/x-blorb',
        'blorb' => 'application/x-blorb',
        'bmi' => 'application/vnd.bmi',
        'bmml' => 'application/vnd.balsamiq.bmml+xml',
        'bmp' => 'image/bmp',
        'book' => 'application/vnd.framemaker',
        'box' => 'application/vnd.previewsystems.box',
        'boz' => 'application/x-bzip2',
        'bpk' => 'application/octet-stream',
        'bpmn' => 'application/octet-stream',
        'bsp' => 'model/vnd.valve.source.compiled-map',
        'btf' => 'image/prs.btif',
        'btif' => 'image/prs.btif',
        'buffer' => 'application/octet-stream',
        'bz' => 'application/x-bzip',
        'bz2' => 'application/x-bzip2',
        'c' => 'text/x-c',
        'c4d' => 'application/vnd.clonk.c4group',
        'c4f' => 'application/vnd.clonk.c4group',
        'c4g' => 'application/vnd.clonk.c4group',
        'c4p' => 'application/vnd.clonk.c4group',
        'c4u' => 'application/vnd.clonk.c4group',
        'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
        'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
        'cab' => 'application/vnd.ms-cab-compressed',
        'caf' => 'audio/x-caf',
        'cap' => 'application/vnd.tcpdump.pcap',
        'car' => 'application/vnd.curl.car',
        'cat' => 'application/vnd.ms-pki.seccat',
        'cb7' => 'application/x-cbr',
        'cba' => 'application/x-cbr',
        'cbr' => 'application/x-cbr',
        'cbt' => 'application/x-cbr',
        'cbz' => 'application/x-cbr',
        'cc' => 'text/x-c',
        'cco' => 'application/x-cocoa',
        'cct' => 'application/x-director',
        'ccxml' => 'application/ccxml+xml',
        'cdbcmsg' => 'application/vnd.contact.cmsg',
        'cdf' => 'application/x-netcdf',
        'cdfx' => 'application/cdfx+xml',
        'cdkey' => 'application/vnd.mediastation.cdkey',
        'cdmia' => 'application/cdmi-capability',
        'cdmic' => 'application/cdmi-container',
        'cdmid' => 'application/cdmi-domain',
        'cdmio' => 'application/cdmi-object',
        'cdmiq' => 'application/cdmi-queue',
        'cdr' => 'application/cdr',
        'cdx' => 'chemical/x-cdx',
        'cdxml' => 'application/vnd.chemdraw+xml',
        'cdy' => 'application/vnd.cinderella',
        'cer' => 'application/pkix-cert',
        'cfs' => 'application/x-cfs-compressed',
        'cgm' => 'image/cgm',
        'chat' => 'application/x-chat',
        'chm' => 'application/vnd.ms-htmlhelp',
        'chrt' => 'application/vnd.kde.kchart',
        'cif' => 'chemical/x-cif',
        'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
        'cil' => 'application/vnd.ms-artgalry',
        'cjs' => 'application/node',
        'cla' => 'application/vnd.claymore',
        'class' => 'application/octet-stream',
        'cld' => 'model/vnd.cld',
        'clkk' => 'application/vnd.crick.clicker.keyboard',
        'clkp' => 'application/vnd.crick.clicker.palette',
        'clkt' => 'application/vnd.crick.clicker.template',
        'clkw' => 'application/vnd.crick.clicker.wordbank',
        'clkx' => 'application/vnd.crick.clicker',
        'clp' => 'application/x-msclip',
        'cmc' => 'application/vnd.cosmocaller',
        'cmdf' => 'chemical/x-cmdf',
        'cml' => 'chemical/x-cml',
        'cmp' => 'application/vnd.yellowriver-custom-menu',
        'cmx' => 'image/x-cmx',
        'cod' => 'application/vnd.rim.cod',
        'coffee' => 'text/coffeescript',
        'com' => 'application/x-msdownload',
        'conf' => 'text/plain',
        'cpio' => 'application/x-cpio',
        'cpl' => 'application/cpl+xml',
        'cpp' => 'text/x-c',
        'cpt' => 'application/mac-compactpro',
        'crd' => 'application/x-mscardfile',
        'crl' => 'application/pkix-crl',
        'crt' => 'application/x-x509-ca-cert',
        'crx' => 'application/x-chrome-extension',
        'cryptonote' => 'application/vnd.rig.cryptonote',
        'csh' => 'application/x-csh',
        'csl' => 'application/vnd.citationstyles.style+xml',
        'csml' => 'chemical/x-csml',
        'csp' => 'application/vnd.commonspace',
        'csr' => 'application/octet-stream',
        'css' => 'text/css',
        'cst' => 'application/x-director',
        'csv' => 'text/csv',
        'cu' => 'application/cu-seeme',
        'curl' => 'text/vnd.curl',
        'cwl' => 'application/cwl',
        'cww' => 'application/prs.cww',
        'cxt' => 'application/x-director',
        'cxx' => 'text/x-c',
        'dae' => 'model/vnd.collada+xml',
        'daf' => 'application/vnd.mobius.daf',
        'dart' => 'application/vnd.dart',
        'dataless' => 'application/vnd.fdsn.seed',
        'davmount' => 'application/davmount+xml',
        'dbf' => 'application/vnd.dbf',
        'dbk' => 'application/docbook+xml',
        'dcr' => 'application/x-director',
        'dcurl' => 'text/vnd.curl.dcurl',
        'dd2' => 'application/vnd.oma.dd2+xml',
        'ddd' => 'application/vnd.fujixerox.ddd',
        'ddf' => 'application/vnd.syncml.dmddf+xml',
        'dds' => 'image/vnd.ms-dds',
        'deb' => 'application/x-debian-package',
        'def' => 'text/plain',
        'deploy' => 'application/octet-stream',
        'der' => 'application/x-x509-ca-cert',
        'dfac' => 'application/vnd.dreamfactory',
        'dgc' => 'application/x-dgc-compressed',
        'dib' => 'image/bmp',
        'dic' => 'text/x-c',
        'dir' => 'application/x-director',
        'dis' => 'application/vnd.mobius.dis',
        'disposition-notification' => 'message/disposition-notification',
        'dist' => 'application/octet-stream',
        'distz' => 'application/octet-stream',
        'djv' => 'image/vnd.djvu',
        'djvu' => 'image/vnd.djvu',
        'dll' => 'application/octet-stream',
        'dmg' => 'application/x-apple-diskimage',
        'dmn' => 'application/octet-stream',
        'dmp' => 'application/vnd.tcpdump.pcap',
        'dms' => 'application/octet-stream',
        'dna' => 'application/vnd.dna',
        'doc' => 'application/msword',
        'docm' => 'application/vnd.ms-word.template.macroEnabled.12',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'dot' => 'application/msword',
        'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
        'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
        'dp' => 'application/vnd.osgi.dp',
        'dpg' => 'application/vnd.dpgraph',
        'dpx' => 'image/dpx',
        'dra' => 'audio/vnd.dra',
        'drle' => 'image/dicom-rle',
        'dsc' => 'text/prs.lines.tag',
        'dssc' => 'application/dssc+der',
        'dtb' => 'application/x-dtbook+xml',
        'dtd' => 'application/xml-dtd',
        'dts' => 'audio/vnd.dts',
        'dtshd' => 'audio/vnd.dts.hd',
        'dump' => 'application/octet-stream',
        'dvb' => 'video/vnd.dvb.file',
        'dvi' => 'application/x-dvi',
        'dwd' => 'application/atsc-dwd+xml',
        'dwf' => 'model/vnd.dwf',
        'dwg' => 'image/vnd.dwg',
        'dxf' => 'image/vnd.dxf',
        'dxp' => 'application/vnd.spotfire.dxp',
        'dxr' => 'application/x-director',
        'ear' => 'application/java-archive',
        'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
        'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
        'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
        'ecma' => 'application/ecmascript',
        'edm' => 'application/vnd.novadigm.edm',
        'edx' => 'application/vnd.novadigm.edx',
        'efif' => 'application/vnd.picsel',
        'ei6' => 'application/vnd.pg.osasli',
        'elc' => 'application/octet-stream',
        'emf' => 'image/emf',
        'eml' => 'message/rfc822',
        'emma' => 'application/emma+xml',
        'emotionml' => 'application/emotionml+xml',
        'emz' => 'application/x-msmetafile',
        'eol' => 'audio/vnd.digital-winds',
        'eot' => 'application/vnd.ms-fontobject',
        'eps' => 'application/postscript',
        'epub' => 'application/epub+zip',
        'es3' => 'application/vnd.eszigno3+xml',
        'esa' => 'application/vnd.osgi.subsystem',
        'esf' => 'application/vnd.epson.esf',
        'et3' => 'application/vnd.eszigno3+xml',
        'etx' => 'text/x-setext',
        'eva' => 'application/x-eva',
        'evy' => 'application/x-envoy',
        'exe' => 'application/octet-stream',
        'exi' => 'application/exi',
        'exp' => 'application/express',
        'exr' => 'image/aces',
        'ext' => 'application/vnd.novadigm.ext',
        'ez' => 'application/andrew-inset',
        'ez2' => 'application/vnd.ezpix-album',
        'ez3' => 'application/vnd.ezpix-package',
        'f' => 'text/x-fortran',
        'f4v' => 'video/mp4',
        'f77' => 'text/x-fortran',
        'f90' => 'text/x-fortran',
        'fbs' => 'image/vnd.fastbidsheet',
        'fcdt' => 'application/vnd.adobe.formscentral.fcdt',
        'fcs' => 'application/vnd.isac.fcs',
        'fdf' => 'application/vnd.fdf',
        'fdt' => 'application/fdt+xml',
        'fe_launch' => 'application/vnd.denovo.fcselayout-link',
        'fg5' => 'application/vnd.fujitsu.oasysgp',
        'fgd' => 'application/x-director',
        'fh' => 'image/x-freehand',
        'fh4' => 'image/x-freehand',
        'fh5' => 'image/x-freehand',
        'fh7' => 'image/x-freehand',
        'fhc' => 'image/x-freehand',
        'fig' => 'application/x-xfig',
        'fits' => 'image/fits',
        'flac' => 'audio/x-flac',
        'fli' => 'video/x-fli',
        'flo' => 'application/vnd.micrografx.flo',
        'flv' => 'video/x-flv',
        'flw' => 'application/vnd.kde.kivio',
        'flx' => 'text/vnd.fmi.flexstor',
        'fly' => 'text/vnd.fly',
        'fm' => 'application/vnd.framemaker',
        'fnc' => 'application/vnd.frogans.fnc',
        'fo' => 'application/vnd.software602.filler.form+xml',
        'for' => 'text/x-fortran',
        'fpx' => 'image/vnd.fpx',
        'frame' => 'application/vnd.framemaker',
        'fsc' => 'application/vnd.fsc.weblaunch',
        'fst' => 'image/vnd.fst',
        'ftc' => 'application/vnd.fluxtime.clip',
        'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
        'fvt' => 'video/vnd.fvt',
        'fxp' => 'application/vnd.adobe.fxp',
        'fxpl' => 'application/vnd.adobe.fxp',
        'fzs' => 'application/vnd.fuzzysheet',
        'g2w' => 'application/vnd.geoplan',
        'g3' => 'image/g3fax',
        'g3w' => 'application/vnd.geospace',
        'gac' => 'application/vnd.groove-account',
        'gam' => 'application/x-tads',
        'gbr' => 'application/rpki-ghostbusters',
        'gca' => 'application/x-gca-compressed',
        'gdl' => 'model/vnd.gdl',
        'gdoc' => 'application/vnd.google-apps.document',
        'ged' => 'text/vnd.familysearch.gedcom',
        'geo' => 'application/vnd.dynageo',
        'geojson' => 'application/geo+json',
        'gex' => 'application/vnd.geometry-explorer',
        'ggb' => 'application/vnd.geogebra.file',
        'ggt' => 'application/vnd.geogebra.tool',
        'ghf' => 'application/vnd.groove-help',
        'gif' => 'image/gif',
        'gim' => 'application/vnd.groove-identity-message',
        'glb' => 'model/gltf-binary',
        'gltf' => 'model/gltf+json',
        'gml' => 'application/gml+xml',
        'gmx' => 'application/vnd.gmx',
        'gnumeric' => 'application/x-gnumeric',
        'gpg' => 'application/gpg-keys',
        'gph' => 'application/vnd.flographit',
        'gpx' => 'application/gpx+xml',
        'gqf' => 'application/vnd.grafeq',
        'gqs' => 'application/vnd.grafeq',
        'gram' => 'application/srgs',
        'gramps' => 'application/x-gramps-xml',
        'gre' => 'application/vnd.geometry-explorer',
        'grv' => 'application/vnd.groove-injector',
        'grxml' => 'application/srgs+xml',
        'gsf' => 'application/x-font-ghostscript',
        'gsheet' => 'application/vnd.google-apps.spreadsheet',
        'gslides' => 'application/vnd.google-apps.presentation',
        'gtar' => 'application/x-gtar',
        'gtm' => 'application/vnd.groove-tool-message',
        'gtw' => 'model/vnd.gtw',
        'gv' => 'text/vnd.graphviz',
        'gxf' => 'application/gxf',
        'gxt' => 'application/vnd.geonext',
        'gz' => 'application/gzip',
        'gzip' => 'application/gzip',
        'h' => 'text/x-c',
        'h261' => 'video/h261',
        'h263' => 'video/h263',
        'h264' => 'video/h264',
        'hal' => 'application/vnd.hal+xml',
        'hbci' => 'application/vnd.hbci',
        'hbs' => 'text/x-handlebars-template',
        'hdd' => 'application/x-virtualbox-hdd',
        'hdf' => 'application/x-hdf',
        'heic' => 'image/heic',
        'heics' => 'image/heic-sequence',
        'heif' => 'image/heif',
        'heifs' => 'image/heif-sequence',
        'hej2' => 'image/hej2k',
        'held' => 'application/atsc-held+xml',
        'hh' => 'text/x-c',
        'hjson' => 'application/hjson',
        'hlp' => 'application/winhlp',
        'hpgl' => 'application/vnd.hp-hpgl',
        'hpid' => 'application/vnd.hp-hpid',
        'hps' => 'application/vnd.hp-hps',
        'hqx' => 'application/mac-binhex40',
        'hsj2' => 'image/hsj2',
        'htc' => 'text/x-component',
        'htke' => 'application/vnd.kenameaapp',
        'htm' => 'text/html',
        'html' => 'text/html',
        'hvd' => 'application/vnd.yamaha.hv-dic',
        'hvp' => 'application/vnd.yamaha.hv-voice',
        'hvs' => 'application/vnd.yamaha.hv-script',
        'i2g' => 'application/vnd.intergeo',
        'icc' => 'application/vnd.iccprofile',
        'ice' => 'x-conference/x-cooltalk',
        'icm' => 'application/vnd.iccprofile',
        'ico' => 'image/x-icon',
        'ics' => 'text/calendar',
        'ief' => 'image/ief',
        'ifb' => 'text/calendar',
        'ifm' => 'application/vnd.shana.informed.formdata',
        'iges' => 'model/iges',
        'igl' => 'application/vnd.igloader',
        'igm' => 'application/vnd.insors.igm',
        'igs' => 'model/iges',
        'igx' => 'application/vnd.micrografx.igx',
        'iif' => 'application/vnd.shana.informed.interchange',
        'img' => 'application/octet-stream',
        'imp' => 'application/vnd.accpac.simply.imp',
        'ims' => 'application/vnd.ms-ims',
        'in' => 'text/plain',
        'ini' => 'text/plain',
        'ink' => 'application/inkml+xml',
        'inkml' => 'application/inkml+xml',
        'install' => 'application/x-install-instructions',
        'iota' => 'application/vnd.astraea-software.iota',
        'ipfix' => 'application/ipfix',
        'ipk' => 'application/vnd.shana.informed.package',
        'irm' => 'application/vnd.ibm.rights-management',
        'irp' => 'application/vnd.irepository.package+xml',
        'iso' => 'application/x-iso9660-image',
        'itp' => 'application/vnd.shana.informed.formtemplate',
        'its' => 'application/its+xml',
        'ivp' => 'application/vnd.immervision-ivp',
        'ivu' => 'application/vnd.immervision-ivu',
        'jad' => 'text/vnd.sun.j2me.app-descriptor',
        'jade' => 'text/jade',
        'jam' => 'application/vnd.jam',
        'jar' => 'application/java-archive',
        'jardiff' => 'application/x-java-archive-diff',
        'java' => 'text/x-java-source',
        'jhc' => 'image/jphc',
        'jisp' => 'application/vnd.jisp',
        'jls' => 'image/jls',
        'jlt' => 'application/vnd.hp-jlyt',
        'jng' => 'image/x-jng',
        'jnlp' => 'application/x-java-jnlp-file',
        'joda' => 'application/vnd.joost.joda-archive',
        'jp2' => 'image/jp2',
        'jpe' => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'jpf' => 'image/jpx',
        'jpg' => 'image/jpeg',
        'jpg2' => 'image/jp2',
        'jpgm' => 'video/jpm',
        'jpgv' => 'video/jpeg',
        'jph' => 'image/jph',
        'jpm' => 'video/jpm',
        'jpx' => 'image/jpx',
        'js' => 'application/javascript',
        'json' => 'application/json',
        'json5' => 'application/json5',
        'jsonld' => 'application/ld+json',
        'jsonml' => 'application/jsonml+json',
        'jsx' => 'text/jsx',
        'jt' => 'model/jt',
        'jxr' => 'image/jxr',
        'jxra' => 'image/jxra',
        'jxrs' => 'image/jxrs',
        'jxs' => 'image/jxs',
        'jxsc' => 'image/jxsc',
        'jxsi' => 'image/jxsi',
        'jxss' => 'image/jxss',
        'kar' => 'audio/midi',
        'karbon' => 'application/vnd.kde.karbon',
        'kdb' => 'application/octet-stream',
        'kdbx' => 'application/x-keepass2',
        'key' => 'application/x-iwork-keynote-sffkey',
        'kfo' => 'application/vnd.kde.kformula',
        'kia' => 'application/vnd.kidspiration',
        'kml' => 'application/vnd.google-earth.kml+xml',
        'kmz' => 'application/vnd.google-earth.kmz',
        'kne' => 'application/vnd.kinar',
        'knp' => 'application/vnd.kinar',
        'kon' => 'application/vnd.kde.kontour',
        'kpr' => 'application/vnd.kde.kpresenter',
        'kpt' => 'application/vnd.kde.kpresenter',
        'kpxx' => 'application/vnd.ds-keypoint',
        'ksp' => 'application/vnd.kde.kspread',
        'ktr' => 'application/vnd.kahootz',
        'ktx' => 'image/ktx',
        'ktx2' => 'image/ktx2',
        'ktz' => 'application/vnd.kahootz',
        'kwd' => 'application/vnd.kde.kword',
        'kwt' => 'application/vnd.kde.kword',
        'lasxml' => 'application/vnd.las.las+xml',
        'latex' => 'application/x-latex',
        'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
        'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
        'les' => 'application/vnd.hhe.lesson-player',
        'less' => 'text/less',
        'lgr' => 'application/lgr+xml',
        'lha' => 'application/octet-stream',
        'link66' => 'application/vnd.route66.link66+xml',
        'list' => 'text/plain',
        'list3820' => 'application/vnd.ibm.modcap',
        'listafp' => 'application/vnd.ibm.modcap',
        'litcoffee' => 'text/coffeescript',
        'lnk' => 'application/x-ms-shortcut',
        'log' => 'text/plain',
        'lostxml' => 'application/lost+xml',
        'lrf' => 'application/octet-stream',
        'lrm' => 'application/vnd.ms-lrm',
        'ltf' => 'application/vnd.frogans.ltf',
        'lua' => 'text/x-lua',
        'luac' => 'application/x-lua-bytecode',
        'lvp' => 'audio/vnd.lucent.voice',
        'lwp' => 'application/vnd.lotus-wordpro',
        'lzh' => 'application/octet-stream',
        'm1v' => 'video/mpeg',
        'm2a' => 'audio/mpeg',
        'm2v' => 'video/mpeg',
        'm3a' => 'audio/mpeg',
        'm3u' => 'text/plain',
        'm3u8' => 'application/vnd.apple.mpegurl',
        'm4a' => 'audio/x-m4a',
        'm4p' => 'application/mp4',
        'm4s' => 'video/iso.segment',
        'm4u' => 'application/vnd.mpegurl',
        'm4v' => 'video/x-m4v',
        'm13' => 'application/x-msmediaview',
        'm14' => 'application/x-msmediaview',
        'm21' => 'application/mp21',
        'ma' => 'application/mathematica',
        'mads' => 'application/mads+xml',
        'maei' => 'application/mmt-aei+xml',
        'mag' => 'application/vnd.ecowin.chart',
        'maker' => 'application/vnd.framemaker',
        'man' => 'text/troff',
        'manifest' => 'text/cache-manifest',
        'map' => 'application/json',
        'mar' => 'application/octet-stream',
        'markdown' => 'text/markdown',
        'mathml' => 'application/mathml+xml',
        'mb' => 'application/mathematica',
        'mbk' => 'application/vnd.mobius.mbk',
        'mbox' => 'application/mbox',
        'mc1' => 'application/vnd.medcalcdata',
        'mcd' => 'application/vnd.mcd',
        'mcurl' => 'text/vnd.curl.mcurl',
        'md' => 'text/markdown',
        'mdb' => 'application/x-msaccess',
        'mdi' => 'image/vnd.ms-modi',
        'mdx' => 'text/mdx',
        'me' => 'text/troff',
        'mesh' => 'model/mesh',
        'meta4' => 'application/metalink4+xml',
        'metalink' => 'application/metalink+xml',
        'mets' => 'application/mets+xml',
        'mfm' => 'application/vnd.mfmp',
        'mft' => 'application/rpki-manifest',
        'mgp' => 'application/vnd.osgeo.mapguide.package',
        'mgz' => 'application/vnd.proteus.magazine',
        'mid' => 'audio/midi',
        'midi' => 'audio/midi',
        'mie' => 'application/x-mie',
        'mif' => 'application/vnd.mif',
        'mime' => 'message/rfc822',
        'mj2' => 'video/mj2',
        'mjp2' => 'video/mj2',
        'mjs' => 'text/javascript',
        'mk3d' => 'video/x-matroska',
        'mka' => 'audio/x-matroska',
        'mkd' => 'text/x-markdown',
        'mks' => 'video/x-matroska',
        'mkv' => 'video/x-matroska',
        'mlp' => 'application/vnd.dolby.mlp',
        'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
        'mmf' => 'application/vnd.smaf',
        'mml' => 'text/mathml',
        'mmr' => 'image/vnd.fujixerox.edmics-mmr',
        'mng' => 'video/x-mng',
        'mny' => 'application/x-msmoney',
        'mobi' => 'application/x-mobipocket-ebook',
        'mods' => 'application/mods+xml',
        'mov' => 'video/quicktime',
        'movie' => 'video/x-sgi-movie',
        'mp2' => 'audio/mpeg',
        'mp2a' => 'audio/mpeg',
        'mp3' => 'audio/mpeg',
        'mp4' => 'video/mp4',
        'mp4a' => 'audio/mp4',
        'mp4s' => 'application/mp4',
        'mp4v' => 'video/mp4',
        'mp21' => 'application/mp21',
        'mpc' => 'application/vnd.mophun.certificate',
        'mpd' => 'application/dash+xml',
        'mpe' => 'video/mpeg',
        'mpeg' => 'video/mpeg',
        'mpf' => 'application/media-policy-dataset+xml',
        'mpg' => 'video/mpeg',
        'mpg4' => 'video/mp4',
        'mpga' => 'audio/mpeg',
        'mpkg' => 'application/vnd.apple.installer+xml',
        'mpm' => 'application/vnd.blueice.multipass',
        'mpn' => 'application/vnd.mophun.application',
        'mpp' => 'application/vnd.ms-project',
        'mpt' => 'application/vnd.ms-project',
        'mpy' => 'application/vnd.ibm.minipay',
        'mqy' => 'application/vnd.mobius.mqy',
        'mrc' => 'application/marc',
        'mrcx' => 'application/marcxml+xml',
        'ms' => 'text/troff',
        'mscml' => 'application/mediaservercontrol+xml',
        'mseed' => 'application/vnd.fdsn.mseed',
        'mseq' => 'application/vnd.mseq',
        'msf' => 'application/vnd.epson.msf',
        'msg' => 'application/vnd.ms-outlook',
        'msh' => 'model/mesh',
        'msi' => 'application/x-msdownload',
        'msix' => 'application/msix',
        'msixbundle' => 'application/msixbundle',
        'msl' => 'application/vnd.mobius.msl',
        'msm' => 'application/octet-stream',
        'msp' => 'application/octet-stream',
        'msty' => 'application/vnd.muvee.style',
        'mtl' => 'model/mtl',
        'mts' => 'model/vnd.mts',
        'mus' => 'application/vnd.musician',
        'musd' => 'application/mmt-usd+xml',
        'musicxml' => 'application/vnd.recordare.musicxml+xml',
        'mvb' => 'application/x-msmediaview',
        'mvt' => 'application/vnd.mapbox-vector-tile',
        'mwf' => 'application/vnd.mfer',
        'mxf' => 'application/mxf',
        'mxl' => 'application/vnd.recordare.musicxml',
        'mxmf' => 'audio/mobile-xmf',
        'mxml' => 'application/xv+xml',
        'mxs' => 'application/vnd.triscape.mxs',
        'mxu' => 'video/vnd.mpegurl',
        'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
        'n3' => 'text/n3',
        'nb' => 'application/mathematica',
        'nbp' => 'application/vnd.wolfram.player',
        'nc' => 'application/x-netcdf',
        'ncx' => 'application/x-dtbncx+xml',
        'nfo' => 'text/x-nfo',
        'ngdat' => 'application/vnd.nokia.n-gage.data',
        'nitf' => 'application/vnd.nitf',
        'nlu' => 'application/vnd.neurolanguage.nlu',
        'nml' => 'application/vnd.enliven',
        'nnd' => 'application/vnd.noblenet-directory',
        'nns' => 'application/vnd.noblenet-sealer',
        'nnw' => 'application/vnd.noblenet-web',
        'npx' => 'image/vnd.net-fpx',
        'nq' => 'application/n-quads',
        'nsc' => 'application/x-conference',
        'nsf' => 'application/vnd.lotus-notes',
        'nt' => 'application/n-triples',
        'ntf' => 'application/vnd.nitf',
        'numbers' => 'application/x-iwork-numbers-sffnumbers',
        'nzb' => 'application/x-nzb',
        'oa2' => 'application/vnd.fujitsu.oasys2',
        'oa3' => 'application/vnd.fujitsu.oasys3',
        'oas' => 'application/vnd.fujitsu.oasys',
        'obd' => 'application/x-msbinder',
        'obgx' => 'application/vnd.openblox.game+xml',
        'obj' => 'model/obj',
        'oda' => 'application/oda',
        'odb' => 'application/vnd.oasis.opendocument.database',
        'odc' => 'application/vnd.oasis.opendocument.chart',
        'odf' => 'application/vnd.oasis.opendocument.formula',
        'odft' => 'application/vnd.oasis.opendocument.formula-template',
        'odg' => 'application/vnd.oasis.opendocument.graphics',
        'odi' => 'application/vnd.oasis.opendocument.image',
        'odm' => 'application/vnd.oasis.opendocument.text-master',
        'odp' => 'application/vnd.oasis.opendocument.presentation',
        'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
        'odt' => 'application/vnd.oasis.opendocument.text',
        'oga' => 'audio/ogg',
        'ogex' => 'model/vnd.opengex',
        'ogg' => 'audio/ogg',
        'ogv' => 'video/ogg',
        'ogx' => 'application/ogg',
        'omdoc' => 'application/omdoc+xml',
        'onepkg' => 'application/onenote',
        'onetmp' => 'application/onenote',
        'onetoc' => 'application/onenote',
        'onetoc2' => 'application/onenote',
        'opf' => 'application/oebps-package+xml',
        'opml' => 'text/x-opml',
        'oprc' => 'application/vnd.palm',
        'opus' => 'audio/ogg',
        'org' => 'text/x-org',
        'osf' => 'application/vnd.yamaha.openscoreformat',
        'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
        'osm' => 'application/vnd.openstreetmap.data+xml',
        'otc' => 'application/vnd.oasis.opendocument.chart-template',
        'otf' => 'font/otf',
        'otg' => 'application/vnd.oasis.opendocument.graphics-template',
        'oth' => 'application/vnd.oasis.opendocument.text-web',
        'oti' => 'application/vnd.oasis.opendocument.image-template',
        'otp' => 'application/vnd.oasis.opendocument.presentation-template',
        'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
        'ott' => 'application/vnd.oasis.opendocument.text-template',
        'ova' => 'application/x-virtualbox-ova',
        'ovf' => 'application/x-virtualbox-ovf',
        'owl' => 'application/rdf+xml',
        'oxps' => 'application/oxps',
        'oxt' => 'application/vnd.openofficeorg.extension',
        'p' => 'text/x-pascal',
        'p7a' => 'application/x-pkcs7-signature',
        'p7b' => 'application/x-pkcs7-certificates',
        'p7c' => 'application/pkcs7-mime',
        'p7m' => 'application/pkcs7-mime',
        'p7r' => 'application/x-pkcs7-certreqresp',
        'p7s' => 'application/pkcs7-signature',
        'p8' => 'application/pkcs8',
        'p10' => 'application/x-pkcs10',
        'p12' => 'application/x-pkcs12',
        'pac' => 'application/x-ns-proxy-autoconfig',
        'pages' => 'application/x-iwork-pages-sffpages',
        'pas' => 'text/x-pascal',
        'paw' => 'application/vnd.pawaafile',
        'pbd' => 'application/vnd.powerbuilder6',
        'pbm' => 'image/x-portable-bitmap',
        'pcap' => 'application/vnd.tcpdump.pcap',
        'pcf' => 'application/x-font-pcf',
        'pcl' => 'application/vnd.hp-pcl',
        'pclxl' => 'application/vnd.hp-pclxl',
        'pct' => 'image/x-pict',
        'pcurl' => 'application/vnd.curl.pcurl',
        'pcx' => 'image/x-pcx',
        'pdb' => 'application/x-pilot',
        'pde' => 'text/x-processing',
        'pdf' => 'application/pdf',
        'pem' => 'application/x-x509-user-cert',
        'pfa' => 'application/x-font-type1',
        'pfb' => 'application/x-font-type1',
        'pfm' => 'application/x-font-type1',
        'pfr' => 'application/font-tdpfr',
        'pfx' => 'application/x-pkcs12',
        'pgm' => 'image/x-portable-graymap',
        'pgn' => 'application/x-chess-pgn',
        'pgp' => 'application/pgp',
        'phar' => 'application/octet-stream',
        'php' => 'application/x-httpd-php',
        'php3' => 'application/x-httpd-php',
        'php4' => 'application/x-httpd-php',
        'phps' => 'application/x-httpd-php-source',
        'phtml' => 'application/x-httpd-php',
        'pic' => 'image/x-pict',
        'pkg' => 'application/octet-stream',
        'pki' => 'application/pkixcmp',
        'pkipath' => 'application/pkix-pkipath',
        'pkpass' => 'application/vnd.apple.pkpass',
        'pl' => 'application/x-perl',
        'plb' => 'application/vnd.3gpp.pic-bw-large',
        'plc' => 'application/vnd.mobius.plc',
        'plf' => 'application/vnd.pocketlearn',
        'pls' => 'application/pls+xml',
        'pm' => 'application/x-perl',
        'pml' => 'application/vnd.ctc-posml',
        'png' => 'image/png',
        'pnm' => 'image/x-portable-anymap',
        'portpkg' => 'application/vnd.macports.portpkg',
        'pot' => 'application/vnd.ms-powerpoint',
        'potm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
        'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
        'ppa' => 'application/vnd.ms-powerpoint',
        'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
        'ppd' => 'application/vnd.cups-ppd',
        'ppm' => 'image/x-portable-pixmap',
        'pps' => 'application/vnd.ms-powerpoint',
        'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
        'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
        'ppt' => 'application/powerpoint',
        'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
        'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        'pqa' => 'application/vnd.palm',
        'prc' => 'model/prc',
        'pre' => 'application/vnd.lotus-freelance',
        'prf' => 'application/pics-rules',
        'provx' => 'application/provenance+xml',
        'ps' => 'application/postscript',
        'psb' => 'application/vnd.3gpp.pic-bw-small',
        'psd' => 'application/x-photoshop',
        'psf' => 'application/x-font-linux-psf',
        'pskcxml' => 'application/pskc+xml',
        'pti' => 'image/prs.pti',
        'ptid' => 'application/vnd.pvi.ptid1',
        'pub' => 'application/x-mspublisher',
        'pvb' => 'application/vnd.3gpp.pic-bw-var',
        'pwn' => 'application/vnd.3m.post-it-notes',
        'pya' => 'audio/vnd.ms-playready.media.pya',
        'pyo' => 'model/vnd.pytha.pyox',
        'pyox' => 'model/vnd.pytha.pyox',
        'pyv' => 'video/vnd.ms-playready.media.pyv',
        'qam' => 'application/vnd.epson.quickanime',
        'qbo' => 'application/vnd.intu.qbo',
        'qfx' => 'application/vnd.intu.qfx',
        'qps' => 'application/vnd.publishare-delta-tree',
        'qt' => 'video/quicktime',
        'qwd' => 'application/vnd.quark.quarkxpress',
        'qwt' => 'application/vnd.quark.quarkxpress',
        'qxb' => 'application/vnd.quark.quarkxpress',
        'qxd' => 'application/vnd.quark.quarkxpress',
        'qxl' => 'application/vnd.quark.quarkxpress',
        'qxt' => 'application/vnd.quark.quarkxpress',
        'ra' => 'audio/x-realaudio',
        'ram' => 'audio/x-pn-realaudio',
        'raml' => 'application/raml+yaml',
        'rapd' => 'application/route-apd+xml',
        'rar' => 'application/x-rar',
        'ras' => 'image/x-cmu-raster',
        'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
        'rdf' => 'application/rdf+xml',
        'rdz' => 'application/vnd.data-vision.rdz',
        'relo' => 'application/p2p-overlay+xml',
        'rep' => 'application/vnd.businessobjects',
        'res' => 'application/x-dtbresource+xml',
        'rgb' => 'image/x-rgb',
        'rif' => 'application/reginfo+xml',
        'rip' => 'audio/vnd.rip',
        'ris' => 'application/x-research-info-systems',
        'rl' => 'application/resource-lists+xml',
        'rlc' => 'image/vnd.fujixerox.edmics-rlc',
        'rld' => 'application/resource-lists-diff+xml',
        'rm' => 'audio/x-pn-realaudio',
        'rmi' => 'audio/midi',
        'rmp' => 'audio/x-pn-realaudio-plugin',
        'rms' => 'application/vnd.jcp.javame.midlet-rms',
        'rmvb' => 'application/vnd.rn-realmedia-vbr',
        'rnc' => 'application/relax-ng-compact-syntax',
        'rng' => 'application/xml',
        'roa' => 'application/rpki-roa',
        'roff' => 'text/troff',
        'rp9' => 'application/vnd.cloanto.rp9',
        'rpm' => 'audio/x-pn-realaudio-plugin',
        'rpss' => 'application/vnd.nokia.radio-presets',
        'rpst' => 'application/vnd.nokia.radio-preset',
        'rq' => 'application/sparql-query',
        'rs' => 'application/rls-services+xml',
        'rsa' => 'application/x-pkcs7',
        'rsat' => 'application/atsc-rsat+xml',
        'rsd' => 'application/rsd+xml',
        'rsheet' => 'application/urc-ressheet+xml',
        'rss' => 'application/rss+xml',
        'rtf' => 'text/rtf',
        'rtx' => 'text/richtext',
        'run' => 'application/x-makeself',
        'rusd' => 'application/route-usd+xml',
        'rv' => 'video/vnd.rn-realvideo',
        's' => 'text/x-asm',
        's3m' => 'audio/s3m',
        'saf' => 'application/vnd.yamaha.smaf-audio',
        'sass' => 'text/x-sass',
        'sbml' => 'application/sbml+xml',
        'sc' => 'application/vnd.ibm.secure-container',
        'scd' => 'application/x-msschedule',
        'scm' => 'application/vnd.lotus-screencam',
        'scq' => 'application/scvp-cv-request',
        'scs' => 'application/scvp-cv-response',
        'scss' => 'text/x-scss',
        'scurl' => 'text/vnd.curl.scurl',
        'sda' => 'application/vnd.stardivision.draw',
        'sdc' => 'application/vnd.stardivision.calc',
        'sdd' => 'application/vnd.stardivision.impress',
        'sdkd' => 'application/vnd.solent.sdkm+xml',
        'sdkm' => 'application/vnd.solent.sdkm+xml',
        'sdp' => 'application/sdp',
        'sdw' => 'application/vnd.stardivision.writer',
        'sea' => 'application/octet-stream',
        'see' => 'application/vnd.seemail',
        'seed' => 'application/vnd.fdsn.seed',
        'sema' => 'application/vnd.sema',
        'semd' => 'application/vnd.semd',
        'semf' => 'application/vnd.semf',
        'senmlx' => 'application/senml+xml',
        'sensmlx' => 'application/sensml+xml',
        'ser' => 'application/java-serialized-object',
        'setpay' => 'application/set-payment-initiation',
        'setreg' => 'application/set-registration-initiation',
        'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
        'sfs' => 'application/vnd.spotfire.sfs',
        'sfv' => 'text/x-sfv',
        'sgi' => 'image/sgi',
        'sgl' => 'application/vnd.stardivision.writer-global',
        'sgm' => 'text/sgml',
        'sgml' => 'text/sgml',
        'sh' => 'application/x-sh',
        'shar' => 'application/x-shar',
        'shex' => 'text/shex',
        'shf' => 'application/shf+xml',
        'shtml' => 'text/html',
        'sid' => 'image/x-mrsid-image',
        'sieve' => 'application/sieve',
        'sig' => 'application/pgp-signature',
        'sil' => 'audio/silk',
        'silo' => 'model/mesh',
        'sis' => 'application/vnd.symbian.install',
        'sisx' => 'application/vnd.symbian.install',
        'sit' => 'application/x-stuffit',
        'sitx' => 'application/x-stuffitx',
        'siv' => 'application/sieve',
        'skd' => 'application/vnd.koan',
        'skm' => 'application/vnd.koan',
        'skp' => 'application/vnd.koan',
        'skt' => 'application/vnd.koan',
        'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
        'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
        'slim' => 'text/slim',
        'slm' => 'text/slim',
        'sls' => 'application/route-s-tsid+xml',
        'slt' => 'application/vnd.epson.salt',
        'sm' => 'application/vnd.stepmania.stepchart',
        'smf' => 'application/vnd.stardivision.math',
        'smi' => 'application/smil',
        'smil' => 'application/smil',
        'smv' => 'video/x-smv',
        'smzip' => 'application/vnd.stepmania.package',
        'snd' => 'audio/basic',
        'snf' => 'application/x-font-snf',
        'so' => 'application/octet-stream',
        'spc' => 'application/x-pkcs7-certificates',
        'spdx' => 'text/spdx',
        'spf' => 'application/vnd.yamaha.smaf-phrase',
        'spl' => 'application/x-futuresplash',
        'spot' => 'text/vnd.in3d.spot',
        'spp' => 'application/scvp-vp-response',
        'spq' => 'application/scvp-vp-request',
        'spx' => 'audio/ogg',
        'sql' => 'application/x-sql',
        'src' => 'application/x-wais-source',
        'srt' => 'application/x-subrip',
        'sru' => 'application/sru+xml',
        'srx' => 'application/sparql-results+xml',
        'ssdl' => 'application/ssdl+xml',
        'sse' => 'application/vnd.kodak-descriptor',
        'ssf' => 'application/vnd.epson.ssf',
        'ssml' => 'application/ssml+xml',
        'sst' => 'application/octet-stream',
        'st' => 'application/vnd.sailingtracker.track',
        'stc' => 'application/vnd.sun.xml.calc.template',
        'std' => 'application/vnd.sun.xml.draw.template',
        'step' => 'application/STEP',
        'stf' => 'application/vnd.wt.stf',
        'sti' => 'application/vnd.sun.xml.impress.template',
        'stk' => 'application/hyperstudio',
        'stl' => 'model/stl',
        'stp' => 'application/STEP',
        'stpx' => 'model/step+xml',
        'stpxz' => 'model/step-xml+zip',
        'stpz' => 'model/step+zip',
        'str' => 'application/vnd.pg.format',
        'stw' => 'application/vnd.sun.xml.writer.template',
        'styl' => 'text/stylus',
        'stylus' => 'text/stylus',
        'sub' => 'text/vnd.dvb.subtitle',
        'sus' => 'application/vnd.sus-calendar',
        'susp' => 'application/vnd.sus-calendar',
        'sv4cpio' => 'application/x-sv4cpio',
        'sv4crc' => 'application/x-sv4crc',
        'svc' => 'application/vnd.dvb.service',
        'svd' => 'application/vnd.svd',
        'svg' => 'image/svg+xml',
        'svgz' => 'image/svg+xml',
        'swa' => 'application/x-director',
        'swf' => 'application/x-shockwave-flash',
        'swi' => 'application/vnd.aristanetworks.swi',
        'swidtag' => 'application/swid+xml',
        'sxc' => 'application/vnd.sun.xml.calc',
        'sxd' => 'application/vnd.sun.xml.draw',
        'sxg' => 'application/vnd.sun.xml.writer.global',
        'sxi' => 'application/vnd.sun.xml.impress',
        'sxm' => 'application/vnd.sun.xml.math',
        'sxw' => 'application/vnd.sun.xml.writer',
        't' => 'text/troff',
        't3' => 'application/x-t3vm-image',
        't38' => 'image/t38',
        'taglet' => 'application/vnd.mynfc',
        'tao' => 'application/vnd.tao.intent-module-archive',
        'tap' => 'image/vnd.tencent.tap',
        'tar' => 'application/x-tar',
        'tcap' => 'application/vnd.3gpp2.tcap',
        'tcl' => 'application/x-tcl',
        'td' => 'application/urc-targetdesc+xml',
        'teacher' => 'application/vnd.smart.teacher',
        'tei' => 'application/tei+xml',
        'teicorpus' => 'application/tei+xml',
        'tex' => 'application/x-tex',
        'texi' => 'application/x-texinfo',
        'texinfo' => 'application/x-texinfo',
        'text' => 'text/plain',
        'tfi' => 'application/thraud+xml',
        'tfm' => 'application/x-tex-tfm',
        'tfx' => 'image/tiff-fx',
        'tga' => 'image/x-tga',
        'tgz' => 'application/x-tar',
        'thmx' => 'application/vnd.ms-officetheme',
        'tif' => 'image/tiff',
        'tiff' => 'image/tiff',
        'tk' => 'application/x-tcl',
        'tmo' => 'application/vnd.tmobile-livetv',
        'toml' => 'application/toml',
        'torrent' => 'application/x-bittorrent',
        'tpl' => 'application/vnd.groove-tool-template',
        'tpt' => 'application/vnd.trid.tpt',
        'tr' => 'text/troff',
        'tra' => 'application/vnd.trueapp',
        'trig' => 'application/trig',
        'trm' => 'application/x-msterminal',
        'ts' => 'video/mp2t',
        'tsd' => 'application/timestamped-data',
        'tsv' => 'text/tab-separated-values',
        'ttc' => 'font/collection',
        'ttf' => 'font/ttf',
        'ttl' => 'text/turtle',
        'ttml' => 'application/ttml+xml',
        'twd' => 'application/vnd.simtech-mindmapper',
        'twds' => 'application/vnd.simtech-mindmapper',
        'txd' => 'application/vnd.genomatix.tuxedo',
        'txf' => 'application/vnd.mobius.txf',
        'txt' => 'text/plain',
        'u3d' => 'model/u3d',
        'u8dsn' => 'message/global-delivery-status',
        'u8hdr' => 'message/global-headers',
        'u8mdn' => 'message/global-disposition-notification',
        'u8msg' => 'message/global',
        'u32' => 'application/x-authorware-bin',
        'ubj' => 'application/ubjson',
        'udeb' => 'application/x-debian-package',
        'ufd' => 'application/vnd.ufdl',
        'ufdl' => 'application/vnd.ufdl',
        'ulx' => 'application/x-glulx',
        'umj' => 'application/vnd.umajin',
        'unityweb' => 'application/vnd.unity',
        'uo' => 'application/vnd.uoml+xml',
        'uoml' => 'application/vnd.uoml+xml',
        'uri' => 'text/uri-list',
        'uris' => 'text/uri-list',
        'urls' => 'text/uri-list',
        'usda' => 'model/vnd.usda',
        'usdz' => 'model/vnd.usdz+zip',
        'ustar' => 'application/x-ustar',
        'utz' => 'application/vnd.uiq.theme',
        'uu' => 'text/x-uuencode',
        'uva' => 'audio/vnd.dece.audio',
        'uvd' => 'application/vnd.dece.data',
        'uvf' => 'application/vnd.dece.data',
        'uvg' => 'image/vnd.dece.graphic',
        'uvh' => 'video/vnd.dece.hd',
        'uvi' => 'image/vnd.dece.graphic',
        'uvm' => 'video/vnd.dece.mobile',
        'uvp' => 'video/vnd.dece.pd',
        'uvs' => 'video/vnd.dece.sd',
        'uvt' => 'application/vnd.dece.ttml+xml',
        'uvu' => 'video/vnd.uvvu.mp4',
        'uvv' => 'video/vnd.dece.video',
        'uvva' => 'audio/vnd.dece.audio',
        'uvvd' => 'application/vnd.dece.data',
        'uvvf' => 'application/vnd.dece.data',
        'uvvg' => 'image/vnd.dece.graphic',
        'uvvh' => 'video/vnd.dece.hd',
        'uvvi' => 'image/vnd.dece.graphic',
        'uvvm' => 'video/vnd.dece.mobile',
        'uvvp' => 'video/vnd.dece.pd',
        'uvvs' => 'video/vnd.dece.sd',
        'uvvt' => 'application/vnd.dece.ttml+xml',
        'uvvu' => 'video/vnd.uvvu.mp4',
        'uvvv' => 'video/vnd.dece.video',
        'uvvx' => 'application/vnd.dece.unspecified',
        'uvvz' => 'application/vnd.dece.zip',
        'uvx' => 'application/vnd.dece.unspecified',
        'uvz' => 'application/vnd.dece.zip',
        'vbox' => 'application/x-virtualbox-vbox',
        'vbox-extpack' => 'application/x-virtualbox-vbox-extpack',
        'vcard' => 'text/vcard',
        'vcd' => 'application/x-cdlink',
        'vcf' => 'text/x-vcard',
        'vcg' => 'application/vnd.groove-vcard',
        'vcs' => 'text/x-vcalendar',
        'vcx' => 'application/vnd.vcx',
        'vdi' => 'application/x-virtualbox-vdi',
        'vds' => 'model/vnd.sap.vds',
        'vhd' => 'application/x-virtualbox-vhd',
        'vis' => 'application/vnd.visionary',
        'viv' => 'video/vnd.vivo',
        'vlc' => 'application/videolan',
        'vmdk' => 'application/x-virtualbox-vmdk',
        'vob' => 'video/x-ms-vob',
        'vor' => 'application/vnd.stardivision.writer',
        'vox' => 'application/x-authorware-bin',
        'vrml' => 'model/vrml',
        'vsd' => 'application/vnd.visio',
        'vsf' => 'application/vnd.vsf',
        'vss' => 'application/vnd.visio',
        'vst' => 'application/vnd.visio',
        'vsw' => 'application/vnd.visio',
        'vtf' => 'image/vnd.valve.source.texture',
        'vtt' => 'text/vtt',
        'vtu' => 'model/vnd.vtu',
        'vxml' => 'application/voicexml+xml',
        'w3d' => 'application/x-director',
        'wad' => 'application/x-doom',
        'wadl' => 'application/vnd.sun.wadl+xml',
        'war' => 'application/java-archive',
        'wasm' => 'application/wasm',
        'wav' => 'audio/x-wav',
        'wax' => 'audio/x-ms-wax',
        'wbmp' => 'image/vnd.wap.wbmp',
        'wbs' => 'application/vnd.criticaltools.wbs+xml',
        'wbxml' => 'application/wbxml',
        'wcm' => 'application/vnd.ms-works',
        'wdb' => 'application/vnd.ms-works',
        'wdp' => 'image/vnd.ms-photo',
        'weba' => 'audio/webm',
        'webapp' => 'application/x-web-app-manifest+json',
        'webm' => 'video/webm',
        'webmanifest' => 'application/manifest+json',
        'webp' => 'image/webp',
        'wg' => 'application/vnd.pmi.widget',
        'wgsl' => 'text/wgsl',
        'wgt' => 'application/widget',
        'wif' => 'application/watcherinfo+xml',
        'wks' => 'application/vnd.ms-works',
        'wm' => 'video/x-ms-wm',
        'wma' => 'audio/x-ms-wma',
        'wmd' => 'application/x-ms-wmd',
        'wmf' => 'image/wmf',
        'wml' => 'text/vnd.wap.wml',
        'wmlc' => 'application/wmlc',
        'wmls' => 'text/vnd.wap.wmlscript',
        'wmlsc' => 'application/vnd.wap.wmlscriptc',
        'wmv' => 'video/x-ms-wmv',
        'wmx' => 'video/x-ms-wmx',
        'wmz' => 'application/x-msmetafile',
        'woff' => 'font/woff',
        'woff2' => 'font/woff2',
        'word' => 'application/msword',
        'wpd' => 'application/vnd.wordperfect',
        'wpl' => 'application/vnd.ms-wpl',
        'wps' => 'application/vnd.ms-works',
        'wqd' => 'application/vnd.wqd',
        'wri' => 'application/x-mswrite',
        'wrl' => 'model/vrml',
        'wsc' => 'message/vnd.wfa.wsc',
        'wsdl' => 'application/wsdl+xml',
        'wspolicy' => 'application/wspolicy+xml',
        'wtb' => 'application/vnd.webturbo',
        'wvx' => 'video/x-ms-wvx',
        'x3d' => 'model/x3d+xml',
        'x3db' => 'model/x3d+fastinfoset',
        'x3dbz' => 'model/x3d+binary',
        'x3dv' => 'model/x3d-vrml',
        'x3dvz' => 'model/x3d+vrml',
        'x3dz' => 'model/x3d+xml',
        'x32' => 'application/x-authorware-bin',
        'x_b' => 'model/vnd.parasolid.transmit.binary',
        'x_t' => 'model/vnd.parasolid.transmit.text',
        'xaml' => 'application/xaml+xml',
        'xap' => 'application/x-silverlight-app',
        'xar' => 'application/vnd.xara',
        'xav' => 'application/xcap-att+xml',
        'xbap' => 'application/x-ms-xbap',
        'xbd' => 'application/vnd.fujixerox.docuworks.binder',
        'xbm' => 'image/x-xbitmap',
        'xca' => 'application/xcap-caps+xml',
        'xcs' => 'application/calendar+xml',
        'xdf' => 'application/xcap-diff+xml',
        'xdm' => 'application/vnd.syncml.dm+xml',
        'xdp' => 'application/vnd.adobe.xdp+xml',
        'xdssc' => 'application/dssc+xml',
        'xdw' => 'application/vnd.fujixerox.docuworks',
        'xel' => 'application/xcap-el+xml',
        'xenc' => 'application/xenc+xml',
        'xer' => 'application/patch-ops-error+xml',
        'xfdf' => 'application/xfdf',
        'xfdl' => 'application/vnd.xfdl',
        'xht' => 'application/xhtml+xml',
        'xhtm' => 'application/vnd.pwg-xhtml-print+xml',
        'xhtml' => 'application/xhtml+xml',
        'xhvml' => 'application/xv+xml',
        'xif' => 'image/vnd.xiff',
        'xl' => 'application/excel',
        'xla' => 'application/vnd.ms-excel',
        'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
        'xlc' => 'application/vnd.ms-excel',
        'xlf' => 'application/xliff+xml',
        'xlm' => 'application/vnd.ms-excel',
        'xls' => 'application/vnd.ms-excel',
        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
        'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'xlt' => 'application/vnd.ms-excel',
        'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
        'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
        'xlw' => 'application/vnd.ms-excel',
        'xm' => 'audio/xm',
        'xml' => 'application/xml',
        'xns' => 'application/xcap-ns+xml',
        'xo' => 'application/vnd.olpc-sugar',
        'xop' => 'application/xop+xml',
        'xpi' => 'application/x-xpinstall',
        'xpl' => 'application/xproc+xml',
        'xpm' => 'image/x-xpixmap',
        'xpr' => 'application/vnd.is-xpr',
        'xps' => 'application/vnd.ms-xpsdocument',
        'xpw' => 'application/vnd.intercon.formnet',
        'xpx' => 'application/vnd.intercon.formnet',
        'xsd' => 'application/xml',
        'xsf' => 'application/prs.xsf+xml',
        'xsl' => 'application/xml',
        'xslt' => 'application/xslt+xml',
        'xsm' => 'application/vnd.syncml+xml',
        'xspf' => 'application/xspf+xml',
        'xul' => 'application/vnd.mozilla.xul+xml',
        'xvm' => 'application/xv+xml',
        'xvml' => 'application/xv+xml',
        'xwd' => 'image/x-xwindowdump',
        'xyz' => 'chemical/x-xyz',
        'xz' => 'application/x-xz',
        'yaml' => 'text/yaml',
        'yang' => 'application/yang',
        'yin' => 'application/yin+xml',
        'yml' => 'text/yaml',
        'ymp' => 'text/x-suse-ymp',
        'z' => 'application/x-compress',
        'z1' => 'application/x-zmachine',
        'z2' => 'application/x-zmachine',
        'z3' => 'application/x-zmachine',
        'z4' => 'application/x-zmachine',
        'z5' => 'application/x-zmachine',
        'z6' => 'application/x-zmachine',
        'z7' => 'application/x-zmachine',
        'z8' => 'application/x-zmachine',
        'zaz' => 'application/vnd.zzazz.deck+xml',
        'zip' => 'application/zip',
        'zir' => 'application/vnd.zul',
        'zirz' => 'application/vnd.zul',
        'zmm' => 'application/vnd.handheld-entertainment+xml',
        'zsh' => 'text/x-scriptzsh',
    ];

    /**
     * Determines the mimetype of a file by looking at its extension.
     *
     * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
     */
    public static function fromFilename(string $filename): ?string
    {
        return self::fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
    }

    /**
     * Maps a file extensions to a mimetype.
     *
     * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
     */
    public static function fromExtension(string $extension): ?string
    {
        return self::MIME_TYPES[strtolower($extension)] ?? null;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Stream that when read returns bytes for a streaming multipart or
 * multipart/form-data stream.
 */
final class MultipartStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var string */
    private $boundary;

    /** @var StreamInterface */
    private $stream;

    /**
     * @param array  $elements Array of associative arrays, each containing a
     *                         required "name" key mapping to the form field,
     *                         name, a required "contents" key mapping to a
     *                         StreamInterface/resource/string, an optional
     *                         "headers" associative array of custom headers,
     *                         and an optional "filename" key mapping to a
     *                         string to send as the filename in the part.
     * @param string $boundary You can optionally provide a specific boundary
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(array $elements = [], ?string $boundary = null)
    {
        $this->boundary = $boundary ?: bin2hex(random_bytes(20));
        $this->stream = $this->createStream($elements);
    }

    public function getBoundary(): string
    {
        return $this->boundary;
    }

    public function isWritable(): bool
    {
        return false;
    }

    /**
     * Get the headers needed before transferring the content of a POST file
     *
     * @param string[] $headers
     */
    private function getHeaders(array $headers): string
    {
        $str = '';
        foreach ($headers as $key => $value) {
            $str .= "{$key}: {$value}\r\n";
        }

        return "--{$this->boundary}\r\n".trim($str)."\r\n\r\n";
    }

    /**
     * Create the aggregate stream that will be used to upload the POST data
     */
    protected function createStream(array $elements = []): StreamInterface
    {
        $stream = new AppendStream();

        foreach ($elements as $element) {
            if (!is_array($element)) {
                throw new \UnexpectedValueException('An array is expected');
            }
            $this->addElement($stream, $element);
        }

        // Add the trailing boundary with CRLF
        $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));

        return $stream;
    }

    private function addElement(AppendStream $stream, array $element): void
    {
        foreach (['contents', 'name'] as $key) {
            if (!array_key_exists($key, $element)) {
                throw new \InvalidArgumentException("A '{$key}' key is required");
            }
        }

        $element['contents'] = Utils::streamFor($element['contents']);

        if (empty($element['filename'])) {
            $uri = $element['contents']->getMetadata('uri');
            if ($uri && \is_string($uri) && \substr($uri, 0, 6) !== 'php://' && \substr($uri, 0, 7) !== 'data://') {
                $element['filename'] = $uri;
            }
        }

        [$body, $headers] = $this->createElement(
            $element['name'],
            $element['contents'],
            $element['filename'] ?? null,
            $element['headers'] ?? []
        );

        $stream->addStream(Utils::streamFor($this->getHeaders($headers)));
        $stream->addStream($body);
        $stream->addStream(Utils::streamFor("\r\n"));
    }

    /**
     * @param string[] $headers
     *
     * @return array{0: StreamInterface, 1: string[]}
     */
    private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers): array
    {
        // Set a default content-disposition header if one was no provided
        $disposition = self::getHeader($headers, 'content-disposition');
        if (!$disposition) {
            $headers['Content-Disposition'] = ($filename === '0' || $filename)
                ? sprintf(
                    'form-data; name="%s"; filename="%s"',
                    $name,
                    basename($filename)
                )
                : "form-data; name=\"{$name}\"";
        }

        // Set a default content-length header if one was no provided
        $length = self::getHeader($headers, 'content-length');
        if (!$length) {
            if ($length = $stream->getSize()) {
                $headers['Content-Length'] = (string) $length;
            }
        }

        // Set a default Content-Type if one was not supplied
        $type = self::getHeader($headers, 'content-type');
        if (!$type && ($filename === '0' || $filename)) {
            $headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream';
        }

        return [$stream, $headers];
    }

    /**
     * @param string[] $headers
     */
    private static function getHeader(array $headers, string $key): ?string
    {
        $lowercaseHeader = strtolower($key);
        foreach ($headers as $k => $v) {
            if (strtolower((string) $k) === $lowercaseHeader) {
                return $v;
            }
        }

        return null;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Stream decorator that prevents a stream from being seeked.
 */
final class NoSeekStream implements StreamInterface
{
    use StreamDecoratorTrait;

    /** @var StreamInterface */
    private $stream;

    public function seek($offset, $whence = SEEK_SET): void
    {
        throw new \RuntimeException('Cannot seek a NoSeekStream');
    }

    public function isSeekable(): bool
    {
        return false;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Provides a read only stream that pumps data from a PHP callable.
 *
 * When invoking the provided callable, the PumpStream will pass the amount of
 * data requested to read to the callable. The callable can choose to ignore
 * this value and return fewer or more bytes than requested. Any extra data
 * returned by the provided callable is buffered internally until drained using
 * the read() function of the PumpStream. The provided callable MUST return
 * false when there is no more data to read.
 */
final class PumpStream implements StreamInterface
{
    /** @var callable(int): (string|false|null)|null */
    private $source;

    /** @var int|null */
    private $size;

    /** @var int */
    private $tellPos = 0;

    /** @var array */
    private $metadata;

    /** @var BufferStream */
    private $buffer;

    /**
     * @param callable(int): (string|false|null)  $source  Source of the stream data. The callable MAY
     *                                                     accept an integer argument used to control the
     *                                                     amount of data to return. The callable MUST
     *                                                     return a string when called, or false|null on error
     *                                                     or EOF.
     * @param array{size?: int, metadata?: array} $options Stream options:
     *                                                     - metadata: Hash of metadata to use with stream.
     *                                                     - size: Size of the stream, if known.
     */
    public function __construct(callable $source, array $options = [])
    {
        $this->source = $source;
        $this->size = $options['size'] ?? null;
        $this->metadata = $options['metadata'] ?? [];
        $this->buffer = new BufferStream();
    }

    public function __toString(): string
    {
        try {
            return Utils::copyToString($this);
        } catch (\Throwable $e) {
            if (\PHP_VERSION_ID >= 70400) {
                throw $e;
            }
            trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);

            return '';
        }
    }

    public function close(): void
    {
        $this->detach();
    }

    public function detach()
    {
        $this->tellPos = 0;
        $this->source = null;

        return null;
    }

    public function getSize(): ?int
    {
        return $this->size;
    }

    public function tell(): int
    {
        return $this->tellPos;
    }

    public function eof(): bool
    {
        return $this->source === null;
    }

    public function isSeekable(): bool
    {
        return false;
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        throw new \RuntimeException('Cannot seek a PumpStream');
    }

    public function isWritable(): bool
    {
        return false;
    }

    public function write($string): int
    {
        throw new \RuntimeException('Cannot write to a PumpStream');
    }

    public function isReadable(): bool
    {
        return true;
    }

    public function read($length): string
    {
        $data = $this->buffer->read($length);
        $readLen = strlen($data);
        $this->tellPos += $readLen;
        $remaining = $length - $readLen;

        if ($remaining) {
            $this->pump($remaining);
            $data .= $this->buffer->read($remaining);
            $this->tellPos += strlen($data) - $readLen;
        }

        return $data;
    }

    public function getContents(): string
    {
        $result = '';
        while (!$this->eof()) {
            $result .= $this->read(1000000);
        }

        return $result;
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        if (!$key) {
            return $this->metadata;
        }

        return $this->metadata[$key] ?? null;
    }

    private function pump(int $length): void
    {
        if ($this->source !== null) {
            do {
                $data = ($this->source)($length);
                if ($data === false || $data === null) {
                    $this->source = null;

                    return;
                }
                $this->buffer->write($data);
                $length -= strlen($data);
            } while ($length > 0);
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

final class Query
{
    /**
     * Parse a query string into an associative array.
     *
     * If multiple values are found for the same key, the value of that key
     * value pair will become an array. This function does not parse nested
     * PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`
     * will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
     *
     * @param string   $str         Query string to parse
     * @param int|bool $urlEncoding How the query string is encoded
     */
    public static function parse(string $str, $urlEncoding = true): array
    {
        $result = [];

        if ($str === '') {
            return $result;
        }

        if ($urlEncoding === true) {
            $decoder = function ($value) {
                return rawurldecode(str_replace('+', ' ', (string) $value));
            };
        } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
            $decoder = 'rawurldecode';
        } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
            $decoder = 'urldecode';
        } else {
            $decoder = function ($str) {
                return $str;
            };
        }

        foreach (explode('&', $str) as $kvp) {
            $parts = explode('=', $kvp, 2);
            $key = $decoder($parts[0]);
            $value = isset($parts[1]) ? $decoder($parts[1]) : null;
            if (!array_key_exists($key, $result)) {
                $result[$key] = $value;
            } else {
                if (!is_array($result[$key])) {
                    $result[$key] = [$result[$key]];
                }
                $result[$key][] = $value;
            }
        }

        return $result;
    }

    /**
     * Build a query string from an array of key value pairs.
     *
     * This function can use the return value of `parse()` to build a query
     * string. This function does not modify the provided keys when an array is
     * encountered (like `http_build_query()` would).
     *
     * @param array     $params           Query string parameters.
     * @param int|false $encoding         Set to false to not encode,
     *                                    PHP_QUERY_RFC3986 to encode using
     *                                    RFC3986, or PHP_QUERY_RFC1738 to
     *                                    encode using RFC1738.
     * @param bool      $treatBoolsAsInts Set to true to encode as 0/1, and
     *                                    false as false/true.
     */
    public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string
    {
        if (!$params) {
            return '';
        }

        if ($encoding === false) {
            $encoder = function (string $str): string {
                return $str;
            };
        } elseif ($encoding === PHP_QUERY_RFC3986) {
            $encoder = 'rawurlencode';
        } elseif ($encoding === PHP_QUERY_RFC1738) {
            $encoder = 'urlencode';
        } else {
            throw new \InvalidArgumentException('Invalid type');
        }

        $castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };

        $qs = '';
        foreach ($params as $k => $v) {
            $k = $encoder((string) $k);
            if (!is_array($v)) {
                $qs .= $k;
                $v = is_bool($v) ? $castBool($v) : $v;
                if ($v !== null) {
                    $qs .= '='.$encoder((string) $v);
                }
                $qs .= '&';
            } else {
                foreach ($v as $vv) {
                    $qs .= $k;
                    $vv = is_bool($vv) ? $castBool($vv) : $vv;
                    if ($vv !== null) {
                        $qs .= '='.$encoder((string) $vv);
                    }
                    $qs .= '&';
                }
            }
        }

        return $qs ? (string) substr($qs, 0, -1) : '';
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

/**
 * PSR-7 request implementation.
 */
class Request implements RequestInterface
{
    use MessageTrait;

    /** @var string */
    private $method;

    /** @var string|null */
    private $requestTarget;

    /** @var UriInterface */
    private $uri;

    /**
     * @param string                               $method  HTTP method
     * @param string|UriInterface                  $uri     URI
     * @param (string|string[])[]                  $headers Request headers
     * @param string|resource|StreamInterface|null $body    Request body
     * @param string                               $version Protocol version
     */
    public function __construct(
        string $method,
        $uri,
        array $headers = [],
        $body = null,
        string $version = '1.1'
    ) {
        $this->assertMethod($method);
        if (!($uri instanceof UriInterface)) {
            $uri = new Uri($uri);
        }

        $this->method = strtoupper($method);
        $this->uri = $uri;
        $this->setHeaders($headers);
        $this->protocol = $version;

        if (!isset($this->headerNames['host'])) {
            $this->updateHostFromUri();
        }

        if ($body !== '' && $body !== null) {
            $this->stream = Utils::streamFor($body);
        }
    }

    public function getRequestTarget(): string
    {
        if ($this->requestTarget !== null) {
            return $this->requestTarget;
        }

        $target = $this->uri->getPath();
        if ($target === '') {
            $target = '/';
        }
        if ($this->uri->getQuery() != '') {
            $target .= '?'.$this->uri->getQuery();
        }

        return $target;
    }

    public function withRequestTarget($requestTarget): RequestInterface
    {
        if (preg_match('#\s#', $requestTarget)) {
            throw new InvalidArgumentException(
                'Invalid request target provided; cannot contain whitespace'
            );
        }

        $new = clone $this;
        $new->requestTarget = $requestTarget;

        return $new;
    }

    public function getMethod(): string
    {
        return $this->method;
    }

    public function withMethod($method): RequestInterface
    {
        $this->assertMethod($method);
        $new = clone $this;
        $new->method = strtoupper($method);

        return $new;
    }

    public function getUri(): UriInterface
    {
        return $this->uri;
    }

    public function withUri(UriInterface $uri, $preserveHost = false): RequestInterface
    {
        if ($uri === $this->uri) {
            return $this;
        }

        $new = clone $this;
        $new->uri = $uri;

        if (!$preserveHost || !isset($this->headerNames['host'])) {
            $new->updateHostFromUri();
        }

        return $new;
    }

    private function updateHostFromUri(): void
    {
        $host = $this->uri->getHost();

        if ($host == '') {
            return;
        }

        if (($port = $this->uri->getPort()) !== null) {
            $host .= ':'.$port;
        }

        if (isset($this->headerNames['host'])) {
            $header = $this->headerNames['host'];
        } else {
            $header = 'Host';
            $this->headerNames['host'] = 'Host';
        }
        // Ensure Host is the first header.
        // See: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
        $this->headers = [$header => [$host]] + $this->headers;
    }

    /**
     * @param mixed $method
     */
    private function assertMethod($method): void
    {
        if (!is_string($method) || $method === '') {
            throw new InvalidArgumentException('Method must be a non-empty string.');
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

/**
 * PSR-7 response implementation.
 */
class Response implements ResponseInterface
{
    use MessageTrait;

    /** Map of standard HTTP status code/reason phrases */
    private const PHRASES = [
        100 => 'Continue',
        101 => 'Switching Protocols',
        102 => 'Processing',
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative Information',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        207 => 'Multi-status',
        208 => 'Already Reported',
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        303 => 'See Other',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        306 => 'Switch Proxy',
        307 => 'Temporary Redirect',
        308 => 'Permanent Redirect',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        402 => 'Payment Required',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Time-out',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Request Entity Too Large',
        414 => 'Request-URI Too Large',
        415 => 'Unsupported Media Type',
        416 => 'Requested range not satisfiable',
        417 => 'Expectation Failed',
        418 => 'I\'m a teapot',
        422 => 'Unprocessable Entity',
        423 => 'Locked',
        424 => 'Failed Dependency',
        425 => 'Unordered Collection',
        426 => 'Upgrade Required',
        428 => 'Precondition Required',
        429 => 'Too Many Requests',
        431 => 'Request Header Fields Too Large',
        451 => 'Unavailable For Legal Reasons',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway',
        503 => 'Service Unavailable',
        504 => 'Gateway Time-out',
        505 => 'HTTP Version not supported',
        506 => 'Variant Also Negotiates',
        507 => 'Insufficient Storage',
        508 => 'Loop Detected',
        510 => 'Not Extended',
        511 => 'Network Authentication Required',
    ];

    /** @var string */
    private $reasonPhrase;

    /** @var int */
    private $statusCode;

    /**
     * @param int                                  $status  Status code
     * @param (string|string[])[]                  $headers Response headers
     * @param string|resource|StreamInterface|null $body    Response body
     * @param string                               $version Protocol version
     * @param string|null                          $reason  Reason phrase (when empty a default will be used based on the status code)
     */
    public function __construct(
        int $status = 200,
        array $headers = [],
        $body = null,
        string $version = '1.1',
        ?string $reason = null
    ) {
        $this->assertStatusCodeRange($status);

        $this->statusCode = $status;

        if ($body !== '' && $body !== null) {
            $this->stream = Utils::streamFor($body);
        }

        $this->setHeaders($headers);
        if ($reason == '' && isset(self::PHRASES[$this->statusCode])) {
            $this->reasonPhrase = self::PHRASES[$this->statusCode];
        } else {
            $this->reasonPhrase = (string) $reason;
        }

        $this->protocol = $version;
    }

    public function getStatusCode(): int
    {
        return $this->statusCode;
    }

    public function getReasonPhrase(): string
    {
        return $this->reasonPhrase;
    }

    public function withStatus($code, $reasonPhrase = ''): ResponseInterface
    {
        $this->assertStatusCodeIsInteger($code);
        $code = (int) $code;
        $this->assertStatusCodeRange($code);

        $new = clone $this;
        $new->statusCode = $code;
        if ($reasonPhrase == '' && isset(self::PHRASES[$new->statusCode])) {
            $reasonPhrase = self::PHRASES[$new->statusCode];
        }
        $new->reasonPhrase = (string) $reasonPhrase;

        return $new;
    }

    /**
     * @param mixed $statusCode
     */
    private function assertStatusCodeIsInteger($statusCode): void
    {
        if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
            throw new \InvalidArgumentException('Status code must be an integer value.');
        }
    }

    private function assertStatusCodeRange(int $statusCode): void
    {
        if ($statusCode < 100 || $statusCode >= 600) {
            throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

/**
 * @internal
 */
final class Rfc7230
{
    /**
     * Header related regular expressions (based on amphp/http package)
     *
     * Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
     *
     * @see https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
     *
     * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
     */
    public const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
    public const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;

/**
 * Server-side HTTP request
 *
 * Extends the Request definition to add methods for accessing incoming data,
 * specifically server parameters, cookies, matched path parameters, query
 * string arguments, body parameters, and upload file information.
 *
 * "Attributes" are discovered via decomposing the request (and usually
 * specifically the URI path), and typically will be injected by the application.
 *
 * Requests are considered immutable; all methods that might change state are
 * implemented such that they retain the internal state of the current
 * message and return a new instance that contains the changed state.
 */
class ServerRequest extends Request implements ServerRequestInterface
{
    /**
     * @var array
     */
    private $attributes = [];

    /**
     * @var array
     */
    private $cookieParams = [];

    /**
     * @var array|object|null
     */
    private $parsedBody;

    /**
     * @var array
     */
    private $queryParams = [];

    /**
     * @var array
     */
    private $serverParams;

    /**
     * @var array
     */
    private $uploadedFiles = [];

    /**
     * @param string                               $method       HTTP method
     * @param string|UriInterface                  $uri          URI
     * @param (string|string[])[]                  $headers      Request headers
     * @param string|resource|StreamInterface|null $body         Request body
     * @param string                               $version      Protocol version
     * @param array                                $serverParams Typically the $_SERVER superglobal
     */
    public function __construct(
        string $method,
        $uri,
        array $headers = [],
        $body = null,
        string $version = '1.1',
        array $serverParams = []
    ) {
        $this->serverParams = $serverParams;

        parent::__construct($method, $uri, $headers, $body, $version);
    }

    /**
     * Return an UploadedFile instance array.
     *
     * @param array $files An array which respect $_FILES structure
     *
     * @throws InvalidArgumentException for unrecognized values
     */
    public static function normalizeFiles(array $files): array
    {
        $normalized = [];

        foreach ($files as $key => $value) {
            if ($value instanceof UploadedFileInterface) {
                $normalized[$key] = $value;
            } elseif (is_array($value) && isset($value['tmp_name'])) {
                $normalized[$key] = self::createUploadedFileFromSpec($value);
            } elseif (is_array($value)) {
                $normalized[$key] = self::normalizeFiles($value);
                continue;
            } else {
                throw new InvalidArgumentException('Invalid value in files specification');
            }
        }

        return $normalized;
    }

    /**
     * Create and return an UploadedFile instance from a $_FILES specification.
     *
     * If the specification represents an array of values, this method will
     * delegate to normalizeNestedFileSpec() and return that return value.
     *
     * @param array $value $_FILES struct
     *
     * @return UploadedFileInterface|UploadedFileInterface[]
     */
    private static function createUploadedFileFromSpec(array $value)
    {
        if (is_array($value['tmp_name'])) {
            return self::normalizeNestedFileSpec($value);
        }

        return new UploadedFile(
            $value['tmp_name'],
            (int) $value['size'],
            (int) $value['error'],
            $value['name'],
            $value['type']
        );
    }

    /**
     * Normalize an array of file specifications.
     *
     * Loops through all nested files and returns a normalized array of
     * UploadedFileInterface instances.
     *
     * @return UploadedFileInterface[]
     */
    private static function normalizeNestedFileSpec(array $files = []): array
    {
        $normalizedFiles = [];

        foreach (array_keys($files['tmp_name']) as $key) {
            $spec = [
                'tmp_name' => $files['tmp_name'][$key],
                'size' => $files['size'][$key] ?? null,
                'error' => $files['error'][$key] ?? null,
                'name' => $files['name'][$key] ?? null,
                'type' => $files['type'][$key] ?? null,
            ];
            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
        }

        return $normalizedFiles;
    }

    /**
     * Return a ServerRequest populated with superglobals:
     * $_GET
     * $_POST
     * $_COOKIE
     * $_FILES
     * $_SERVER
     */
    public static function fromGlobals(): ServerRequestInterface
    {
        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
        $headers = getallheaders();
        $uri = self::getUriFromGlobals();
        $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';

        $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);

        return $serverRequest
            ->withCookieParams($_COOKIE)
            ->withQueryParams($_GET)
            ->withParsedBody($_POST)
            ->withUploadedFiles(self::normalizeFiles($_FILES));
    }

    private static function extractHostAndPortFromAuthority(string $authority): array
    {
        $uri = 'http://'.$authority;
        $parts = parse_url($uri);
        if (false === $parts) {
            return [null, null];
        }

        $host = $parts['host'] ?? null;
        $port = $parts['port'] ?? null;

        return [$host, $port];
    }

    /**
     * Get a Uri populated with values from $_SERVER.
     */
    public static function getUriFromGlobals(): UriInterface
    {
        $uri = new Uri('');

        $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');

        $hasPort = false;
        if (isset($_SERVER['HTTP_HOST'])) {
            [$host, $port] = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
            if ($host !== null) {
                $uri = $uri->withHost($host);
            }

            if ($port !== null) {
                $hasPort = true;
                $uri = $uri->withPort($port);
            }
        } elseif (isset($_SERVER['SERVER_NAME'])) {
            $uri = $uri->withHost($_SERVER['SERVER_NAME']);
        } elseif (isset($_SERVER['SERVER_ADDR'])) {
            $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
        }

        if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
            $uri = $uri->withPort($_SERVER['SERVER_PORT']);
        }

        $hasQuery = false;
        if (isset($_SERVER['REQUEST_URI'])) {
            $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
            $uri = $uri->withPath($requestUriParts[0]);
            if (isset($requestUriParts[1])) {
                $hasQuery = true;
                $uri = $uri->withQuery($requestUriParts[1]);
            }
        }

        if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
            $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
        }

        return $uri;
    }

    public function getServerParams(): array
    {
        return $this->serverParams;
    }

    public function getUploadedFiles(): array
    {
        return $this->uploadedFiles;
    }

    public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
    {
        $new = clone $this;
        $new->uploadedFiles = $uploadedFiles;

        return $new;
    }

    public function getCookieParams(): array
    {
        return $this->cookieParams;
    }

    public function withCookieParams(array $cookies): ServerRequestInterface
    {
        $new = clone $this;
        $new->cookieParams = $cookies;

        return $new;
    }

    public function getQueryParams(): array
    {
        return $this->queryParams;
    }

    public function withQueryParams(array $query): ServerRequestInterface
    {
        $new = clone $this;
        $new->queryParams = $query;

        return $new;
    }

    /**
     * @return array|object|null
     */
    public function getParsedBody()
    {
        return $this->parsedBody;
    }

    public function withParsedBody($data): ServerRequestInterface
    {
        $new = clone $this;
        $new->parsedBody = $data;

        return $new;
    }

    public function getAttributes(): array
    {
        return $this->attributes;
    }

    /**
     * @return mixed
     */
    public function getAttribute($attribute, $default = null)
    {
        if (false === array_key_exists($attribute, $this->attributes)) {
            return $default;
        }

        return $this->attributes[$attribute];
    }

    public function withAttribute($attribute, $value): ServerRequestInterface
    {
        $new = clone $this;
        $new->attributes[$attribute] = $value;

        return $new;
    }

    public function withoutAttribute($attribute): ServerRequestInterface
    {
        if (false === array_key_exists($attribute, $this->attributes)) {
            return $this;
        }

        $new = clone $this;
        unset($new->attributes[$attribute]);

        return $new;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * PHP stream implementation.
 */
class Stream implements StreamInterface
{
    /**
     * @see https://www.php.net/manual/en/function.fopen.php
     * @see https://www.php.net/manual/en/function.gzopen.php
     */
    private const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/';
    private const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';

    /** @var resource */
    private $stream;
    /** @var int|null */
    private $size;
    /** @var bool */
    private $seekable;
    /** @var bool */
    private $readable;
    /** @var bool */
    private $writable;
    /** @var string|null */
    private $uri;
    /** @var mixed[] */
    private $customMetadata;

    /**
     * This constructor accepts an associative array of options.
     *
     * - size: (int) If a read stream would otherwise have an indeterminate
     *   size, but the size is known due to foreknowledge, then you can
     *   provide that size, in bytes.
     * - metadata: (array) Any additional metadata to return when the metadata
     *   of the stream is accessed.
     *
     * @param resource                            $stream  Stream resource to wrap.
     * @param array{size?: int, metadata?: array} $options Associative array of options.
     *
     * @throws \InvalidArgumentException if the stream is not a stream resource
     */
    public function __construct($stream, array $options = [])
    {
        if (!is_resource($stream)) {
            throw new \InvalidArgumentException('Stream must be a resource');
        }

        if (isset($options['size'])) {
            $this->size = $options['size'];
        }

        $this->customMetadata = $options['metadata'] ?? [];
        $this->stream = $stream;
        $meta = stream_get_meta_data($this->stream);
        $this->seekable = $meta['seekable'];
        $this->readable = (bool) preg_match(self::READABLE_MODES, $meta['mode']);
        $this->writable = (bool) preg_match(self::WRITABLE_MODES, $meta['mode']);
        $this->uri = $this->getMetadata('uri');
    }

    /**
     * Closes the stream when the destructed
     */
    public function __destruct()
    {
        $this->close();
    }

    public function __toString(): string
    {
        try {
            if ($this->isSeekable()) {
                $this->seek(0);
            }

            return $this->getContents();
        } catch (\Throwable $e) {
            if (\PHP_VERSION_ID >= 70400) {
                throw $e;
            }
            trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);

            return '';
        }
    }

    public function getContents(): string
    {
        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }

        if (!$this->readable) {
            throw new \RuntimeException('Cannot read from non-readable stream');
        }

        return Utils::tryGetContents($this->stream);
    }

    public function close(): void
    {
        if (isset($this->stream)) {
            if (is_resource($this->stream)) {
                fclose($this->stream);
            }
            $this->detach();
        }
    }

    public function detach()
    {
        if (!isset($this->stream)) {
            return null;
        }

        $result = $this->stream;
        unset($this->stream);
        $this->size = $this->uri = null;
        $this->readable = $this->writable = $this->seekable = false;

        return $result;
    }

    public function getSize(): ?int
    {
        if ($this->size !== null) {
            return $this->size;
        }

        if (!isset($this->stream)) {
            return null;
        }

        // Clear the stat cache if the stream has a URI
        if ($this->uri) {
            clearstatcache(true, $this->uri);
        }

        $stats = fstat($this->stream);
        if (is_array($stats) && isset($stats['size'])) {
            $this->size = $stats['size'];

            return $this->size;
        }

        return null;
    }

    public function isReadable(): bool
    {
        return $this->readable;
    }

    public function isWritable(): bool
    {
        return $this->writable;
    }

    public function isSeekable(): bool
    {
        return $this->seekable;
    }

    public function eof(): bool
    {
        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }

        return feof($this->stream);
    }

    public function tell(): int
    {
        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }

        $result = ftell($this->stream);

        if ($result === false) {
            throw new \RuntimeException('Unable to determine stream position');
        }

        return $result;
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        $whence = (int) $whence;

        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }
        if (!$this->seekable) {
            throw new \RuntimeException('Stream is not seekable');
        }
        if (fseek($this->stream, $offset, $whence) === -1) {
            throw new \RuntimeException('Unable to seek to stream position '
                .$offset.' with whence '.var_export($whence, true));
        }
    }

    public function read($length): string
    {
        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }
        if (!$this->readable) {
            throw new \RuntimeException('Cannot read from non-readable stream');
        }
        if ($length < 0) {
            throw new \RuntimeException('Length parameter cannot be negative');
        }

        if (0 === $length) {
            return '';
        }

        try {
            $string = fread($this->stream, $length);
        } catch (\Exception $e) {
            throw new \RuntimeException('Unable to read from stream', 0, $e);
        }

        if (false === $string) {
            throw new \RuntimeException('Unable to read from stream');
        }

        return $string;
    }

    public function write($string): int
    {
        if (!isset($this->stream)) {
            throw new \RuntimeException('Stream is detached');
        }
        if (!$this->writable) {
            throw new \RuntimeException('Cannot write to a non-writable stream');
        }

        // We can't know the size after writing anything
        $this->size = null;
        $result = fwrite($this->stream, $string);

        if ($result === false) {
            throw new \RuntimeException('Unable to write to stream');
        }

        return $result;
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        if (!isset($this->stream)) {
            return $key ? null : [];
        } elseif (!$key) {
            return $this->customMetadata + stream_get_meta_data($this->stream);
        } elseif (isset($this->customMetadata[$key])) {
            return $this->customMetadata[$key];
        }

        $meta = stream_get_meta_data($this->stream);

        return $meta[$key] ?? null;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Stream decorator trait
 *
 * @property StreamInterface $stream
 */
trait StreamDecoratorTrait
{
    /**
     * @param StreamInterface $stream Stream to decorate
     */
    public function __construct(StreamInterface $stream)
    {
        $this->stream = $stream;
    }

    /**
     * Magic method used to create a new stream if streams are not added in
     * the constructor of a decorator (e.g., LazyOpenStream).
     *
     * @return StreamInterface
     */
    public function __get(string $name)
    {
        if ($name === 'stream') {
            $this->stream = $this->createStream();

            return $this->stream;
        }

        throw new \UnexpectedValueException("$name not found on class");
    }

    public function __toString(): string
    {
        try {
            if ($this->isSeekable()) {
                $this->seek(0);
            }

            return $this->getContents();
        } catch (\Throwable $e) {
            if (\PHP_VERSION_ID >= 70400) {
                throw $e;
            }
            trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);

            return '';
        }
    }

    public function getContents(): string
    {
        return Utils::copyToString($this);
    }

    /**
     * Allow decorators to implement custom methods
     *
     * @return mixed
     */
    public function __call(string $method, array $args)
    {
        /** @var callable $callable */
        $callable = [$this->stream, $method];
        $result = ($callable)(...$args);

        // Always return the wrapped object if the result is a return $this
        return $result === $this->stream ? $this : $result;
    }

    public function close(): void
    {
        $this->stream->close();
    }

    /**
     * @return mixed
     */
    public function getMetadata($key = null)
    {
        return $this->stream->getMetadata($key);
    }

    public function detach()
    {
        return $this->stream->detach();
    }

    public function getSize(): ?int
    {
        return $this->stream->getSize();
    }

    public function eof(): bool
    {
        return $this->stream->eof();
    }

    public function tell(): int
    {
        return $this->stream->tell();
    }

    public function isReadable(): bool
    {
        return $this->stream->isReadable();
    }

    public function isWritable(): bool
    {
        return $this->stream->isWritable();
    }

    public function isSeekable(): bool
    {
        return $this->stream->isSeekable();
    }

    public function rewind(): void
    {
        $this->seek(0);
    }

    public function seek($offset, $whence = SEEK_SET): void
    {
        $this->stream->seek($offset, $whence);
    }

    public function read($length): string
    {
        return $this->stream->read($length);
    }

    public function write($string): int
    {
        return $this->stream->write($string);
    }

    /**
     * Implement in subclasses to dynamically create streams when requested.
     *
     * @throws \BadMethodCallException
     */
    protected function createStream(): StreamInterface
    {
        throw new \BadMethodCallException('Not implemented');
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;

/**
 * Converts Guzzle streams into PHP stream resources.
 *
 * @see https://www.php.net/streamwrapper
 */
final class StreamWrapper
{
    /** @var resource */
    public $context;

    /** @var StreamInterface */
    private $stream;

    /** @var string r, r+, or w */
    private $mode;

    /**
     * Returns a resource representing the stream.
     *
     * @param StreamInterface $stream The stream to get a resource for
     *
     * @return resource
     *
     * @throws \InvalidArgumentException if stream is not readable or writable
     */
    public static function getResource(StreamInterface $stream)
    {
        self::register();

        if ($stream->isReadable()) {
            $mode = $stream->isWritable() ? 'r+' : 'r';
        } elseif ($stream->isWritable()) {
            $mode = 'w';
        } else {
            throw new \InvalidArgumentException('The stream must be readable, '
                .'writable, or both.');
        }

        return fopen('guzzle://stream', $mode, false, self::createStreamContext($stream));
    }

    /**
     * Creates a stream context that can be used to open a stream as a php stream resource.
     *
     * @return resource
     */
    public static function createStreamContext(StreamInterface $stream)
    {
        return stream_context_create([
            'guzzle' => ['stream' => $stream],
        ]);
    }

    /**
     * Registers the stream wrapper if needed
     */
    public static function register(): void
    {
        if (!in_array('guzzle', stream_get_wrappers())) {
            stream_wrapper_register('guzzle', __CLASS__);
        }
    }

    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool
    {
        $options = stream_context_get_options($this->context);

        if (!isset($options['guzzle']['stream'])) {
            return false;
        }

        $this->mode = $mode;
        $this->stream = $options['guzzle']['stream'];

        return true;
    }

    public function stream_read(int $count): string
    {
        return $this->stream->read($count);
    }

    public function stream_write(string $data): int
    {
        return $this->stream->write($data);
    }

    public function stream_tell(): int
    {
        return $this->stream->tell();
    }

    public function stream_eof(): bool
    {
        return $this->stream->eof();
    }

    public function stream_seek(int $offset, int $whence): bool
    {
        $this->stream->seek($offset, $whence);

        return true;
    }

    /**
     * @return resource|false
     */
    public function stream_cast(int $cast_as)
    {
        $stream = clone $this->stream;
        $resource = $stream->detach();

        return $resource ?? false;
    }

    /**
     * @return array{
     *   dev: int,
     *   ino: int,
     *   mode: int,
     *   nlink: int,
     *   uid: int,
     *   gid: int,
     *   rdev: int,
     *   size: int,
     *   atime: int,
     *   mtime: int,
     *   ctime: int,
     *   blksize: int,
     *   blocks: int
     * }|false
     */
    public function stream_stat()
    {
        if ($this->stream->getSize() === null) {
            return false;
        }

        static $modeMap = [
            'r' => 33060,
            'rb' => 33060,
            'r+' => 33206,
            'w' => 33188,
            'wb' => 33188,
        ];

        return [
            'dev' => 0,
            'ino' => 0,
            'mode' => $modeMap[$this->mode],
            'nlink' => 0,
            'uid' => 0,
            'gid' => 0,
            'rdev' => 0,
            'size' => $this->stream->getSize() ?: 0,
            'atime' => 0,
            'mtime' => 0,
            'ctime' => 0,
            'blksize' => 0,
            'blocks' => 0,
        ];
    }

    /**
     * @return array{
     *   dev: int,
     *   ino: int,
     *   mode: int,
     *   nlink: int,
     *   uid: int,
     *   gid: int,
     *   rdev: int,
     *   size: int,
     *   atime: int,
     *   mtime: int,
     *   ctime: int,
     *   blksize: int,
     *   blocks: int
     * }
     */
    public function url_stat(string $path, int $flags): array
    {
        return [
            'dev' => 0,
            'ino' => 0,
            'mode' => 0,
            'nlink' => 0,
            'uid' => 0,
            'gid' => 0,
            'rdev' => 0,
            'size' => 0,
            'atime' => 0,
            'mtime' => 0,
            'ctime' => 0,
            'blksize' => 0,
            'blocks' => 0,
        ];
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use RuntimeException;

class UploadedFile implements UploadedFileInterface
{
    private const ERROR_MAP = [
        UPLOAD_ERR_OK => 'UPLOAD_ERR_OK',
        UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE',
        UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE',
        UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL',
        UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE',
        UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR',
        UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE',
        UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION',
    ];

    /**
     * @var string|null
     */
    private $clientFilename;

    /**
     * @var string|null
     */
    private $clientMediaType;

    /**
     * @var int
     */
    private $error;

    /**
     * @var string|null
     */
    private $file;

    /**
     * @var bool
     */
    private $moved = false;

    /**
     * @var int|null
     */
    private $size;

    /**
     * @var StreamInterface|null
     */
    private $stream;

    /**
     * @param StreamInterface|string|resource $streamOrFile
     */
    public function __construct(
        $streamOrFile,
        ?int $size,
        int $errorStatus,
        ?string $clientFilename = null,
        ?string $clientMediaType = null
    ) {
        $this->setError($errorStatus);
        $this->size = $size;
        $this->clientFilename = $clientFilename;
        $this->clientMediaType = $clientMediaType;

        if ($this->isOk()) {
            $this->setStreamOrFile($streamOrFile);
        }
    }

    /**
     * Depending on the value set file or stream variable
     *
     * @param StreamInterface|string|resource $streamOrFile
     *
     * @throws InvalidArgumentException
     */
    private function setStreamOrFile($streamOrFile): void
    {
        if (is_string($streamOrFile)) {
            $this->file = $streamOrFile;
        } elseif (is_resource($streamOrFile)) {
            $this->stream = new Stream($streamOrFile);
        } elseif ($streamOrFile instanceof StreamInterface) {
            $this->stream = $streamOrFile;
        } else {
            throw new InvalidArgumentException(
                'Invalid stream or file provided for UploadedFile'
            );
        }
    }

    /**
     * @throws InvalidArgumentException
     */
    private function setError(int $error): void
    {
        if (!isset(UploadedFile::ERROR_MAP[$error])) {
            throw new InvalidArgumentException(
                'Invalid error status for UploadedFile'
            );
        }

        $this->error = $error;
    }

    private static function isStringNotEmpty($param): bool
    {
        return is_string($param) && false === empty($param);
    }

    /**
     * Return true if there is no upload error
     */
    private function isOk(): bool
    {
        return $this->error === UPLOAD_ERR_OK;
    }

    public function isMoved(): bool
    {
        return $this->moved;
    }

    /**
     * @throws RuntimeException if is moved or not ok
     */
    private function validateActive(): void
    {
        if (false === $this->isOk()) {
            throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error]));
        }

        if ($this->isMoved()) {
            throw new RuntimeException('Cannot retrieve stream after it has already been moved');
        }
    }

    public function getStream(): StreamInterface
    {
        $this->validateActive();

        if ($this->stream instanceof StreamInterface) {
            return $this->stream;
        }

        /** @var string $file */
        $file = $this->file;

        return new LazyOpenStream($file, 'r+');
    }

    public function moveTo($targetPath): void
    {
        $this->validateActive();

        if (false === self::isStringNotEmpty($targetPath)) {
            throw new InvalidArgumentException(
                'Invalid path provided for move operation; must be a non-empty string'
            );
        }

        if ($this->file) {
            $this->moved = PHP_SAPI === 'cli'
                ? rename($this->file, $targetPath)
                : move_uploaded_file($this->file, $targetPath);
        } else {
            Utils::copyToStream(
                $this->getStream(),
                new LazyOpenStream($targetPath, 'w')
            );

            $this->moved = true;
        }

        if (false === $this->moved) {
            throw new RuntimeException(
                sprintf('Uploaded file could not be moved to %s', $targetPath)
            );
        }
    }

    public function getSize(): ?int
    {
        return $this->size;
    }

    public function getError(): int
    {
        return $this->error;
    }

    public function getClientFilename(): ?string
    {
        return $this->clientFilename;
    }

    public function getClientMediaType(): ?string
    {
        return $this->clientMediaType;
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use GuzzleHttp\Psr7\Exception\MalformedUriException;
use Psr\Http\Message\UriInterface;

/**
 * PSR-7 URI implementation.
 *
 * @author Michael Dowling
 * @author Tobias Schultze
 * @author Matthew Weier O'Phinney
 */
class Uri implements UriInterface, \JsonSerializable
{
    /**
     * Absolute http and https URIs require a host per RFC 7230 Section 2.7
     * but in generic URIs the host can be empty. So for http(s) URIs
     * we apply this default host when no host is given yet to form a
     * valid URI.
     */
    private const HTTP_DEFAULT_HOST = 'localhost';

    private const DEFAULT_PORTS = [
        'http' => 80,
        'https' => 443,
        'ftp' => 21,
        'gopher' => 70,
        'nntp' => 119,
        'news' => 119,
        'telnet' => 23,
        'tn3270' => 23,
        'imap' => 143,
        'pop' => 110,
        'ldap' => 389,
    ];

    /**
     * Unreserved characters for use in a regex.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
     */
    private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';

    /**
     * Sub-delims for use in a regex.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
     */
    private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
    private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];

    /** @var string Uri scheme. */
    private $scheme = '';

    /** @var string Uri user info. */
    private $userInfo = '';

    /** @var string Uri host. */
    private $host = '';

    /** @var int|null Uri port. */
    private $port;

    /** @var string Uri path. */
    private $path = '';

    /** @var string Uri query string. */
    private $query = '';

    /** @var string Uri fragment. */
    private $fragment = '';

    /** @var string|null String representation */
    private $composedComponents;

    public function __construct(string $uri = '')
    {
        if ($uri !== '') {
            $parts = self::parse($uri);
            if ($parts === false) {
                throw new MalformedUriException("Unable to parse URI: $uri");
            }
            $this->applyParts($parts);
        }
    }

    /**
     * UTF-8 aware \parse_url() replacement.
     *
     * The internal function produces broken output for non ASCII domain names
     * (IDN) when used with locales other than "C".
     *
     * On the other hand, cURL understands IDN correctly only when UTF-8 locale
     * is configured ("C.UTF-8", "en_US.UTF-8", etc.).
     *
     * @see https://bugs.php.net/bug.php?id=52923
     * @see https://www.php.net/manual/en/function.parse-url.php#114817
     * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
     *
     * @return array|false
     */
    private static function parse(string $url)
    {
        // If IPv6
        $prefix = '';
        if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) {
            /** @var array{0:string, 1:string, 2:string} $matches */
            $prefix = $matches[1];
            $url = $matches[2];
        }

        /** @var string */
        $encodedUrl = preg_replace_callback(
            '%[^:/@?&=#]+%usD',
            static function ($matches) {
                return urlencode($matches[0]);
            },
            $url
        );

        $result = parse_url($prefix.$encodedUrl);

        if ($result === false) {
            return false;
        }

        return array_map('urldecode', $result);
    }

    public function __toString(): string
    {
        if ($this->composedComponents === null) {
            $this->composedComponents = self::composeComponents(
                $this->scheme,
                $this->getAuthority(),
                $this->path,
                $this->query,
                $this->fragment
            );
        }

        return $this->composedComponents;
    }

    /**
     * Composes a URI reference string from its various components.
     *
     * Usually this method does not need to be called manually but instead is used indirectly via
     * `Psr\Http\Message\UriInterface::__toString`.
     *
     * PSR-7 UriInterface treats an empty component the same as a missing component as
     * getQuery(), getFragment() etc. always return a string. This explains the slight
     * difference to RFC 3986 Section 5.3.
     *
     * Another adjustment is that the authority separator is added even when the authority is missing/empty
     * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
     * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
     * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
     * that format).
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.3
     */
    public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string
    {
        $uri = '';

        // weak type checks to also accept null until we can add scalar type hints
        if ($scheme != '') {
            $uri .= $scheme.':';
        }

        if ($authority != '' || $scheme === 'file') {
            $uri .= '//'.$authority;
        }

        if ($authority != '' && $path != '' && $path[0] != '/') {
            $path = '/'.$path;
        }

        $uri .= $path;

        if ($query != '') {
            $uri .= '?'.$query;
        }

        if ($fragment != '') {
            $uri .= '#'.$fragment;
        }

        return $uri;
    }

    /**
     * Whether the URI has the default port of the current scheme.
     *
     * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
     * independently of the implementation.
     */
    public static function isDefaultPort(UriInterface $uri): bool
    {
        return $uri->getPort() === null
            || (isset(self::DEFAULT_PORTS[$uri->getScheme()]) && $uri->getPort() === self::DEFAULT_PORTS[$uri->getScheme()]);
    }

    /**
     * Whether the URI is absolute, i.e. it has a scheme.
     *
     * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
     * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
     * to another URI, the base URI. Relative references can be divided into several forms:
     * - network-path references, e.g. '//example.com/path'
     * - absolute-path references, e.g. '/path'
     * - relative-path references, e.g. 'subpath'
     *
     * @see Uri::isNetworkPathReference
     * @see Uri::isAbsolutePathReference
     * @see Uri::isRelativePathReference
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4
     */
    public static function isAbsolute(UriInterface $uri): bool
    {
        return $uri->getScheme() !== '';
    }

    /**
     * Whether the URI is a network-path reference.
     *
     * A relative reference that begins with two slash characters is termed an network-path reference.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2
     */
    public static function isNetworkPathReference(UriInterface $uri): bool
    {
        return $uri->getScheme() === '' && $uri->getAuthority() !== '';
    }

    /**
     * Whether the URI is a absolute-path reference.
     *
     * A relative reference that begins with a single slash character is termed an absolute-path reference.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2
     */
    public static function isAbsolutePathReference(UriInterface $uri): bool
    {
        return $uri->getScheme() === ''
            && $uri->getAuthority() === ''
            && isset($uri->getPath()[0])
            && $uri->getPath()[0] === '/';
    }

    /**
     * Whether the URI is a relative-path reference.
     *
     * A relative reference that does not begin with a slash character is termed a relative-path reference.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2
     */
    public static function isRelativePathReference(UriInterface $uri): bool
    {
        return $uri->getScheme() === ''
            && $uri->getAuthority() === ''
            && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
    }

    /**
     * Whether the URI is a same-document reference.
     *
     * A same-document reference refers to a URI that is, aside from its fragment
     * component, identical to the base URI. When no base URI is given, only an empty
     * URI reference (apart from its fragment) is considered a same-document reference.
     *
     * @param UriInterface      $uri  The URI to check
     * @param UriInterface|null $base An optional base URI to compare against
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.4
     */
    public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool
    {
        if ($base !== null) {
            $uri = UriResolver::resolve($base, $uri);

            return ($uri->getScheme() === $base->getScheme())
                && ($uri->getAuthority() === $base->getAuthority())
                && ($uri->getPath() === $base->getPath())
                && ($uri->getQuery() === $base->getQuery());
        }

        return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
    }

    /**
     * Creates a new URI with a specific query string value removed.
     *
     * Any existing query string values that exactly match the provided key are
     * removed.
     *
     * @param UriInterface $uri URI to use as a base.
     * @param string       $key Query string key to remove.
     */
    public static function withoutQueryValue(UriInterface $uri, string $key): UriInterface
    {
        $result = self::getFilteredQueryString($uri, [$key]);

        return $uri->withQuery(implode('&', $result));
    }

    /**
     * Creates a new URI with a specific query string value.
     *
     * Any existing query string values that exactly match the provided key are
     * removed and replaced with the given key value pair.
     *
     * A value of null will set the query string key without a value, e.g. "key"
     * instead of "key=value".
     *
     * @param UriInterface $uri   URI to use as a base.
     * @param string       $key   Key to set.
     * @param string|null  $value Value to set
     */
    public static function withQueryValue(UriInterface $uri, string $key, ?string $value): UriInterface
    {
        $result = self::getFilteredQueryString($uri, [$key]);

        $result[] = self::generateQueryString($key, $value);

        return $uri->withQuery(implode('&', $result));
    }

    /**
     * Creates a new URI with multiple specific query string values.
     *
     * It has the same behavior as withQueryValue() but for an associative array of key => value.
     *
     * @param UriInterface    $uri           URI to use as a base.
     * @param (string|null)[] $keyValueArray Associative array of key and values
     */
    public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface
    {
        $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));

        foreach ($keyValueArray as $key => $value) {
            $result[] = self::generateQueryString((string) $key, $value !== null ? (string) $value : null);
        }

        return $uri->withQuery(implode('&', $result));
    }

    /**
     * Creates a URI from a hash of `parse_url` components.
     *
     * @see https://www.php.net/manual/en/function.parse-url.php
     *
     * @throws MalformedUriException If the components do not form a valid URI.
     */
    public static function fromParts(array $parts): UriInterface
    {
        $uri = new self();
        $uri->applyParts($parts);
        $uri->validateState();

        return $uri;
    }

    public function getScheme(): string
    {
        return $this->scheme;
    }

    public function getAuthority(): string
    {
        $authority = $this->host;
        if ($this->userInfo !== '') {
            $authority = $this->userInfo.'@'.$authority;
        }

        if ($this->port !== null) {
            $authority .= ':'.$this->port;
        }

        return $authority;
    }

    public function getUserInfo(): string
    {
        return $this->userInfo;
    }

    public function getHost(): string
    {
        return $this->host;
    }

    public function getPort(): ?int
    {
        return $this->port;
    }

    public function getPath(): string
    {
        return $this->path;
    }

    public function getQuery(): string
    {
        return $this->query;
    }

    public function getFragment(): string
    {
        return $this->fragment;
    }

    public function withScheme($scheme): UriInterface
    {
        $scheme = $this->filterScheme($scheme);

        if ($this->scheme === $scheme) {
            return $this;
        }

        $new = clone $this;
        $new->scheme = $scheme;
        $new->composedComponents = null;
        $new->removeDefaultPort();
        $new->validateState();

        return $new;
    }

    public function withUserInfo($user, $password = null): UriInterface
    {
        $info = $this->filterUserInfoComponent($user);
        if ($password !== null) {
            $info .= ':'.$this->filterUserInfoComponent($password);
        }

        if ($this->userInfo === $info) {
            return $this;
        }

        $new = clone $this;
        $new->userInfo = $info;
        $new->composedComponents = null;
        $new->validateState();

        return $new;
    }

    public function withHost($host): UriInterface
    {
        $host = $this->filterHost($host);

        if ($this->host === $host) {
            return $this;
        }

        $new = clone $this;
        $new->host = $host;
        $new->composedComponents = null;
        $new->validateState();

        return $new;
    }

    public function withPort($port): UriInterface
    {
        $port = $this->filterPort($port);

        if ($this->port === $port) {
            return $this;
        }

        $new = clone $this;
        $new->port = $port;
        $new->composedComponents = null;
        $new->removeDefaultPort();
        $new->validateState();

        return $new;
    }

    public function withPath($path): UriInterface
    {
        $path = $this->filterPath($path);

        if ($this->path === $path) {
            return $this;
        }

        $new = clone $this;
        $new->path = $path;
        $new->composedComponents = null;
        $new->validateState();

        return $new;
    }

    public function withQuery($query): UriInterface
    {
        $query = $this->filterQueryAndFragment($query);

        if ($this->query === $query) {
            return $this;
        }

        $new = clone $this;
        $new->query = $query;
        $new->composedComponents = null;

        return $new;
    }

    public function withFragment($fragment): UriInterface
    {
        $fragment = $this->filterQueryAndFragment($fragment);

        if ($this->fragment === $fragment) {
            return $this;
        }

        $new = clone $this;
        $new->fragment = $fragment;
        $new->composedComponents = null;

        return $new;
    }

    public function jsonSerialize(): string
    {
        return $this->__toString();
    }

    /**
     * Apply parse_url parts to a URI.
     *
     * @param array $parts Array of parse_url parts to apply.
     */
    private function applyParts(array $parts): void
    {
        $this->scheme = isset($parts['scheme'])
            ? $this->filterScheme($parts['scheme'])
            : '';
        $this->userInfo = isset($parts['user'])
            ? $this->filterUserInfoComponent($parts['user'])
            : '';
        $this->host = isset($parts['host'])
            ? $this->filterHost($parts['host'])
            : '';
        $this->port = isset($parts['port'])
            ? $this->filterPort($parts['port'])
            : null;
        $this->path = isset($parts['path'])
            ? $this->filterPath($parts['path'])
            : '';
        $this->query = isset($parts['query'])
            ? $this->filterQueryAndFragment($parts['query'])
            : '';
        $this->fragment = isset($parts['fragment'])
            ? $this->filterQueryAndFragment($parts['fragment'])
            : '';
        if (isset($parts['pass'])) {
            $this->userInfo .= ':'.$this->filterUserInfoComponent($parts['pass']);
        }

        $this->removeDefaultPort();
    }

    /**
     * @param mixed $scheme
     *
     * @throws \InvalidArgumentException If the scheme is invalid.
     */
    private function filterScheme($scheme): string
    {
        if (!is_string($scheme)) {
            throw new \InvalidArgumentException('Scheme must be a string');
        }

        return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
    }

    /**
     * @param mixed $component
     *
     * @throws \InvalidArgumentException If the user info is invalid.
     */
    private function filterUserInfoComponent($component): string
    {
        if (!is_string($component)) {
            throw new \InvalidArgumentException('User info must be a string');
        }

        return preg_replace_callback(
            '/(?:[^%'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.']+|%(?![A-Fa-f0-9]{2}))/',
            [$this, 'rawurlencodeMatchZero'],
            $component
        );
    }

    /**
     * @param mixed $host
     *
     * @throws \InvalidArgumentException If the host is invalid.
     */
    private function filterHost($host): string
    {
        if (!is_string($host)) {
            throw new \InvalidArgumentException('Host must be a string');
        }

        return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
    }

    /**
     * @param mixed $port
     *
     * @throws \InvalidArgumentException If the port is invalid.
     */
    private function filterPort($port): ?int
    {
        if ($port === null) {
            return null;
        }

        $port = (int) $port;
        if (0 > $port || 0xFFFF < $port) {
            throw new \InvalidArgumentException(
                sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
            );
        }

        return $port;
    }

    /**
     * @param (string|int)[] $keys
     *
     * @return string[]
     */
    private static function getFilteredQueryString(UriInterface $uri, array $keys): array
    {
        $current = $uri->getQuery();

        if ($current === '') {
            return [];
        }

        $decodedKeys = array_map(function ($k): string {
            return rawurldecode((string) $k);
        }, $keys);

        return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
            return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
        });
    }

    private static function generateQueryString(string $key, ?string $value): string
    {
        // Query string separators ("=", "&") within the key or value need to be encoded
        // (while preventing double-encoding) before setting the query string. All other
        // chars that need percent-encoding will be encoded by withQuery().
        $queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);

        if ($value !== null) {
            $queryString .= '='.strtr($value, self::QUERY_SEPARATORS_REPLACEMENT);
        }

        return $queryString;
    }

    private function removeDefaultPort(): void
    {
        if ($this->port !== null && self::isDefaultPort($this)) {
            $this->port = null;
        }
    }

    /**
     * Filters the path of a URI
     *
     * @param mixed $path
     *
     * @throws \InvalidArgumentException If the path is invalid.
     */
    private function filterPath($path): string
    {
        if (!is_string($path)) {
            throw new \InvalidArgumentException('Path must be a string');
        }

        return preg_replace_callback(
            '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
            [$this, 'rawurlencodeMatchZero'],
            $path
        );
    }

    /**
     * Filters the query string or fragment of a URI.
     *
     * @param mixed $str
     *
     * @throws \InvalidArgumentException If the query or fragment is invalid.
     */
    private function filterQueryAndFragment($str): string
    {
        if (!is_string($str)) {
            throw new \InvalidArgumentException('Query and fragment must be a string');
        }

        return preg_replace_callback(
            '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
            [$this, 'rawurlencodeMatchZero'],
            $str
        );
    }

    private function rawurlencodeMatchZero(array $match): string
    {
        return rawurlencode($match[0]);
    }

    private function validateState(): void
    {
        if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
            $this->host = self::HTTP_DEFAULT_HOST;
        }

        if ($this->getAuthority() === '') {
            if (0 === strpos($this->path, '//')) {
                throw new MalformedUriException('The path of a URI without an authority must not start with two slashes "//"');
            }
            if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
                throw new MalformedUriException('A relative URI must not have a path beginning with a segment containing a colon');
            }
        }
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;

/**
 * Provides methods to determine if a modified URL should be considered cross-origin.
 *
 * @author Graham Campbell
 */
final class UriComparator
{
    /**
     * Determines if a modified URL should be considered cross-origin with
     * respect to an original URL.
     */
    public static function isCrossOrigin(UriInterface $original, UriInterface $modified): bool
    {
        if (\strcasecmp($original->getHost(), $modified->getHost()) !== 0) {
            return true;
        }

        if ($original->getScheme() !== $modified->getScheme()) {
            return true;
        }

        if (self::computePort($original) !== self::computePort($modified)) {
            return true;
        }

        return false;
    }

    private static function computePort(UriInterface $uri): int
    {
        $port = $uri->getPort();

        if (null !== $port) {
            return $port;
        }

        return 'https' === $uri->getScheme() ? 443 : 80;
    }

    private function __construct()
    {
        // cannot be instantiated
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;

/**
 * Provides methods to normalize and compare URIs.
 *
 * @author Tobias Schultze
 *
 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6
 */
final class UriNormalizer
{
    /**
     * Default normalizations which only include the ones that preserve semantics.
     */
    public const PRESERVING_NORMALIZATIONS =
        self::CAPITALIZE_PERCENT_ENCODING |
        self::DECODE_UNRESERVED_CHARACTERS |
        self::CONVERT_EMPTY_PATH |
        self::REMOVE_DEFAULT_HOST |
        self::REMOVE_DEFAULT_PORT |
        self::REMOVE_DOT_SEGMENTS;

    /**
     * All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
     *
     * Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b
     */
    public const CAPITALIZE_PERCENT_ENCODING = 1;

    /**
     * Decodes percent-encoded octets of unreserved characters.
     *
     * For consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39),
     * hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers and,
     * when found in a URI, should be decoded to their corresponding unreserved characters by URI normalizers.
     *
     * Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/
     */
    public const DECODE_UNRESERVED_CHARACTERS = 2;

    /**
     * Converts the empty path to "/" for http and https URIs.
     *
     * Example: http://example.org → http://example.org/
     */
    public const CONVERT_EMPTY_PATH = 4;

    /**
     * Removes the default host of the given URI scheme from the URI.
     *
     * Only the "file" scheme defines the default host "localhost".
     * All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile`
     * are equivalent according to RFC 3986. The first format is not accepted
     * by PHPs stream functions and thus already normalized implicitly to the
     * second format in the Uri class. See `GuzzleHttp\Psr7\Uri::composeComponents`.
     *
     * Example: file://localhost/myfile → file:///myfile
     */
    public const REMOVE_DEFAULT_HOST = 8;

    /**
     * Removes the default port of the given URI scheme from the URI.
     *
     * Example: http://example.org:80/ → http://example.org/
     */
    public const REMOVE_DEFAULT_PORT = 16;

    /**
     * Removes unnecessary dot-segments.
     *
     * Dot-segments in relative-path references are not removed as it would
     * change the semantics of the URI reference.
     *
     * Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html
     */
    public const REMOVE_DOT_SEGMENTS = 32;

    /**
     * Paths which include two or more adjacent slashes are converted to one.
     *
     * Webservers usually ignore duplicate slashes and treat those URIs equivalent.
     * But in theory those URIs do not need to be equivalent. So this normalization
     * may change the semantics. Encoded slashes (%2F) are not removed.
     *
     * Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html
     */
    public const REMOVE_DUPLICATE_SLASHES = 64;

    /**
     * Sort query parameters with their values in alphabetical order.
     *
     * However, the order of parameters in a URI may be significant (this is not defined by the standard).
     * So this normalization is not safe and may change the semantics of the URI.
     *
     * Example: ?lang=en&article=fred → ?article=fred&lang=en
     *
     * Note: The sorting is neither locale nor Unicode aware (the URI query does not get decoded at all) as the
     * purpose is to be able to compare URIs in a reproducible way, not to have the params sorted perfectly.
     */
    public const SORT_QUERY_PARAMETERS = 128;

    /**
     * Returns a normalized URI.
     *
     * The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
     * This methods adds additional normalizations that can be configured with the $flags parameter.
     *
     * PSR-7 UriInterface cannot distinguish between an empty component and a missing component as
     * getQuery(), getFragment() etc. always return a string. This means the URIs "/?#" and "/" are
     * treated equivalent which is not necessarily true according to RFC 3986. But that difference
     * is highly uncommon in reality. So this potential normalization is implied in PSR-7 as well.
     *
     * @param UriInterface $uri   The URI to normalize
     * @param int          $flags A bitmask of normalizations to apply, see constants
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.2
     */
    public static function normalize(UriInterface $uri, int $flags = self::PRESERVING_NORMALIZATIONS): UriInterface
    {
        if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {
            $uri = self::capitalizePercentEncoding($uri);
        }

        if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {
            $uri = self::decodeUnreservedCharacters($uri);
        }

        if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === ''
            && ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
        ) {
            $uri = $uri->withPath('/');
        }

        if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
            $uri = $uri->withHost('');
        }

        if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
            $uri = $uri->withPort(null);
        }

        if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
            $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
        }

        if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
            $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
        }

        if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
            $queryKeyValues = explode('&', $uri->getQuery());
            sort($queryKeyValues);
            $uri = $uri->withQuery(implode('&', $queryKeyValues));
        }

        return $uri;
    }

    /**
     * Whether two URIs can be considered equivalent.
     *
     * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
     * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
     * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
     * relative references does not mean anything.
     *
     * @param UriInterface $uri1           An URI to compare
     * @param UriInterface $uri2           An URI to compare
     * @param int          $normalizations A bitmask of normalizations to apply, see constants
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.1
     */
    public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS): bool
    {
        return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
    }

    private static function capitalizePercentEncoding(UriInterface $uri): UriInterface
    {
        $regex = '/(?:%[A-Fa-f0-9]{2})++/';

        $callback = function (array $match): string {
            return strtoupper($match[0]);
        };

        return
            $uri->withPath(
                preg_replace_callback($regex, $callback, $uri->getPath())
            )->withQuery(
                preg_replace_callback($regex, $callback, $uri->getQuery())
            );
    }

    private static function decodeUnreservedCharacters(UriInterface $uri): UriInterface
    {
        $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';

        $callback = function (array $match): string {
            return rawurldecode($match[0]);
        };

        return
            $uri->withPath(
                preg_replace_callback($regex, $callback, $uri->getPath())
            )->withQuery(
                preg_replace_callback($regex, $callback, $uri->getQuery())
            );
    }

    private function __construct()
    {
        // cannot be instantiated
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;

/**
 * Resolves a URI reference in the context of a base URI and the opposite way.
 *
 * @author Tobias Schultze
 *
 * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5
 */
final class UriResolver
{
    /**
     * Removes dot segments from a path and returns the new path.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
     */
    public static function removeDotSegments(string $path): string
    {
        if ($path === '' || $path === '/') {
            return $path;
        }

        $results = [];
        $segments = explode('/', $path);
        foreach ($segments as $segment) {
            if ($segment === '..') {
                array_pop($results);
            } elseif ($segment !== '.') {
                $results[] = $segment;
            }
        }

        $newPath = implode('/', $results);

        if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
            // Re-add the leading slash if necessary for cases like "/.."
            $newPath = '/'.$newPath;
        } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
            // Add the trailing slash if necessary
            // If newPath is not empty, then $segment must be set and is the last segment from the foreach
            $newPath .= '/';
        }

        return $newPath;
    }

    /**
     * Converts the relative URI into a new URI that is resolved against the base URI.
     *
     * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2
     */
    public static function resolve(UriInterface $base, UriInterface $rel): UriInterface
    {
        if ((string) $rel === '') {
            // we can simply return the same base URI instance for this same-document reference
            return $base;
        }

        if ($rel->getScheme() != '') {
            return $rel->withPath(self::removeDotSegments($rel->getPath()));
        }

        if ($rel->getAuthority() != '') {
            $targetAuthority = $rel->getAuthority();
            $targetPath = self::removeDotSegments($rel->getPath());
            $targetQuery = $rel->getQuery();
        } else {
            $targetAuthority = $base->getAuthority();
            if ($rel->getPath() === '') {
                $targetPath = $base->getPath();
                $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
            } else {
                if ($rel->getPath()[0] === '/') {
                    $targetPath = $rel->getPath();
                } else {
                    if ($targetAuthority != '' && $base->getPath() === '') {
                        $targetPath = '/'.$rel->getPath();
                    } else {
                        $lastSlashPos = strrpos($base->getPath(), '/');
                        if ($lastSlashPos === false) {
                            $targetPath = $rel->getPath();
                        } else {
                            $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1).$rel->getPath();
                        }
                    }
                }
                $targetPath = self::removeDotSegments($targetPath);
                $targetQuery = $rel->getQuery();
            }
        }

        return new Uri(Uri::composeComponents(
            $base->getScheme(),
            $targetAuthority,
            $targetPath,
            $targetQuery,
            $rel->getFragment()
        ));
    }

    /**
     * Returns the target URI as a relative reference from the base URI.
     *
     * This method is the counterpart to resolve():
     *
     *    (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
     *
     * One use-case is to use the current request URI as base URI and then generate relative links in your documents
     * to reduce the document size or offer self-contained downloadable document archives.
     *
     *    $base = new Uri('http://example.com/a/b/');
     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.
     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.
     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
     *    echo UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.
     *
     * This method also accepts a target that is already relative and will try to relativize it further. Only a
     * relative-path reference will be returned as-is.
     *
     *    echo UriResolver::relativize($base, new Uri('/a/b/c'));  // prints 'c' as well
     */
    public static function relativize(UriInterface $base, UriInterface $target): UriInterface
    {
        if ($target->getScheme() !== ''
            && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
        ) {
            return $target;
        }

        if (Uri::isRelativePathReference($target)) {
            // As the target is already highly relative we return it as-is. It would be possible to resolve
            // the target with `$target = self::resolve($base, $target);` and then try make it more relative
            // by removing a duplicate query. But let's not do that automatically.
            return $target;
        }

        if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
            return $target->withScheme('');
        }

        // We must remove the path before removing the authority because if the path starts with two slashes, the URI
        // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
        // invalid.
        $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');

        if ($base->getPath() !== $target->getPath()) {
            return $emptyPathUri->withPath(self::getRelativePath($base, $target));
        }

        if ($base->getQuery() === $target->getQuery()) {
            // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
            return $emptyPathUri->withQuery('');
        }

        // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
        // inherit the base query component when resolving.
        if ($target->getQuery() === '') {
            $segments = explode('/', $target->getPath());
            /** @var string $lastSegment */
            $lastSegment = end($segments);

            return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
        }

        return $emptyPathUri;
    }

    private static function getRelativePath(UriInterface $base, UriInterface $target): string
    {
        $sourceSegments = explode('/', $base->getPath());
        $targetSegments = explode('/', $target->getPath());
        array_pop($sourceSegments);
        $targetLastSegment = array_pop($targetSegments);
        foreach ($sourceSegments as $i => $segment) {
            if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
                unset($sourceSegments[$i], $targetSegments[$i]);
            } else {
                break;
            }
        }
        $targetSegments[] = $targetLastSegment;
        $relativePath = str_repeat('../', count($sourceSegments)).implode('/', $targetSegments);

        // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
        // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
        // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
        if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
            $relativePath = "./$relativePath";
        } elseif ('/' === $relativePath[0]) {
            if ($base->getAuthority() != '' && $base->getPath() === '') {
                // In this case an extra slash is added by resolve() automatically. So we must not add one here.
                $relativePath = ".$relativePath";
            } else {
                $relativePath = "./$relativePath";
            }
        }

        return $relativePath;
    }

    private function __construct()
    {
        // cannot be instantiated
    }
}
<?php

declare(strict_types=1);

namespace GuzzleHttp\Psr7;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

final class Utils
{
    /**
     * Remove the items given by the keys, case insensitively from the data.
     *
     * @param (string|int)[] $keys
     */
    public static function caselessRemove(array $keys, array $data): array
    {
        $result = [];

        foreach ($keys as &$key) {
            $key = strtolower((string) $key);
        }

        foreach ($data as $k => $v) {
            if (!in_array(strtolower((string) $k), $keys)) {
                $result[$k] = $v;
            }
        }

        return $result;
    }

    /**
     * Copy the contents of a stream into another stream until the given number
     * of bytes have been read.
     *
     * @param StreamInterface $source Stream to read from
     * @param StreamInterface $dest   Stream to write to
     * @param int             $maxLen Maximum number of bytes to read. Pass -1
     *                                to read the entire stream.
     *
     * @throws \RuntimeException on error.
     */
    public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1): void
    {
        $bufferSize = 8192;

        if ($maxLen === -1) {
            while (!$source->eof()) {
                if (!$dest->write($source->read($bufferSize))) {
                    break;
                }
            }
        } else {
            $remaining = $maxLen;
            while ($remaining > 0 && !$source->eof()) {
                $buf = $source->read(min($bufferSize, $remaining));
                $len = strlen($buf);
                if (!$len) {
                    break;
                }
                $remaining -= $len;
                $dest->write($buf);
            }
        }
    }

    /**
     * Copy the contents of a stream into a string until the given number of
     * bytes have been read.
     *
     * @param StreamInterface $stream Stream to read
     * @param int             $maxLen Maximum number of bytes to read. Pass -1
     *                                to read the entire stream.
     *
     * @throws \RuntimeException on error.
     */
    public static function copyToString(StreamInterface $stream, int $maxLen = -1): string
    {
        $buffer = '';

        if ($maxLen === -1) {
            while (!$stream->eof()) {
                $buf = $stream->read(1048576);
                if ($buf === '') {
                    break;
                }
                $buffer .= $buf;
            }

            return $buffer;
        }

        $len = 0;
        while (!$stream->eof() && $len < $maxLen) {
            $buf = $stream->read($maxLen - $len);
            if ($buf === '') {
                break;
            }
            $buffer .= $buf;
            $len = strlen($buffer);
        }

        return $buffer;
    }

    /**
     * Calculate a hash of a stream.
     *
     * This method reads the entire stream to calculate a rolling hash, based
     * on PHP's `hash_init` functions.
     *
     * @param StreamInterface $stream    Stream to calculate the hash for
     * @param string          $algo      Hash algorithm (e.g. md5, crc32, etc)
     * @param bool            $rawOutput Whether or not to use raw output
     *
     * @throws \RuntimeException on error.
     */
    public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = false): string
    {
        $pos = $stream->tell();

        if ($pos > 0) {
            $stream->rewind();
        }

        $ctx = hash_init($algo);
        while (!$stream->eof()) {
            hash_update($ctx, $stream->read(1048576));
        }

        $out = hash_final($ctx, $rawOutput);
        $stream->seek($pos);

        return $out;
    }

    /**
     * Clone and modify a request with the given changes.
     *
     * This method is useful for reducing the number of clones needed to mutate
     * a message.
     *
     * The changes can be one of:
     * - method: (string) Changes the HTTP method.
     * - set_headers: (array) Sets the given headers.
     * - remove_headers: (array) Remove the given headers.
     * - body: (mixed) Sets the given body.
     * - uri: (UriInterface) Set the URI.
     * - query: (string) Set the query string value of the URI.
     * - version: (string) Set the protocol version.
     *
     * @param RequestInterface $request Request to clone and modify.
     * @param array            $changes Changes to apply.
     */
    public static function modifyRequest(RequestInterface $request, array $changes): RequestInterface
    {
        if (!$changes) {
            return $request;
        }

        $headers = $request->getHeaders();

        if (!isset($changes['uri'])) {
            $uri = $request->getUri();
        } else {
            // Remove the host header if one is on the URI
            if ($host = $changes['uri']->getHost()) {
                $changes['set_headers']['Host'] = $host;

                if ($port = $changes['uri']->getPort()) {
                    $standardPorts = ['http' => 80, 'https' => 443];
                    $scheme = $changes['uri']->getScheme();
                    if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
                        $changes['set_headers']['Host'] .= ':'.$port;
                    }
                }
            }
            $uri = $changes['uri'];
        }

        if (!empty($changes['remove_headers'])) {
            $headers = self::caselessRemove($changes['remove_headers'], $headers);
        }

        if (!empty($changes['set_headers'])) {
            $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);
            $headers = $changes['set_headers'] + $headers;
        }

        if (isset($changes['query'])) {
            $uri = $uri->withQuery($changes['query']);
        }

        if ($request instanceof ServerRequestInterface) {
            $new = (new ServerRequest(
                $changes['method'] ?? $request->getMethod(),
                $uri,
                $headers,
                $changes['body'] ?? $request->getBody(),
                $changes['version'] ?? $request->getProtocolVersion(),
                $request->getServerParams()
            ))
            ->withParsedBody($request->getParsedBody())
            ->withQueryParams($request->getQueryParams())
            ->withCookieParams($request->getCookieParams())
            ->withUploadedFiles($request->getUploadedFiles());

            foreach ($request->getAttributes() as $key => $value) {
                $new = $new->withAttribute($key, $value);
            }

            return $new;
        }

        return new Request(
            $changes['method'] ?? $request->getMethod(),
            $uri,
            $headers,
            $changes['body'] ?? $request->getBody(),
            $changes['version'] ?? $request->getProtocolVersion()
        );
    }

    /**
     * Read a line from the stream up to the maximum allowed buffer length.
     *
     * @param StreamInterface $stream    Stream to read from
     * @param int|null        $maxLength Maximum buffer length
     */
    public static function readLine(StreamInterface $stream, ?int $maxLength = null): string
    {
        $buffer = '';
        $size = 0;

        while (!$stream->eof()) {
            if ('' === ($byte = $stream->read(1))) {
                return $buffer;
            }
            $buffer .= $byte;
            // Break when a new line is found or the max length - 1 is reached
            if ($byte === "\n" || ++$size === $maxLength - 1) {
                break;
            }
        }

        return $buffer;
    }

    /**
     * Redact the password in the user info part of a URI.
     */
    public static function redactUserInfo(UriInterface $uri): UriInterface
    {
        $userInfo = $uri->getUserInfo();

        if (false !== ($pos = \strpos($userInfo, ':'))) {
            return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
        }

        return $uri;
    }

    /**
     * Create a new stream based on the input type.
     *
     * Options is an associative array that can contain the following keys:
     * - metadata: Array of custom metadata.
     * - size: Size of the stream.
     *
     * This method accepts the following `$resource` types:
     * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
     * - `string`: Creates a stream object that uses the given string as the contents.
     * - `resource`: Creates a stream object that wraps the given PHP stream resource.
     * - `Iterator`: If the provided value implements `Iterator`, then a read-only
     *   stream object will be created that wraps the given iterable. Each time the
     *   stream is read from, data from the iterator will fill a buffer and will be
     *   continuously called until the buffer is equal to the requested read size.
     *   Subsequent read calls will first read from the buffer and then call `next`
     *   on the underlying iterator until it is exhausted.
     * - `object` with `__toString()`: If the object has the `__toString()` method,
     *   the object will be cast to a string and then a stream will be returned that
     *   uses the string value.
     * - `NULL`: When `null` is passed, an empty stream object is returned.
     * - `callable` When a callable is passed, a read-only stream object will be
     *   created that invokes the given callable. The callable is invoked with the
     *   number of suggested bytes to read. The callable can return any number of
     *   bytes, but MUST return `false` when there is no more data to return. The
     *   stream object that wraps the callable will invoke the callable until the
     *   number of requested bytes are available. Any additional bytes will be
     *   buffered and used in subsequent reads.
     *
     * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
     * @param array{size?: int, metadata?: array}                                    $options  Additional options
     *
     * @throws \InvalidArgumentException if the $resource arg is not valid.
     */
    public static function streamFor($resource = '', array $options = []): StreamInterface
    {
        if (is_scalar($resource)) {
            $stream = self::tryFopen('php://temp', 'r+');
            if ($resource !== '') {
                fwrite($stream, (string) $resource);
                fseek($stream, 0);
            }

            return new Stream($stream, $options);
        }

        switch (gettype($resource)) {
            case 'resource':
                /*
                 * The 'php://input' is a special stream with quirks and inconsistencies.
                 * We avoid using that stream by reading it into php://temp
                 */

                /** @var resource $resource */
                if ((\stream_get_meta_data($resource)['uri'] ?? '') === 'php://input') {
                    $stream = self::tryFopen('php://temp', 'w+');
                    stream_copy_to_stream($resource, $stream);
                    fseek($stream, 0);
                    $resource = $stream;
                }

                return new Stream($resource, $options);
            case 'object':
                /** @var object $resource */
                if ($resource instanceof StreamInterface) {
                    return $resource;
                } elseif ($resource instanceof \Iterator) {
                    return new PumpStream(function () use ($resource) {
                        if (!$resource->valid()) {
                            return false;
                        }
                        $result = $resource->current();
                        $resource->next();

                        return $result;
                    }, $options);
                } elseif (method_exists($resource, '__toString')) {
                    return self::streamFor((string) $resource, $options);
                }
                break;
            case 'NULL':
                return new Stream(self::tryFopen('php://temp', 'r+'), $options);
        }

        if (is_callable($resource)) {
            return new PumpStream($resource, $options);
        }

        throw new \InvalidArgumentException('Invalid resource type: '.gettype($resource));
    }

    /**
     * Safely opens a PHP stream resource using a filename.
     *
     * When fopen fails, PHP normally raises a warning. This function adds an
     * error handler that checks for errors and throws an exception instead.
     *
     * @param string $filename File to open
     * @param string $mode     Mode used to open the file
     *
     * @return resource
     *
     * @throws \RuntimeException if the file cannot be opened
     */
    public static function tryFopen(string $filename, string $mode)
    {
        $ex = null;
        set_error_handler(static function (int $errno, string $errstr) use ($filename, $mode, &$ex): bool {
            $ex = new \RuntimeException(sprintf(
                'Unable to open "%s" using mode "%s": %s',
                $filename,
                $mode,
                $errstr
            ));

            return true;
        });

        try {
            /** @var resource $handle */
            $handle = fopen($filename, $mode);
        } catch (\Throwable $e) {
            $ex = new \RuntimeException(sprintf(
                'Unable to open "%s" using mode "%s": %s',
                $filename,
                $mode,
                $e->getMessage()
            ), 0, $e);
        }

        restore_error_handler();

        if ($ex) {
            /** @var \RuntimeException $ex */
            throw $ex;
        }

        return $handle;
    }

    /**
     * Safely gets the contents of a given stream.
     *
     * When stream_get_contents fails, PHP normally raises a warning. This
     * function adds an error handler that checks for errors and throws an
     * exception instead.
     *
     * @param resource $stream
     *
     * @throws \RuntimeException if the stream cannot be read
     */
    public static function tryGetContents($stream): string
    {
        $ex = null;
        set_error_handler(static function (int $errno, string $errstr) use (&$ex): bool {
            $ex = new \RuntimeException(sprintf(
                'Unable to read stream contents: %s',
                $errstr
            ));

            return true;
        });

        try {
            /** @var string|false $contents */
            $contents = stream_get_contents($stream);

            if ($contents === false) {
                $ex = new \RuntimeException('Unable to read stream contents');
            }
        } catch (\Throwable $e) {
            $ex = new \RuntimeException(sprintf(
                'Unable to read stream contents: %s',
                $e->getMessage()
            ), 0, $e);
        }

        restore_error_handler();

        if ($ex) {
            /** @var \RuntimeException $ex */
            throw $ex;
        }

        return $contents;
    }

    /**
     * Returns a UriInterface for the given value.
     *
     * This function accepts a string or UriInterface and returns a
     * UriInterface for the given value. If the value is already a
     * UriInterface, it is returned as-is.
     *
     * @param string|UriInterface $uri
     *
     * @throws \InvalidArgumentException
     */
    public static function uriFor($uri): UriInterface
    {
        if ($uri instanceof UriInterface) {
            return $uri;
        }

        if (is_string($uri)) {
            return new Uri($uri);
        }

        throw new \InvalidArgumentException('URI must be a string or UriInterface');
    }
}
<?php

/**
 * URL constants as defined in the PHP Manual under "Constants usable with
 * http_build_url()".
 *
 * @see http://us2.php.net/manual/en/http.constants.php#http.constants.url
 */
if (!defined('HTTP_URL_REPLACE')) {
	define('HTTP_URL_REPLACE', 1);
}
if (!defined('HTTP_URL_JOIN_PATH')) {
	define('HTTP_URL_JOIN_PATH', 2);
}
if (!defined('HTTP_URL_JOIN_QUERY')) {
	define('HTTP_URL_JOIN_QUERY', 4);
}
if (!defined('HTTP_URL_STRIP_USER')) {
	define('HTTP_URL_STRIP_USER', 8);
}
if (!defined('HTTP_URL_STRIP_PASS')) {
	define('HTTP_URL_STRIP_PASS', 16);
}
if (!defined('HTTP_URL_STRIP_AUTH')) {
	define('HTTP_URL_STRIP_AUTH', 32);
}
if (!defined('HTTP_URL_STRIP_PORT')) {
	define('HTTP_URL_STRIP_PORT', 64);
}
if (!defined('HTTP_URL_STRIP_PATH')) {
	define('HTTP_URL_STRIP_PATH', 128);
}
if (!defined('HTTP_URL_STRIP_QUERY')) {
	define('HTTP_URL_STRIP_QUERY', 256);
}
if (!defined('HTTP_URL_STRIP_FRAGMENT')) {
	define('HTTP_URL_STRIP_FRAGMENT', 512);
}
if (!defined('HTTP_URL_STRIP_ALL')) {
	define('HTTP_URL_STRIP_ALL', 1024);
}

if (!function_exists('http_build_url')) {

	/**
	 * Build a URL.
	 *
	 * The parts of the second URL will be merged into the first according to
	 * the flags argument.
	 *
	 * @param mixed $url     (part(s) of) an URL in form of a string or
	 *                       associative array like parse_url() returns
	 * @param mixed $parts   same as the first argument
	 * @param int   $flags   a bitmask of binary or'ed HTTP_URL constants;
	 *                       HTTP_URL_REPLACE is the default
	 * @param array $new_url if set, it will be filled with the parts of the
	 *                       composed url like parse_url() would return
	 * @return string
	 */
	function http_build_url($url, $parts = array(), $flags = HTTP_URL_REPLACE, &$new_url = array())
	{
		is_array($url) || $url = parse_url($url);
		is_array($parts) || $parts = parse_url($parts);

		isset($url['query']) && is_string($url['query']) || $url['query'] = null;
		isset($parts['query']) && is_string($parts['query']) || $parts['query'] = null;

		$keys = array('user', 'pass', 'port', 'path', 'query', 'fragment');

		// HTTP_URL_STRIP_ALL and HTTP_URL_STRIP_AUTH cover several other flags.
		if ($flags & HTTP_URL_STRIP_ALL) {
			$flags |= HTTP_URL_STRIP_USER | HTTP_URL_STRIP_PASS
				| HTTP_URL_STRIP_PORT | HTTP_URL_STRIP_PATH
				| HTTP_URL_STRIP_QUERY | HTTP_URL_STRIP_FRAGMENT;
		} elseif ($flags & HTTP_URL_STRIP_AUTH) {
			$flags |= HTTP_URL_STRIP_USER | HTTP_URL_STRIP_PASS;
		}

		// Schema and host are alwasy replaced
		foreach (array('scheme', 'host') as $part) {
			if (isset($parts[$part])) {
				$url[$part] = $parts[$part];
			}
		}

		if ($flags & HTTP_URL_REPLACE) {
			foreach ($keys as $key) {
				if (isset($parts[$key])) {
					$url[$key] = $parts[$key];
				}
			}
		} else {
			if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH)) {
				if (isset($url['path']) && substr($parts['path'], 0, 1) !== '/') {
					// Workaround for trailing slashes
					$url['path'] .= 'a';
					$url['path'] = rtrim(
							str_replace(basename($url['path']), '', $url['path']),
							'/'
						) . '/' . ltrim($parts['path'], '/');
				} else {
					$url['path'] = $parts['path'];
				}
			}

			if (isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY)) {
				if (isset($url['query'])) {
					parse_str($url['query'], $url_query);
					parse_str($parts['query'], $parts_query);

					$url['query'] = http_build_query(
						array_replace_recursive(
							$url_query,
							$parts_query
						)
					);
				} else {
					$url['query'] = $parts['query'];
				}
			}
		}

		if (isset($url['path']) && $url['path'] !== '' && substr($url['path'], 0, 1) !== '/') {
			$url['path'] = '/' . $url['path'];
		}

		foreach ($keys as $key) {
			$strip = 'HTTP_URL_STRIP_' . strtoupper($key);
			if ($flags & constant($strip)) {
				unset($url[$key]);
			}
		}

		$parsed_string = '';

		if (!empty($url['scheme'])) {
			$parsed_string .= $url['scheme'] . '://';
		}

		if (!empty($url['user'])) {
			$parsed_string .= $url['user'];

			if (isset($url['pass'])) {
				$parsed_string .= ':' . $url['pass'];
			}

			$parsed_string .= '@';
		}

		if (!empty($url['host'])) {
			$parsed_string .= $url['host'];
		}

		if (!empty($url['port'])) {
			$parsed_string .= ':' . $url['port'];
		}

		if (!empty($url['path'])) {
			$parsed_string .= $url['path'];
		}

		if (!empty($url['query'])) {
			$parsed_string .= '?' . $url['query'];
		}

		if (!empty($url['fragment'])) {
			$parsed_string .= '#' . $url['fragment'];
		}

		$new_url = $url;

		return $parsed_string;
	}
}
<?php
require dirname( __DIR__ ) . '/src/http_build_url.php';

// PHPUnit 6 compatibility for previous versions
if ( class_exists( 'PHPUnit\Runner\Version' ) && version_compare( PHPUnit\Runner\Version::id(), '6.0', '>=' ) ) {
    class_alias( 'PHPUnit\Framework\Assert',        'PHPUnit_Framework_Assert' );
    class_alias( 'PHPUnit\Framework\TestCase',      'PHPUnit_Framework_TestCase' );
    class_alias( 'PHPUnit\Framework\Error\Error',   'PHPUnit_Framework_Error' );
    class_alias( 'PHPUnit\Framework\Error\Notice',  'PHPUnit_Framework_Error_Notice' );
    class_alias( 'PHPUnit\Framework\Error\Warning', 'PHPUnit_Framework_Error_Warning' );
}

// Past this point, tests will start
<?php

class HttpBuildUrlTest extends \PHPUnit_Framework_TestCase
{
	private $full_url = "http://user:pass@www.example.com:8080/pub/index.php?a=b#files";

	/**
	 * Test example one.
	 *
	 * @see http://us2.php.net/manual/en/function.http-build-url.php
	 */
	public function testExampleOne()
	{
		$expected = 'ftp://ftp.example.com/pub/files/current/?a=c';
		$actual   = http_build_url(
			"http://user@www.example.com/pub/index.php?a=b#files",
			array(
				"scheme" => "ftp",
				"host"   => "ftp.example.com",
				"path"   => "files/current/",
				"query"  => "a=c"
			),
			HTTP_URL_STRIP_AUTH | HTTP_URL_JOIN_PATH | HTTP_URL_JOIN_QUERY | HTTP_URL_STRIP_FRAGMENT
		);

		$this->assertSame($expected, $actual);
	}

	public function trailingSlashProvider()
	{
		return array(
			array(
				'http://example.com',
				array(
					'scheme' => 'http',
					'host' => 'example.com'
				)
			),
			array(
				'http://example.com',
				array(
					'scheme' => 'http',
					'host' => 'example.com',
					'path' => ''
				)
			),
			array(
				'http://example.com/',
				array(
					'scheme' => 'http',
					'host' => 'example.com',
					'path' => '/'
				)
			),
			array(
				'http://example.com/yes',
				array(
					'scheme' => 'http',
					'host' => 'example.com',
					'path' => 'yes'
				)
			),
			array(
				'http://example.com/yes',
				array(
					'scheme' => 'http',
					'host' => 'example.com',
					'path' => '/yes'
				)
			),
			array(
				'http://example.com:81?a=b',
				array(
					'scheme' => 'http',
					'host' => 'example.com',
					'query' => 'a=b',
					'port' => 81
				)
			)
		);
	}

	/**
	 * @dataProvider trailingSlashProvider
	 */
	public function testTrailingSlash($expected, $config)
	{
		$this->assertEquals($expected, http_build_url($config));
	}

	public function testUrlQueryArrayIsIgnored()
	{
		$expected = 'http://user:pass@www.example.com:8080/pub/index.php#files';
		$url      = parse_url($this->full_url);
		parse_str($url['query'], $url['query']);
		$actual = http_build_url($url);

		$this->assertSame($expected, $actual);
	}

	public function testPartsQueryArrayIsIgnored()
	{
		$expected = $this->full_url;
		$actual   = http_build_url($this->full_url, array('query' => array('foo' => 'bar')));

		$this->assertSame($expected, $actual);
	}

	public function testAcceptStrings()
	{
		$expected = 'http://user:pass@foobar.com:8080/pub/index.php?a=b#files';
		$actual   = http_build_url($this->full_url, 'http://foobar.com:8080');

		$this->assertSame($expected, $actual);
	}

	public function testAcceptArrays()
	{
		$expected = 'http://user:pass@foobar.com:8080/pub/index.php?a=b#files';
		$actual   = http_build_url(parse_url($this->full_url), parse_url('http://foobar.com:8080'));

		$this->assertSame($expected, $actual);
	}

	public function testDefaults()
	{
		$expected = $this->full_url;
		$actual   = http_build_url($this->full_url);

		$this->assertSame($expected, $actual);
	}

	public function testNewUrl()
	{
		$expected = parse_url($this->full_url);
		http_build_url($this->full_url, null, null, $actual);

		$this->assertEquals($expected, $actual);
	}

	/**
	 * @dataProvider queryProvider
	 */
	public function testJoinQuery($query, $expected)
	{
		$actual = http_build_url($this->full_url, array('query' => $query), HTTP_URL_JOIN_QUERY);

		$this->assertSame($expected, $actual);
	}

	/**
	 * @dataProvider pathProvider
	 */
	public function testJoinPath($path, $expected)
	{
		$actual = http_build_url($this->full_url, array('path' => $path), HTTP_URL_JOIN_PATH);

		$this->assertSame($expected, $actual);
	}

	public function testJoinPathTwo()
	{
		$expected = "http://site.testing.com/preview/testing/09-2013/p04/image/15.jpg";
		$actual = http_build_url(
			"http://site.testing.com/preview/testing/09-2013/p04/?code=asdfghjkl",
			array('path' => 'image/15.jpg'),
			HTTP_URL_JOIN_PATH | HTTP_URL_STRIP_FRAGMENT | HTTP_URL_STRIP_QUERY
		);

		$this->assertSame($expected, $actual);
	}

	/**
	 * @dataProvider bitmaskProvider
	 */
	public function testBitmasks($constant, $expected)
	{
		$actual = http_build_url($this->full_url, array(), constant($constant));

		$this->assertSame($expected, $actual);
	}

	public function pathProvider()
	{
		return array(
			array('/donuts/brownies', 'http://user:pass@www.example.com:8080/donuts/brownies?a=b#files'),
			array('chicken/wings', 'http://user:pass@www.example.com:8080/pub/chicken/wings?a=b#files'),
			array('sausage/bacon/', 'http://user:pass@www.example.com:8080/pub/sausage/bacon/?a=b#files')
		);
	}

	public function queryProvider()
	{
		return array(
			array('a=c', 'http://user:pass@www.example.com:8080/pub/index.php?a=c#files'),
			array('d=a', 'http://user:pass@www.example.com:8080/pub/index.php?a=b&d=a#files')
		);
	}

	public function bitmaskProvider()
	{
		return array(
			array('HTTP_URL_REPLACE', 'http://user:pass@www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_JOIN_PATH', 'http://user:pass@www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_JOIN_QUERY', 'http://user:pass@www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_STRIP_USER', 'http://www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_STRIP_PASS', 'http://user@www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_STRIP_AUTH', 'http://www.example.com:8080/pub/index.php?a=b#files'),
			array('HTTP_URL_STRIP_PORT', 'http://user:pass@www.example.com/pub/index.php?a=b#files'),
			array('HTTP_URL_STRIP_PATH', 'http://user:pass@www.example.com:8080?a=b#files'),
			array('HTTP_URL_STRIP_QUERY', 'http://user:pass@www.example.com:8080/pub/index.php#files'),
			array('HTTP_URL_STRIP_FRAGMENT', 'http://user:pass@www.example.com:8080/pub/index.php?a=b'),
			array('HTTP_URL_STRIP_ALL', 'http://www.example.com'),
		);
	}
}
<?php
/**
 * Random_* Compatibility Library
 * for using the new PHP 7 random_* API in PHP 5 projects
 *
 * @version 2.99.99
 * @released 2018-06-06
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
 *
 * 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.
 */

// NOP
<?php
$dist = dirname(__DIR__).'/dist';
if (!is_dir($dist)) {
    mkdir($dist, 0755);
}
if (file_exists($dist.'/random_compat.phar')) {
    unlink($dist.'/random_compat.phar');
}
$phar = new Phar(
    $dist.'/random_compat.phar',
    FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_FILENAME,
    'random_compat.phar'
);
rename(
    dirname(__DIR__).'/lib/random.php', 
    dirname(__DIR__).'/lib/index.php'
);
$phar->buildFromDirectory(dirname(__DIR__).'/lib');
rename(
    dirname(__DIR__).'/lib/index.php', 
    dirname(__DIR__).'/lib/random.php'
);

/**
 * If we pass an (optional) path to a private key as a second argument, we will
 * sign the Phar with OpenSSL.
 * 
 * If you leave this out, it will produce an unsigned .phar!
 */
if ($argc > 1) {
    if (!@is_readable($argv[1])) {
        echo 'Could not read the private key file:', $argv[1], "\n";
        exit(255);
    }
    $pkeyFile = file_get_contents($argv[1]);
    
    $private = openssl_get_privatekey($pkeyFile);
    if ($private !== false) {
        $pkey = '';
        openssl_pkey_export($private, $pkey);
        $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
        
        /**
         * Save the corresponding public key to the file
         */
        if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
            $details = openssl_pkey_get_details($private);
            file_put_contents(
                $dist.'/random_compat.phar.pubkey',
                $details['key']
            );
        }
    } else {
        echo 'An error occurred reading the private key from OpenSSL.', "\n";
        exit(255);
    }
}
<?php

require_once 'lib/byte_safe_strings.php';
require_once 'lib/cast_to_int.php';
require_once 'lib/error_polyfill.php';
require_once 'other/ide_stubs/libsodium.php';
require_once 'lib/random.php';

$int = random_int(0, 65536);
<?php

$loader = require_once __DIR__ . '/vendor/autoload.php';

$consoleColor = new PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor();

echo "Colors are supported: " . ($consoleColor->isSupported() ? 'Yes' : 'No') . "\n";
echo "256 colors are supported: " . ($consoleColor->are256ColorsSupported() ? 'Yes' : 'No') . "\n\n";

if ($consoleColor->isSupported()) {
    foreach ($consoleColor->getPossibleStyles() as $style) {
        echo $consoleColor->apply($style, $style) . "\n";
    }
}

echo "\n";

if ($consoleColor->are256ColorsSupported()) {
    echo "Foreground colors:\n";
    for ($i = 1; $i <= 255; $i++) {
        echo $consoleColor->apply("color_$i", str_pad($i, 6, ' ', STR_PAD_BOTH));

        if ($i % 15 === 0) {
            echo "\n";
        }
    }

    echo "\nBackground colors:\n";

    for ($i = 1; $i <= 255; $i++) {
        echo $consoleColor->apply("bg_color_$i", str_pad($i, 6, ' ', STR_PAD_BOTH));

        if ($i % 15 === 0) {
            echo "\n";
        }
    }

    echo "\n";
}
<?php

namespace PHP_Parallel_Lint\PhpConsoleColor;

class ConsoleColor
{
    const FOREGROUND = 38,
        BACKGROUND = 48;

    const COLOR256_REGEXP = '~^(bg_)?color_([0-9]{1,3})$~';

    const RESET_STYLE = 0;

    /** @var bool */
    private $isSupported;

    /** @var bool */
    private $forceStyle = false;

    /** @var array */
    private $styles = array(
        'none' => null,
        'bold' => '1',
        'dark' => '2',
        'italic' => '3',
        'underline' => '4',
        'blink' => '5',
        'reverse' => '7',
        'concealed' => '8',

        'default' => '39',
        'black' => '30',
        'red' => '31',
        'green' => '32',
        'yellow' => '33',
        'blue' => '34',
        'magenta' => '35',
        'cyan' => '36',
        'light_gray' => '37',

        'dark_gray' => '90',
        'light_red' => '91',
        'light_green' => '92',
        'light_yellow' => '93',
        'light_blue' => '94',
        'light_magenta' => '95',
        'light_cyan' => '96',
        'white' => '97',

        'bg_default' => '49',
        'bg_black' => '40',
        'bg_red' => '41',
        'bg_green' => '42',
        'bg_yellow' => '43',
        'bg_blue' => '44',
        'bg_magenta' => '45',
        'bg_cyan' => '46',
        'bg_light_gray' => '47',

        'bg_dark_gray' => '100',
        'bg_light_red' => '101',
        'bg_light_green' => '102',
        'bg_light_yellow' => '103',
        'bg_light_blue' => '104',
        'bg_light_magenta' => '105',
        'bg_light_cyan' => '106',
        'bg_white' => '107',
    );

    /** @var array */
    private $themes = array();

    public function __construct()
    {
        $this->isSupported = $this->isSupported();
    }

    /**
     * @param string|array $style
     * @param string $text
     * @return string
     * @throws InvalidStyleException
     * @throws \InvalidArgumentException
     */
    public function apply($style, $text)
    {
        if (!$this->isStyleForced() && !$this->isSupported()) {
            return $text;
        }

        if (is_string($style)) {
            $style = array($style);
        }
        if (!is_array($style)) {
            throw new \InvalidArgumentException("Style must be string or array.");
        }

        $sequences = array();

        foreach ($style as $s) {
            if (isset($this->themes[$s])) {
                $sequences = array_merge($sequences, $this->themeSequence($s));
            } elseif ($this->isValidStyle($s)) {
                $sequences[] = $this->styleSequence($s);
            } else {
                throw new InvalidStyleException($s);
            }
        }

        $sequences = array_filter($sequences, function ($val) {
            return $val !== null;
        });

        if (empty($sequences)) {
            return $text;
        }

        return $this->escSequence(implode(';', $sequences)) . $text . $this->escSequence(self::RESET_STYLE);
    }

    /**
     * @param bool $forceStyle
     */
    public function setForceStyle($forceStyle)
    {
        $this->forceStyle = (bool) $forceStyle;
    }

    /**
     * @return bool
     */
    public function isStyleForced()
    {
        return $this->forceStyle;
    }

    /**
     * @param array $themes
     * @throws InvalidStyleException
     * @throws \InvalidArgumentException
     */
    public function setThemes(array $themes)
    {
        $this->themes = array();
        foreach ($themes as $name => $styles) {
            $this->addTheme($name, $styles);
        }
    }

    /**
     * @param string $name
     * @param array|string $styles
     * @throws \InvalidArgumentException
     * @throws InvalidStyleException
     */
    public function addTheme($name, $styles)
    {
        if (is_string($styles)) {
            $styles = array($styles);
        }
        if (!is_array($styles)) {
            throw new \InvalidArgumentException("Style must be string or array.");
        }

        foreach ($styles as $style) {
            if (!$this->isValidStyle($style)) {
                throw new InvalidStyleException($style);
            }
        }

        $this->themes[$name] = $styles;
    }

    /**
     * @return array
     */
    public function getThemes()
    {
        return $this->themes;
    }

    /**
     * @param string $name
     * @return bool
     */
    public function hasTheme($name)
    {
        return isset($this->themes[$name]);
    }

    /**
     * @param string $name
     */
    public function removeTheme($name)
    {
        unset($this->themes[$name]);
    }

    /**
     * @codeCoverageIgnore
     *
     * @return bool
     */
    public function isSupported()
    {
        if (DIRECTORY_SEPARATOR === '\\') {
            // phpcs:ignore Generic.PHP.NoSilencedErrors,PHPCompatibility.FunctionUse.NewFunctions.sapi_windows_vt100_supportFound
            if (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) {
                return true;
            } elseif (getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON') {
                return true;
            }
            return false;
        } else {
            // phpcs:ignore Generic.PHP.NoSilencedErrors
            return function_exists('posix_isatty') && @posix_isatty(STDOUT);
        }
    }

    /**
     * @codeCoverageIgnore
     *
     * @return bool
     */
    public function are256ColorsSupported()
    {
        if (DIRECTORY_SEPARATOR === '\\') {
            // phpcs:ignore Generic.PHP.NoSilencedErrors,PHPCompatibility.FunctionUse.NewFunctions.sapi_windows_vt100_supportFound
            return function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT);
        } else {
            return strpos(getenv('TERM'), '256color') !== false;
        }
    }

    /**
     * @return array
     */
    public function getPossibleStyles()
    {
        return array_keys($this->styles);
    }

    /**
     * @param string $name
     * @return string[]
     */
    private function themeSequence($name)
    {
        $sequences = array();
        foreach ($this->themes[$name] as $style) {
            $sequences[] = $this->styleSequence($style);
        }
        return $sequences;
    }

    /**
     * @param string $style
     * @return string
     */
    private function styleSequence($style)
    {
        if (array_key_exists($style, $this->styles)) {
            return $this->styles[$style];
        }

        if (!$this->are256ColorsSupported()) {
            return null;
        }

        preg_match(self::COLOR256_REGEXP, $style, $matches);

        $type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND;
        $value = $matches[2];

        return "$type;5;$value";
    }

    /**
     * @param string $style
     * @return bool
     */
    private function isValidStyle($style)
    {
        return array_key_exists($style, $this->styles) || preg_match(self::COLOR256_REGEXP, $style);
    }

    /**
     * @param string|int $value
     * @return string
     */
    private function escSequence($value)
    {
        return "\033[{$value}m";
    }
}
<?php

namespace PHP_Parallel_Lint\PhpConsoleColor;

class InvalidStyleException extends \Exception
{
    public function __construct($styleName)
    {
        parent::__construct("Invalid style $styleName.");
    }
}
<?php

namespace PHP_Parallel_Lint\PhpConsoleHighlighter;

use PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor;

class Highlighter
{
    const TOKEN_DEFAULT = 'token_default',
        TOKEN_COMMENT = 'token_comment',
        TOKEN_STRING = 'token_string',
        TOKEN_HTML = 'token_html',
        TOKEN_KEYWORD = 'token_keyword';

    const ACTUAL_LINE_MARK = 'actual_line_mark',
        LINE_NUMBER = 'line_number';

    /** @var ConsoleColor */
    private $color;

    /** @var array */
    private $defaultTheme = array(
        self::TOKEN_STRING => 'red',
        self::TOKEN_COMMENT => 'yellow',
        self::TOKEN_KEYWORD => 'green',
        self::TOKEN_DEFAULT => 'default',
        self::TOKEN_HTML => 'cyan',

        self::ACTUAL_LINE_MARK  => 'red',
        self::LINE_NUMBER => 'dark_gray',
    );

    /** @var array */
    private $phpTagTokens = array(
        T_OPEN_TAG           => T_OPEN_TAG,
        T_OPEN_TAG_WITH_ECHO => T_OPEN_TAG_WITH_ECHO,
        T_CLOSE_TAG          => T_CLOSE_TAG,
    );

    /** @var array */
    private $magicConstantTokens = array(
        T_DIR      => T_DIR,
        T_FILE     => T_FILE,
        T_LINE     => T_LINE,
        T_CLASS_C  => T_CLASS_C,
        T_FUNC_C   => T_FUNC_C,
        T_METHOD_C => T_METHOD_C,
        T_NS_C     => T_NS_C,
    );

    /** @var array */
    private $miscTokens = array(
        T_STRING   => T_STRING, // Labels.
        T_VARIABLE => T_VARIABLE,
        T_DNUMBER  => T_DNUMBER, // Floats.
        T_LNUMBER  => T_LNUMBER, // Integers.
    );

    /** @var array */
    private $commentTokens = array(
        T_COMMENT     => T_COMMENT,
        T_DOC_COMMENT => T_DOC_COMMENT,
    );

    /** @var array */
    private $textStringTokens = array(
        T_ENCAPSED_AND_WHITESPACE  => T_ENCAPSED_AND_WHITESPACE,
        T_CONSTANT_ENCAPSED_STRING => T_CONSTANT_ENCAPSED_STRING,
    );

    /** @var array */
    private $htmlTokens = array(
        T_INLINE_HTML => T_INLINE_HTML,
    );

    /**
     * @param ConsoleColor $color
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     */
    public function __construct(ConsoleColor $color)
    {
        $this->color = $color;

        foreach ($this->defaultTheme as $name => $styles) {
            if (!$this->color->hasTheme($name)) {
                $this->color->addTheme($name, $styles);
            }
        }
    }

    /**
     * @param string $source
     * @param int $lineNumber
     * @param int $linesBefore
     * @param int $linesAfter
     * @return string
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     * @throws \InvalidArgumentException
     */
    public function getCodeSnippet($source, $lineNumber, $linesBefore = 2, $linesAfter = 2)
    {
        $tokenLines = $this->getHighlightedLines($source);

        $offset = $lineNumber - $linesBefore - 1;
        $offset = max($offset, 0);

        if ($lineNumber <= $linesBefore) {
            $length = $lineNumber + $linesAfter;
        } else {
            $length = $linesAfter + $linesBefore + 1;
        }

        $tokenLines = array_slice($tokenLines, $offset, $length, $preserveKeys = true);

        $lines = $this->colorLines($tokenLines);

        return $this->lineNumbers($lines, $lineNumber);
    }

    /**
     * @param string $source
     * @return string
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     * @throws \InvalidArgumentException
     */
    public function getWholeFile($source)
    {
        $tokenLines = $this->getHighlightedLines($source);
        $lines = $this->colorLines($tokenLines);
        return implode(PHP_EOL, $lines);
    }

    /**
     * @param string $source
     * @return string
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     * @throws \InvalidArgumentException
     */
    public function getWholeFileWithLineNumbers($source)
    {
        $tokenLines = $this->getHighlightedLines($source);
        $lines = $this->colorLines($tokenLines);
        return $this->lineNumbers($lines);
    }

    /**
     * @param string $source
     * @return array
     */
    private function getHighlightedLines($source)
    {
        $source = str_replace(array("\r\n", "\r"), "\n", $source);
        $tokens = $this->tokenize($source);
        return $this->splitToLines($tokens);
    }

    /**
     * @param string $source
     * @return array
     */
    private function tokenize($source)
    {
        $tokens = token_get_all($source);

        $output = array();
        $currentType = null;
        $buffer = '';

        foreach ($tokens as $token) {
            if (is_array($token)) {
                if ($token[0] !== T_WHITESPACE) {
                    $newType = $this->getTokenType($token);
                }
            } else {
                $newType = $token === '"' ? self::TOKEN_STRING : self::TOKEN_KEYWORD;
            }

            if ($currentType === null) {
                $currentType = $newType;
            }

            if ($currentType !== $newType) {
                $output[] = array($currentType, $buffer);
                $buffer = '';
                $currentType = $newType;
            }

            $buffer .= is_array($token) ? $token[1] : $token;
        }

        if (isset($newType)) {
            $output[] = array($newType, $buffer);
        }

        return $output;
    }

    /**
     * @param array $arrayToken
     * @return string
     */
    private function getTokenType($arrayToken)
    {
        switch (true) {
            case isset($this->phpTagTokens[$arrayToken[0]]):
            case isset($this->magicConstantTokens[$arrayToken[0]]):
            case isset($this->miscTokens[$arrayToken[0]]):
                return self::TOKEN_DEFAULT;

            case isset($this->commentTokens[$arrayToken[0]]):
                return self::TOKEN_COMMENT;

            case isset($this->textStringTokens[$arrayToken[0]]):
                return self::TOKEN_STRING;

            case isset($this->htmlTokens[$arrayToken[0]]):
                return self::TOKEN_HTML;
        }

        // phpcs:disable PHPCompatibility.Constants.NewConstants -- The new token constants are only used when defined.

        // Traits didn't exist in PHP 5.3 yet, so the trait magic constant needs special casing for PHP >= 5.4.
        // __TRAIT__ will tokenize as T_STRING in PHP 5.3, so, the end result will be the same cross-version.
        if (defined('T_TRAIT_C') && $arrayToken[0] === T_TRAIT_C) {
            return self::TOKEN_DEFAULT;
        }

        // Handle PHP >= 8.0 namespaced name tokens.
        // https://www.php.net/manual/en/migration80.incompatible.php#migration80.incompatible.tokenizer
        if (
            (defined('T_NAME_QUALIFIED') && $arrayToken[0] === T_NAME_QUALIFIED)
            || (defined('T_NAME_FULLY_QUALIFIED') && $arrayToken[0] === T_NAME_FULLY_QUALIFIED)
            || (defined('T_NAME_RELATIVE') && $arrayToken[0] === T_NAME_RELATIVE)
        ) {
            return self::TOKEN_DEFAULT;
        }

        // phpcs:enable

        return self::TOKEN_KEYWORD;
    }

    /**
     * @param array $tokens
     * @return array
     */
    private function splitToLines(array $tokens)
    {
        $lines = array();

        $line = array();
        foreach ($tokens as $token) {
            foreach (explode("\n", $token[1]) as $count => $tokenLine) {
                if ($count > 0) {
                    $lines[] = $line;
                    $line = array();
                }

                if ($tokenLine === '') {
                    continue;
                }

                $line[] = array($token[0], $tokenLine);
            }
        }

        $lines[] = $line;

        return $lines;
    }

    /**
     * @param array $tokenLines
     * @return array
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     * @throws \InvalidArgumentException
     */
    private function colorLines(array $tokenLines)
    {
        $lines = array();
        foreach ($tokenLines as $lineCount => $tokenLine) {
            $line = '';
            foreach ($tokenLine as $token) {
                list($tokenType, $tokenValue) = $token;
                if ($this->color->hasTheme($tokenType)) {
                    $line .= $this->color->apply($tokenType, $tokenValue);
                } else {
                    $line .= $tokenValue;
                }
            }
            $lines[$lineCount] = $line;
        }

        return $lines;
    }

    /**
     * @param array $lines
     * @param null|int $markLine
     * @return string
     * @throws \PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException
     */
    private function lineNumbers(array $lines, $markLine = null)
    {
        end($lines);
        $lineStrlen = strlen(key($lines) + 1);

        $snippet = '';
        foreach ($lines as $i => $line) {
            if ($markLine !== null) {
                $snippet .= ($markLine === $i + 1 ? $this->color->apply(self::ACTUAL_LINE_MARK, '  > ') : '    ');
            }

            $snippet .= $this->color->apply(self::LINE_NUMBER, str_pad($i + 1, $lineStrlen, ' ', STR_PAD_LEFT) . '| ');
            $snippet .= $line . PHP_EOL;
        }

        return rtrim($snippet, PHP_EOL);
    }
}
<?php

declare(strict_types=1);

/**
 * phpDocumentor
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * Interface for Api Elements
 */
interface Element
{
    /**
     * Returns the Fqsen of the element.
     */
    public function getFqsen() : Fqsen;

    /**
     * Returns the name of the element.
     */
    public function getName() : string;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * Interface for files processed by the ProjectFactory
 */
interface File
{
    /**
     * Returns the content of the file as a string.
     */
    public function getContents() : string;

    /**
     * Returns md5 hash of the file.
     */
    public function md5() : string;

    /**
     * Returns an relative path to the file.
     */
    public function path() : string;
}
<?php

declare(strict_types=1);

/**
 * phpDocumentor
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use function assert;
use function end;
use function explode;
use function is_string;
use function preg_match;
use function sprintf;
use function trim;

/**
 * Value Object for Fqsen.
 *
 * @link https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc-meta.md
 *
 * @psalm-immutable
 */
final class Fqsen
{
    /** @var string full quallified class name */
    private $fqsen;

    /** @var string name of the element without path. */
    private $name;

    /**
     * Initializes the object.
     *
     * @throws InvalidArgumentException when $fqsen is not matching the format.
     */
    public function __construct(string $fqsen)
    {
        $matches = [];

        $result = preg_match(
            //phpcs:ignore Generic.Files.LineLength.TooLong
            '/^\\\\([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff\\\\]*)?(?:[:]{2}\\$?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*))?(?:\\(\\))?$/',
            $fqsen,
            $matches
        );

        if ($result === 0) {
            throw new InvalidArgumentException(
                sprintf('"%s" is not a valid Fqsen.', $fqsen)
            );
        }

        $this->fqsen = $fqsen;

        if (isset($matches[2])) {
            $this->name = $matches[2];
        } else {
            $matches = explode('\\', $fqsen);
            $name = end($matches);
            assert(is_string($name));
            $this->name = trim($name, '()');
        }
    }

    /**
     * converts this class to string.
     */
    public function __toString() : string
    {
        return $this->fqsen;
    }

    /**
     * Returns the name of the element without path.
     */
    public function getName() : string
    {
        return $this->name;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * The location where an element occurs within a file.
 *
 * @psalm-immutable
 */
final class Location
{
    /** @var int */
    private $lineNumber = 0;

    /** @var int */
    private $columnNumber = 0;

    /**
     * Initializes the location for an element using its line number in the file and optionally the column number.
     */
    public function __construct(int $lineNumber, int $columnNumber = 0)
    {
        $this->lineNumber = $lineNumber;
        $this->columnNumber = $columnNumber;
    }

    /**
     * Returns the line number that is covered by this location.
     */
    public function getLineNumber() : int
    {
        return $this->lineNumber;
    }

    /**
     * Returns the column number (character position on a line) for this location object.
     */
    public function getColumnNumber() : int
    {
        return $this->columnNumber;
    }
}
<?php

declare(strict_types=1);

/**
 * phpDocumentor
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * Interface for project. Since the definition of a project can be different per factory this interface will be small.
 */
interface Project
{
    /**
     * Returns the name of the project.
     */
    public function getName() : string;
}
<?php

declare(strict_types=1);

/**
 * phpDocumentor
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * Interface for project factories. A project factory shall convert a set of files
 * into an object implementing the Project interface.
 */
interface ProjectFactory
{
    /**
     * Creates a project from the set of files.
     *
     * @param File[] $files
     */
    public function create(string $name, array $files) : Project;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;

use function vsprintf;

/**
 * Object representing to description for a DocBlock.
 *
 * A Description object can consist of plain text but can also include tags. A Description Formatter can then combine
 * a body template with sprintf-style placeholders together with formatted tags in order to reconstitute a complete
 * description text using the format that you would prefer.
 *
 * Because parsing a Description text can be a verbose process this is handled by the {@see DescriptionFactory}. It is
 * thus recommended to use that to create a Description object, like this:
 *
 *     $description = $descriptionFactory->create('This is a {@see Description}', $context);
 *
 * The description factory will interpret the given body and create a body template and list of tags from them, and pass
 * that onto the constructor if this class.
 *
 * > The $context variable is a class of type {@see \phpDocumentor\Reflection\Types\Context} and contains the namespace
 * > and the namespace aliases that apply to this DocBlock. These are used by the Factory to resolve and expand partial
 * > type names and FQSENs.
 *
 * If you do not want to use the DescriptionFactory you can pass a body template and tag listing like this:
 *
 *     $description = new Description(
 *         'This is a %1$s',
 *         [ new See(new Fqsen('\phpDocumentor\Reflection\DocBlock\Description')) ]
 *     );
 *
 * It is generally recommended to use the Factory as that will also apply escaping rules, while the Description object
 * is mainly responsible for rendering.
 *
 * @see DescriptionFactory to create a new Description.
 * @see Tags\Formatter for the formatting of the body and tags.
 */
class Description
{
    private string $bodyTemplate;

    /** @var Tag[] */
    private array $tags;

    /**
     * Initializes a Description with its body (template) and a listing of the tags used in the body template.
     *
     * @param Tag[] $tags
     */
    public function __construct(string $bodyTemplate, array $tags = [])
    {
        $this->bodyTemplate = $bodyTemplate;
        $this->tags         = $tags;
    }

    /**
     * Returns the body template.
     */
    public function getBodyTemplate(): string
    {
        return $this->bodyTemplate;
    }

    /**
     * Returns the tags for this DocBlock.
     *
     * @return Tag[]
     */
    public function getTags(): array
    {
        return $this->tags;
    }

    /**
     * Renders this description as a string where the provided formatter will format the tags in the expected string
     * format.
     */
    public function render(?Formatter $formatter = null): string
    {
        if ($this->tags === []) {
            return vsprintf($this->bodyTemplate, []);
        }

        if ($formatter === null) {
            $formatter = new PassthroughFormatter();
        }

        $tags = [];
        foreach ($this->tags as $tag) {
            $tags[] = '{' . $formatter->format($tag) . '}';
        }

        return vsprintf($this->bodyTemplate, $tags);
    }

    /**
     * Returns a plain string representation of this description.
     */
    public function __toString(): string
    {
        return $this->render();
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;

use function count;
use function implode;
use function ltrim;
use function min;
use function str_replace;
use function strlen;
use function strpos;
use function substr;
use function trim;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Creates a new Description object given a body of text.
 *
 * Descriptions in phpDocumentor are somewhat complex entities as they can contain one or more tags inside their
 * body that can be replaced with a readable output. The replacing is done by passing a Formatter object to the
 * Description object's `render` method.
 *
 * In addition to the above does a Description support two types of escape sequences:
 *
 * 1. `{@}` to escape the `@` character to prevent it from being interpreted as part of a tag, i.e. `{{@}link}`
 * 2. `{}` to escape the `}` character, this can be used if you want to use the `}` character in the description
 *    of an inline tag.
 *
 * If a body consists of multiple lines then this factory will also remove any superfluous whitespace at the beginning
 * of each line while maintaining any indentation that is used. This will prevent formatting parsers from tripping
 * over unexpected spaces as can be observed with tag descriptions.
 */
class DescriptionFactory
{
    private Factory $tagFactory;

    /**
     * Initializes this factory with the means to construct (inline) tags.
     */
    public function __construct(Factory $tagFactory)
    {
        $this->tagFactory = $tagFactory;
    }

    /**
     * Returns the parsed text of this description.
     */
    public function create(string $contents, ?TypeContext $context = null): Description
    {
        $tokens   = $this->lex($contents);
        $count    = count($tokens);
        $tagCount = 0;
        $tags     = [];

        for ($i = 1; $i < $count; $i += 2) {
            $tags[]     = $this->tagFactory->create($tokens[$i], $context);
            $tokens[$i] = '%' . ++$tagCount . '$s';
        }

        //In order to allow "literal" inline tags, the otherwise invalid
        //sequence "{@}" is changed to "@", and "{}" is changed to "}".
        //"%" is escaped to "%%" because of vsprintf.
        //See unit tests for examples.
        for ($i = 0; $i < $count; $i += 2) {
            $tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]);
        }

        return new Description(implode('', $tokens), $tags);
    }

    /**
     * Strips the contents from superfluous whitespace and splits the description into a series of tokens.
     *
     * @return string[] A series of tokens of which the description text is composed.
     */
    private function lex(string $contents): array
    {
        $contents = $this->removeSuperfluousStartingWhitespace($contents);

        // performance optimalization; if there is no inline tag, don't bother splitting it up.
        if (strpos($contents, '{@') === false) {
            return [$contents];
        }

        return Utils::pregSplit(
            '/\{
                # "{@}" is not a valid inline tag. This ensures that we do not treat it as one, but treat it literally.
                (?!@\})
                # We want to capture the whole tag line, but without the inline tag delimiters.
                (\@
                    # Match everything up to the next delimiter.
                    [^{}]*
                    # Nested inline tag content should not be captured, or it will appear in the result separately.
                    (?:
                        # Match nested inline tags.
                        (?:
                            # Because we did not catch the tag delimiters earlier, we must be explicit with them here.
                            # Notice that this also matches "{}", as a way to later introduce it as an escape sequence.
                            \{(?1)?\}
                            |
                            # Make sure we match hanging "{".
                            \{
                        )
                        # Match content after the nested inline tag.
                        [^{}]*
                    )* # If there are more inline tags, match them as well. We use "*" since there may not be any
                       # nested inline tags.
                )
            \}/Sux',
            $contents,
            0,
            PREG_SPLIT_DELIM_CAPTURE
        );
    }

    /**
     * Removes the superfluous from a multi-line description.
     *
     * When a description has more than one line then it can happen that the second and subsequent lines have an
     * additional indentation. This is commonly in use with tags like this:
     *
     *     {@}since 1.1.0 This is an example
     *         description where we have an
     *         indentation in the second and
     *         subsequent lines.
     *
     * If we do not normalize the indentation then we have superfluous whitespace on the second and subsequent
     * lines and this may cause rendering issues when, for example, using a Markdown converter.
     */
    private function removeSuperfluousStartingWhitespace(string $contents): string
    {
        $lines = Utils::pregSplit("/\r\n?|\n/", $contents);

        // if there is only one line then we don't have lines with superfluous whitespace and
        // can use the contents as-is
        if (count($lines) <= 1) {
            return $contents;
        }

        // determine how many whitespace characters need to be stripped
        $startingSpaceCount = 9999999;
        for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {
            // lines with a no length do not count as they are not indented at all
            if (trim($lines[$i]) === '') {
                continue;
            }

            // determine the number of prefixing spaces by checking the difference in line length before and after
            // an ltrim
            $startingSpaceCount = min($startingSpaceCount, strlen($lines[$i]) - strlen(ltrim($lines[$i])));
        }

        // strip the number of spaces from each line
        if ($startingSpaceCount > 0) {
            for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {
                $lines[$i] = substr($lines[$i], $startingSpaceCount);
            }
        }

        return implode("\n", $lines);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Example;

use function array_slice;
use function file;
use function getcwd;
use function implode;
use function is_readable;
use function rtrim;
use function sprintf;
use function trim;

use const DIRECTORY_SEPARATOR;

/**
 * Class used to find an example file's location based on a given ExampleDescriptor.
 */
class ExampleFinder
{
    private string $sourceDirectory = '';

    /** @var string[] */
    private array $exampleDirectories = [];

    /**
     * Attempts to find the example contents for the given descriptor.
     */
    public function find(Example $example): string
    {
        $filename = $example->getFilePath();

        $file = $this->getExampleFileContents($filename);
        if ($file === null) {
            return sprintf('** File not found : %s **', $filename);
        }

        return implode('', array_slice($file, $example->getStartingLine() - 1, $example->getLineCount()));
    }

    /**
     * Registers the project's root directory where an 'examples' folder can be expected.
     */
    public function setSourceDirectory(string $directory = ''): void
    {
        $this->sourceDirectory = $directory;
    }

    /**
     * Returns the project's root directory where an 'examples' folder can be expected.
     */
    public function getSourceDirectory(): string
    {
        return $this->sourceDirectory;
    }

    /**
     * Registers a series of directories that may contain examples.
     *
     * @param string[] $directories
     */
    public function setExampleDirectories(array $directories): void
    {
        $this->exampleDirectories = $directories;
    }

    /**
     * Returns a series of directories that may contain examples.
     *
     * @return string[]
     */
    public function getExampleDirectories(): array
    {
        return $this->exampleDirectories;
    }

    /**
     * Attempts to find the requested example file and returns its contents or null if no file was found.
     *
     * This method will try several methods in search of the given example file, the first one it encounters is
     * returned:
     *
     * 1. Iterates through all examples folders for the given filename
     * 2. Checks the source folder for the given filename
     * 3. Checks the 'examples' folder in the current working directory for examples
     * 4. Checks the path relative to the current working directory for the given filename
     *
     * @return string[] all lines of the example file
     */
    private function getExampleFileContents(string $filename): ?array
    {
        $normalizedPath = null;

        foreach ($this->exampleDirectories as $directory) {
            $exampleFileFromConfig = $this->constructExamplePath($directory, $filename);
            if (is_readable($exampleFileFromConfig)) {
                $normalizedPath = $exampleFileFromConfig;
                break;
            }
        }

        if ($normalizedPath === null) {
            if (is_readable($this->getExamplePathFromSource($filename))) {
                $normalizedPath = $this->getExamplePathFromSource($filename);
            } elseif (is_readable($this->getExamplePathFromExampleDirectory($filename))) {
                $normalizedPath = $this->getExamplePathFromExampleDirectory($filename);
            } elseif (is_readable($filename)) {
                $normalizedPath = $filename;
            }
        }

        $lines = $normalizedPath !== null && is_readable($normalizedPath) ? file($normalizedPath) : false;

        return $lines !== false ? $lines : null;
    }

    /**
     * Get example filepath based on the example directory inside your project.
     */
    private function getExamplePathFromExampleDirectory(string $file): string
    {
        return getcwd() . DIRECTORY_SEPARATOR . 'examples' . DIRECTORY_SEPARATOR . $file;
    }

    /**
     * Returns a path to the example file in the given directory..
     */
    private function constructExamplePath(string $directory, string $file): string
    {
        return rtrim($directory, '\\/') . DIRECTORY_SEPARATOR . $file;
    }

    /**
     * Get example filepath based on sourcecode.
     */
    private function getExamplePathFromSource(string $file): string
    {
        return sprintf(
            '%s%s%s',
            trim($this->getSourceDirectory(), '\\/'),
            DIRECTORY_SEPARATOR,
            trim($file, '"')
        );
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;

use function sprintf;
use function str_repeat;
use function str_replace;
use function strlen;
use function wordwrap;

/**
 * Converts a DocBlock back from an object to a complete DocComment including Asterisks.
 */
class Serializer
{
    /** @var string The string to indent the comment with. */
    protected string $indentString = ' ';

    /** @var int The number of times the indent string is repeated. */
    protected int $indent = 0;

    /** @var bool Whether to indent the first line with the given indent amount and string. */
    protected bool $isFirstLineIndented = true;

    /** @var int|null The max length of a line. */
    protected ?int $lineLength = null;

    /** @var Formatter A custom tag formatter. */
    protected Formatter $tagFormatter;
    private string $lineEnding;

    /**
     * Create a Serializer instance.
     *
     * @param int       $indent          The number of times the indent string is repeated.
     * @param string    $indentString    The string to indent the comment with.
     * @param bool      $indentFirstLine Whether to indent the first line.
     * @param int|null  $lineLength      The max length of a line or NULL to disable line wrapping.
     * @param Formatter $tagFormatter    A custom tag formatter, defaults to PassthroughFormatter.
     * @param string    $lineEnding      Line ending used in the output, by default \n is used.
     */
    public function __construct(
        int $indent = 0,
        string $indentString = ' ',
        bool $indentFirstLine = true,
        ?int $lineLength = null,
        ?Formatter $tagFormatter = null,
        string $lineEnding = "\n"
    ) {
        $this->indent              = $indent;
        $this->indentString        = $indentString;
        $this->isFirstLineIndented = $indentFirstLine;
        $this->lineLength          = $lineLength;
        $this->tagFormatter        = $tagFormatter ?: new PassthroughFormatter();
        $this->lineEnding = $lineEnding;
    }

    /**
     * Generate a DocBlock comment.
     *
     * @param DocBlock $docblock The DocBlock to serialize.
     *
     * @return string The serialized doc block.
     */
    public function getDocComment(DocBlock $docblock): string
    {
        $indent      = str_repeat($this->indentString, $this->indent);
        $firstIndent = $this->isFirstLineIndented ? $indent : '';
        // 3 === strlen(' * ')
        $wrapLength = $this->lineLength !== null ? $this->lineLength - strlen($indent) - 3 : null;

        $text = $this->removeTrailingSpaces(
            $indent,
            $this->addAsterisksForEachLine(
                $indent,
                $this->getSummaryAndDescriptionTextBlock($docblock, $wrapLength)
            )
        );

        $comment = $firstIndent . "/**\n";
        if ($text) {
            $comment .= $indent . ' * ' . $text . "\n";
            $comment .= $indent . " *\n";
        }

        $comment = $this->addTagBlock($docblock, $wrapLength, $indent, $comment);

        return str_replace("\n", $this->lineEnding, $comment . $indent . ' */');
    }

    private function removeTrailingSpaces(string $indent, string $text): string
    {
        return str_replace(
            sprintf("\n%s * \n", $indent),
            sprintf("\n%s *\n", $indent),
            $text
        );
    }

    private function addAsterisksForEachLine(string $indent, string $text): string
    {
        return str_replace(
            "\n",
            sprintf("\n%s * ", $indent),
            $text
        );
    }

    private function getSummaryAndDescriptionTextBlock(DocBlock $docblock, ?int $wrapLength): string
    {
        $text = $docblock->getSummary() . ((string) $docblock->getDescription() ? "\n\n" . $docblock->getDescription()
                : '');
        if ($wrapLength !== null) {
            $text = wordwrap($text, $wrapLength);

            return $text;
        }

        return $text;
    }

    private function addTagBlock(DocBlock $docblock, ?int $wrapLength, string $indent, string $comment): string
    {
        foreach ($docblock->getTags() as $tag) {
            $tagText = $this->tagFormatter->format($tag);
            if ($wrapLength !== null) {
                $tagText = wordwrap($tagText, $wrapLength);
            }

            $tagText = str_replace(
                "\n",
                sprintf("\n%s * ", $indent),
                $tagText
            );

            $comment .= sprintf("%s * %s\n", $indent, $tagText);
        }

        return $comment;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tags\Author;
use phpDocumentor\Reflection\DocBlock\Tags\Covers;
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlock\Tags\Mixin;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\DocBlock\Tags\Property;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\DocBlock\Tags\See as SeeTag;
use phpDocumentor\Reflection\DocBlock\Tags\Since;
use phpDocumentor\Reflection\DocBlock\Tags\Source;
use phpDocumentor\Reflection\DocBlock\Tags\TemplateCovariant;
use phpDocumentor\Reflection\DocBlock\Tags\Throws;
use phpDocumentor\Reflection\DocBlock\Tags\Uses;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\DocBlock\Tags\Version;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function array_merge;
use function array_slice;
use function call_user_func_array;
use function get_class;
use function is_object;
use function preg_match;
use function sprintf;
use function strpos;
use function trim;

/**
 * Creates a Tag object given the contents of a tag.
 *
 * This Factory is capable of determining the appropriate class for a tag and instantiate it using its `create`
 * factory method. The `create` factory method of a Tag can have a variable number of arguments; this way you can
 * pass the dependencies that you need to construct a tag object.
 *
 * > Important: each parameter in addition to the body variable for the `create` method must default to null, otherwise
 * > it violates the constraint with the interface; it is recommended to use the {@see Assert::notNull()} method to
 * > verify that a dependency is actually passed.
 *
 * This Factory also features a Service Locator component that is used to pass the right dependencies to the
 * `create` method of a tag; each dependency should be registered as a service or as a parameter.
 *
 * When you want to use a Tag of your own with custom handling you need to call the `registerTagHandler` method, pass
 * the name of the tag and a Fully Qualified Class Name pointing to a class that implements the Tag interface.
 */
final class StandardTagFactory implements TagFactory
{
    /** PCRE regular expression matching a tag name. */
    public const REGEX_TAGNAME = '[\w\-\_\\\\:]+';

    /**
     * @var array<class-string<Tag>|Factory> An array with a tag as a key, and an
     *                               FQCN to a class that handles it as an array value.
     */
    private array $tagHandlerMappings = [
        'author'             => Author::class,
        'covers'             => Covers::class,
        'deprecated'         => Deprecated::class,
        // 'example'         => '\phpDocumentor\Reflection\DocBlock\Tags\Example',
        'link'               => LinkTag::class,
        'mixin'              => Mixin::class,
        'method'             => Method::class,
        'param'              => Param::class,
        'property-read'      => PropertyRead::class,
        'property'           => Property::class,
        'property-write'     => PropertyWrite::class,
        'return'             => Return_::class,
        'see'                => SeeTag::class,
        'since'              => Since::class,
        'source'             => Source::class,
        'template-covariant' => TemplateCovariant::class,
        'throw'              => Throws::class,
        'throws'             => Throws::class,
        'uses'               => Uses::class,
        'var'                => Var_::class,
        'version'            => Version::class,
    ];

    /**
     * @var array<class-string<Tag>> An array with an annotation as a key, and an
     *      FQCN to a class that handles it as an array value.
     */
    private array $annotationMappings = [];

    /**
     * @var ReflectionParameter[][] a lazy-loading cache containing parameters
     *      for each tagHandler that has been used.
     */
    private array $tagHandlerParameterCache = [];

    private FqsenResolver $fqsenResolver;

    /**
     * @var mixed[] an array representing a simple Service Locator where we can store parameters and
     *     services that can be inserted into the Factory Methods of Tag Handlers.
     */
    private array $serviceLocator = [];

    /**
     * Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers.
     *
     * If no tag handlers are provided than the default list in the {@see self::$tagHandlerMappings} property
     * is used.
     *
     * @see self::registerTagHandler() to add a new tag handler to the existing default list.
     *
     * @param array<class-string<Tag>> $tagHandlers
     */
    public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null)
    {
        $this->fqsenResolver = $fqsenResolver;
        if ($tagHandlers !== null) {
            $this->tagHandlerMappings = $tagHandlers;
        }

        $this->addService($fqsenResolver, FqsenResolver::class);
    }

    public function create(string $tagLine, ?TypeContext $context = null): Tag
    {
        if (!$context) {
            $context = new TypeContext('');
        }

        [$tagName, $tagBody] = $this->extractTagParts($tagLine);

        return $this->createTag(trim($tagBody), $tagName, $context);
    }

    /**
     * @param mixed $value
     */
    public function addParameter(string $name, $value): void
    {
        $this->serviceLocator[$name] = $value;
    }

    public function addService(object $service, ?string $alias = null): void
    {
        $this->serviceLocator[$alias ?? get_class($service)] = $service;
    }

    /** {@inheritDoc} */
    public function registerTagHandler(string $tagName, $handler): void
    {
        Assert::stringNotEmpty($tagName);
        if (strpos($tagName, '\\') !== false && $tagName[0] !== '\\') {
            throw new InvalidArgumentException(
                'A namespaced tag must have a leading backslash as it must be fully qualified'
            );
        }

        if (is_object($handler)) {
            Assert::isInstanceOf($handler, Factory::class);
            $this->tagHandlerMappings[$tagName] = $handler;

            return;
        }

        Assert::classExists($handler);
        Assert::implementsInterface($handler, Tag::class);
        $this->tagHandlerMappings[$tagName] = $handler;
    }

    /**
     * Extracts all components for a tag.
     *
     * @return string[]
     */
    private function extractTagParts(string $tagLine): array
    {
        $matches = [];
        if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')((?:[\s\(\{])\s*([^\s].*)|$)/us', $tagLine, $matches)) {
            throw new InvalidArgumentException(
                'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
            );
        }

        return array_slice($matches, 1);
    }

    /**
     * Creates a new tag object with the given name and body or returns null if the tag name was recognized but the
     * body was invalid.
     */
    private function createTag(string $body, string $name, TypeContext $context): Tag
    {
        $handlerClassName = $this->findHandlerClassName($name, $context);
        $arguments        = $this->getArgumentsForParametersFromWiring(
            $this->fetchParametersForHandlerFactoryMethod($handlerClassName),
            $this->getServiceLocatorWithDynamicParameters($context, $name, $body)
        );

        if (array_key_exists('tagLine', $arguments)) {
            $arguments['tagLine'] = sprintf('@%s %s', $name, $body);
        }

        try {
            $callable = [$handlerClassName, 'create'];
            Assert::isCallable($callable);
            /** @phpstan-var callable(string): ?Tag $callable */
            $tag = call_user_func_array($callable, $arguments);

            return $tag ?? InvalidTag::create($body, $name);
        } catch (InvalidArgumentException $e) {
            return InvalidTag::create($body, $name)->withError($e);
        }
    }

    /**
     * Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`).
     *
     * @return class-string<Tag>|Factory
     */
    private function findHandlerClassName(string $tagName, TypeContext $context)
    {
        $handlerClassName = Generic::class;
        if (isset($this->tagHandlerMappings[$tagName])) {
            $handlerClassName = $this->tagHandlerMappings[$tagName];
        } elseif ($this->isAnnotation($tagName)) {
            // TODO: Annotation support is planned for a later stage and as such is disabled for now
            $tagName = (string) $this->fqsenResolver->resolve($tagName, $context);
            if (isset($this->annotationMappings[$tagName])) {
                $handlerClassName = $this->annotationMappings[$tagName];
            }
        }

        return $handlerClassName;
    }

    /**
     * Retrieves the arguments that need to be passed to the Factory Method with the given Parameters.
     *
     * @param ReflectionParameter[] $parameters
     * @param mixed[]               $locator
     *
     * @return mixed[] A series of values that can be passed to the Factory Method of the tag whose parameters
     *     is provided with this method.
     */
    private function getArgumentsForParametersFromWiring(array $parameters, array $locator): array
    {
        $arguments = [];
        foreach ($parameters as $parameter) {
            $type     = $parameter->getType();
            $typeHint = null;
            if ($type instanceof ReflectionNamedType) {
                $typeHint = $type->getName();
                if ($typeHint === 'self') {
                    $declaringClass = $parameter->getDeclaringClass();
                    if ($declaringClass !== null) {
                        $typeHint = $declaringClass->getName();
                    }
                }
            }

            $parameterName = $parameter->getName();
            if (isset($locator[$typeHint])) {
                $arguments[$parameterName] = $locator[$typeHint];
                continue;
            }

            if (isset($locator[$parameterName])) {
                $arguments[$parameterName] = $locator[$parameterName];
                continue;
            }

            $arguments[$parameterName] = null;
        }

        return $arguments;
    }

    /**
     * Retrieves a series of ReflectionParameter objects for the static 'create' method of the given
     * tag handler class name.
     *
     * @param class-string|Factory $handler
     *
     * @return ReflectionParameter[]
     */
    private function fetchParametersForHandlerFactoryMethod($handler): array
    {
        $handlerClassName = is_object($handler) ? get_class($handler) : $handler;

        if (!isset($this->tagHandlerParameterCache[$handlerClassName])) {
            $methodReflection                                  = new ReflectionMethod($handlerClassName, 'create');
            $this->tagHandlerParameterCache[$handlerClassName] = $methodReflection->getParameters();
        }

        return $this->tagHandlerParameterCache[$handlerClassName];
    }

    /**
     * Returns a copy of this class' Service Locator with added dynamic parameters,
     * such as the tag's name, body and Context.
     *
     * @param TypeContext $context The Context (namespace and aliases) that may be
     *  passed and is used to resolve FQSENs.
     * @param string      $tagName The name of the tag that may be
     *  passed onto the factory method of the Tag class.
     * @param string      $tagBody The body of the tag that may be
     *  passed onto the factory method of the Tag class.
     *
     * @return mixed[]
     */
    private function getServiceLocatorWithDynamicParameters(
        TypeContext $context,
        string $tagName,
        string $tagBody
    ): array {
        return array_merge(
            $this->serviceLocator,
            [
                'name' => $tagName,
                'body' => $tagBody,
                TypeContext::class => $context,
            ]
        );
    }

    /**
     * Returns whether the given tag belongs to an annotation.
     *
     * @todo this method should be populated once we implement Annotation notation support.
     */
    private function isAnnotation(string $tagContent): bool
    {
        // 1. Contains a namespace separator
        // 2. Contains parenthesis
        // 3. Is present in a list of known annotations (make the algorithm smart by first checking is the last part
        //    of the annotation class name matches the found tag name

        return false;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

interface Tag
{
    public function getName(): string;

    /**
     * @return Tag|mixed Class that implements Tag
     * @phpstan-return ?Tag
     */
    public static function create(string $body);

    public function render(?Formatter $formatter = null): string;

    public function __toString(): string;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;

interface TagFactory extends Factory
{
    /**
     * Adds a parameter to the service locator that can be injected in a tag's factory method.
     *
     * When calling a tag's "create" method we always check the signature for dependencies to inject. One way is to
     * typehint a parameter in the signature so that we can use that interface or class name to inject a dependency
     * (see {@see addService()} for more information on that).
     *
     * Another way is to check the name of the argument against the names in the Service Locator. With this method
     * you can add a variable that will be inserted when a tag's create method is not typehinted and has a matching
     * name.
     *
     * Be aware that there are two reserved names:
     *
     * - name, representing the name of the tag.
     * - body, representing the complete body of the tag.
     *
     * These parameters are injected at the last moment and will override any existing parameter with those names.
     *
     * @param mixed $value
     */
    public function addParameter(string $name, $value): void;

    /**
     * Registers a service with the Service Locator using the FQCN of the class or the alias, if provided.
     *
     * When calling a tag's "create" method we always check the signature for dependencies to inject. If a parameter
     * has a typehint then the ServiceLocator is queried to see if a Service is registered for that typehint.
     *
     * Because interfaces are regularly used as type-hints this method provides an alias parameter; if the FQCN of the
     * interface is passed as alias then every time that interface is requested the provided service will be returned.
     */
    public function addService(object $service): void;

    /**
     * Registers a handler for tags.
     *
     * If you want to use your own tags then you can use this method to instruct the TagFactory
     * to register the name of a tag with the FQCN of a 'Tag Handler'. The Tag handler should implement
     * the {@see Tag} interface (and thus the create method).
     *
     * @param string                    $tagName Name of tag to register a handler for. When registering a namespaced
     *                                   tag, the full name, along with a prefixing slash MUST be provided.
     * @param class-string<Tag>|Factory $handler FQCN of handler.
     *
     * @throws InvalidArgumentException If the tag name is not a string.
     * @throws InvalidArgumentException If the tag name is namespaced (contains backslashes) but
     *                                   does not start with a backslash.
     * @throws InvalidArgumentException If the handler is not a string.
     * @throws InvalidArgumentException If the handler is not an existing class.
     * @throws InvalidArgumentException If the handler does not implement the {@see Tag} interface.
     */
    public function registerTagHandler(string $tagName, $handler): void;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;

use function filter_var;
use function preg_match;
use function trim;

use const FILTER_VALIDATE_EMAIL;

/**
 * Reflection class for an {@}author tag in a Docblock.
 */
final class Author extends BaseTag implements Factory\StaticMethod
{
    /** @var string register that this is the author tag. */
    protected string $name = 'author';

    /** @var string The name of the author */
    private string $authorName;

    /** @var string The email of the author */
    private string $authorEmail;

    /**
     * Initializes this tag with the author name and e-mail.
     */
    public function __construct(string $authorName, string $authorEmail)
    {
        if ($authorEmail && !filter_var($authorEmail, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('The author tag does not have a valid e-mail address');
        }

        $this->authorName  = $authorName;
        $this->authorEmail = $authorEmail;
    }

    /**
     * Gets the author's name.
     *
     * @return string The author's name.
     */
    public function getAuthorName(): string
    {
        return $this->authorName;
    }

    /**
     * Returns the author's email.
     *
     * @return string The author's email.
     */
    public function getEmail(): string
    {
        return $this->authorEmail;
    }

    /**
     * Returns this tag in string form.
     */
    public function __toString(): string
    {
        if ($this->authorEmail) {
            $authorEmail = '<' . $this->authorEmail . '>';
        } else {
            $authorEmail = '';
        }

        $authorName = $this->authorName;

        return $authorName . ($authorEmail !== '' ? ($authorName !== '' ? ' ' : '') . $authorEmail : '');
    }

    /**
     * Attempts to create a new Author object based on the tag body.
     */
    public static function create(string $body): ?self
    {
        $splitTagContent = preg_match('/^([^\<]*)(?:\<([^\>]*)\>)?$/u', $body, $matches);
        if (!$splitTagContent) {
            return null;
        }

        $authorName = trim($matches[1]);
        $email      = isset($matches[2]) ? trim($matches[2]) : '';

        return new static($authorName, $email);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Description;

/**
 * Parses a tag definition for a DocBlock.
 */
abstract class BaseTag implements DocBlock\Tag
{
    /** @var string Name of the tag */
    protected string $name = '';

    /** @var Description|null Description of the tag. */
    protected ?Description $description = null;

    /**
     * Gets the name of this tag.
     *
     * @return string The name of this tag.
     */
    public function getName(): string
    {
        return $this->name;
    }

    public function getDescription(): ?Description
    {
        return $this->description;
    }

    public function render(?Formatter $formatter = null): string
    {
        if ($formatter === null) {
            $formatter = new Formatter\PassthroughFormatter();
        }

        return $formatter->format($this);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;

/**
 * Reflection class for a @covers tag in a Docblock.
 */
final class Covers extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'covers';

    private Fqsen $refers;

    /**
     * Initializes this tag.
     */
    public function __construct(Fqsen $refers, ?Description $description = null)
    {
        $this->refers      = $refers;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?FqsenResolver $resolver = null,
        ?TypeContext $context = null
    ): self {
        Assert::stringNotEmpty($body);
        Assert::notNull($descriptionFactory);
        Assert::notNull($resolver);

        $parts = Utils::pregSplit('/\s+/Su', $body, 2);

        return new static(
            self::resolveFqsen($parts[0], $resolver, $context),
            $descriptionFactory->create($parts[1] ?? '', $context)
        );
    }

    private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
    {
        Assert::notNull($fqsenResolver);
        $fqsenParts = explode('::', $parts);
        $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

        if (!array_key_exists(1, $fqsenParts)) {
            return $resolved;
        }

        return new Fqsen($resolved . '::' . $fqsenParts[1]);
    }

    /**
     * Returns the structural element this tag refers to.
     */
    public function getReference(): Fqsen
    {
        return $this->refers;
    }

    /**
     * Returns a string representation of this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $refers = (string) $this->refers;

        return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;

/**
 * Reflection class for a {@}deprecated tag in a Docblock.
 */
final class Deprecated extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'deprecated';

    /**
     * PCRE regular expression matching a version vector.
     * Assumes the "x" modifier.
     */
    public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';

    /** @var string|null The version vector. */
    private ?string $version = null;

    public function __construct(?string $version = null, ?Description $description = null)
    {
        Assert::nullOrNotEmpty($version);

        $this->version     = $version;
        $this->description = $description;
    }

    /**
     * @return static
     */
    public static function create(
        ?string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        if ($body === null || $body === '') {
            return new static();
        }

        $matches = [];
        if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
            return new static(
                null,
                $descriptionFactory !== null ? $descriptionFactory->create($body, $context) : null
            );
        }

        Assert::notNull($descriptionFactory);

        return new static(
            $matches[1],
            $descriptionFactory->create($matches[2] ?? '', $context)
        );
    }

    /**
     * Gets the version section of the tag.
     */
    public function getVersion(): ?string
    {
        return $this->version;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $version = (string) $this->version;

        return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Tag;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function preg_match;
use function rawurlencode;
use function str_replace;
use function strpos;
use function trim;

/**
 * Reflection class for a {@}example tag in a Docblock.
 */
final class Example implements Tag, Factory\StaticMethod
{
    /** @var string Path to a file to use as an example. May also be an absolute URI. */
    private string $filePath;

    /**
     * @var bool Whether the file path component represents an URI. This determines how the file portion
     *     appears at {@link getContent()}.
     */
    private bool $isURI;

    private int $startingLine;

    private int $lineCount;

    private ?string $content = null;

    public function __construct(
        string $filePath,
        bool $isURI,
        int $startingLine,
        int $lineCount,
        ?string $content
    ) {
        Assert::stringNotEmpty($filePath);
        Assert::greaterThanEq($startingLine, 1);
        Assert::greaterThanEq($lineCount, 0);

        $this->filePath     = $filePath;
        $this->startingLine = $startingLine;
        $this->lineCount    = $lineCount;
        if ($content !== null) {
            $this->content = trim($content);
        }

        $this->isURI = $isURI;
    }

    public function getContent(): string
    {
        if ($this->content === null || $this->content === '') {
            $filePath = $this->filePath;
            if ($this->isURI) {
                $filePath = $this->isUriRelative($this->filePath)
                    ? str_replace('%2F', '/', rawurlencode($this->filePath))
                    : $this->filePath;
            }

            return trim($filePath);
        }

        return $this->content;
    }

    public function getDescription(): ?string
    {
        return $this->content;
    }

    public static function create(string $body): ?Tag
    {
        // File component: File path in quotes or File URI / Source information
        if (!preg_match('/^\s*(?:(\"[^\"]+\")|(\S+))(?:\s+(.*))?$/sux', $body, $matches)) {
            return null;
        }

        $filePath = null;
        $fileUri  = null;
        if (array_key_exists(1, $matches) && $matches[1] !== '') {
            $filePath = $matches[1];
        } else {
            $fileUri = array_key_exists(2, $matches) ? $matches[2] : '';
        }

        $startingLine = 1;
        $lineCount    = 0;
        $description  = null;

        if (array_key_exists(3, $matches)) {
            $description = $matches[3];

            // Starting line / Number of lines / Description
            if (preg_match('/^([1-9]\d*)(?:\s+((?1))\s*)?(.*)$/sux', $matches[3], $contentMatches)) {
                $startingLine = (int) $contentMatches[1];
                if (isset($contentMatches[2])) {
                    $lineCount = (int) $contentMatches[2];
                }

                if (array_key_exists(3, $contentMatches)) {
                    $description = $contentMatches[3];
                }
            }
        }

        return new static(
            $filePath ?? ($fileUri ?? ''),
            $fileUri !== null,
            $startingLine,
            $lineCount,
            $description
        );
    }

    /**
     * Returns the file path.
     *
     * @return string Path to a file to use as an example.
     *     May also be an absolute URI.
     */
    public function getFilePath(): string
    {
        return trim($this->filePath, '"');
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        $filePath = $this->filePath;
        $isDefaultLine = $this->startingLine === 1 && $this->lineCount === 0;
        $startingLine = !$isDefaultLine ? (string) $this->startingLine : '';
        $lineCount = !$isDefaultLine ? (string) $this->lineCount : '';
        $content = (string) $this->content;

        return $filePath
            . ($startingLine !== ''
                ? ($filePath !== '' ? ' ' : '') . $startingLine
                : '')
            . ($lineCount !== ''
                ? ($filePath !== '' || $startingLine !== '' ? ' ' : '') . $lineCount
                : '')
            . ($content !== ''
                ? ($filePath !== '' || $startingLine !== '' || $lineCount !== '' ? ' ' : '') . $content
                : '');
    }

    /**
     * Returns true if the provided URI is relative or contains a complete scheme (and thus is absolute).
     */
    private function isUriRelative(string $uri): bool
    {
        return strpos($uri, ':') === false;
    }

    public function getStartingLine(): int
    {
        return $this->startingLine;
    }

    public function getLineCount(): int
    {
        return $this->lineCount;
    }

    public function getName(): string
    {
        return 'example';
    }

    public function render(?Formatter $formatter = null): string
    {
        if ($formatter === null) {
            $formatter = new Formatter\PassthroughFormatter();
        }

        return $formatter->format($this);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Type;

/**
 * Reflection class for a {@}extends tag in a Docblock.
 */
class Extends_ extends TagWithType
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'extends';
        $this->type        = $type;
        $this->description = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(string $body): ?Tag
    {
        Deprecation::trigger(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        return null;
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\PhpDocParser\ParserConfig;
use RuntimeException;

use function class_exists;
use function ltrim;
use function property_exists;
use function rtrim;

/**
 * Factory class creating tags using phpstan's parser
 *
 * This class uses {@see PHPStanFactory} implementations to create tags
 * from the ast of the phpstan docblock parser.
 *
 * @internal This class is not part of the BC promise of this library.
 */
class AbstractPHPStanFactory implements Factory
{
    private PhpDocParser $parser;
    private Lexer $lexer;
    /** @var PHPStanFactory[] */
    private array $factories;

    public function __construct(PHPStanFactory ...$factories)
    {
        if (class_exists(ParserConfig::class)) {
            $config = new ParserConfig(['indexes' => true, 'lines' => true]);
            $this->lexer = new Lexer($config);
            $constParser = new ConstExprParser($config);
            $this->parser = new PhpDocParser(
                $config,
                new TypeParser($config, $constParser),
                $constParser
            );
        } else {
            $this->lexer = new Lexer(true);
            $constParser = new ConstExprParser(true, true, ['lines' => true, 'indexes' => true]);
            $this->parser = new PhpDocParser(
                new TypeParser($constParser, true, ['lines' => true, 'indexes' => true]),
                $constParser,
                true,
                true,
                ['lines' => true, 'indexes' => true],
                true
            );
        }

        $this->factories = $factories;
    }

    public function create(string $tagLine, ?TypeContext $context = null): Tag
    {
        $tokens = $this->tokenizeLine($tagLine . "\n");
        $ast = $this->parser->parseTag($tokens);
        if (property_exists($ast->value, 'description') === true) {
            $ast->value->setAttribute(
                'description',
                rtrim($ast->value->description . $tokens->joinUntil(Lexer::TOKEN_END), "\n")
            );
        }

        if ($context === null) {
            $context = new TypeContext('');
        }

        try {
            foreach ($this->factories as $factory) {
                if ($factory->supports($ast, $context)) {
                    return $factory->create($ast, $context);
                }
            }
        } catch (RuntimeException $e) {
            return InvalidTag::create((string) $ast->value, 'method')->withError($e);
        }

        return InvalidTag::create(
            (string) $ast->value,
            $ast->name
        );
    }

    /**
     * Solve the issue with the lexer not tokenizing the line correctly
     *
     * This method is a workaround for the lexer that includes newline tokens with spaces. For
     * phpstan this isn't an issue, as it doesn't do a lot of things with the indentation of descriptions.
     * But for us is important to keep the indentation of the descriptions, so we need to fix the lexer output.
     */
    private function tokenizeLine(string $tagLine): TokenIterator
    {
        $tokens = $this->lexer->tokenize($tagLine);
        $fixed = [];
        foreach ($tokens as $token) {
            if (($token[1] === Lexer::TOKEN_PHPDOC_EOL) && rtrim($token[0], " \t") !== $token[0]) {
                $fixed[] = [
                    rtrim($token[Lexer::VALUE_OFFSET], " \t"),
                    Lexer::TOKEN_PHPDOC_EOL,
                    $token[2] ?? 0,
                ];
                $fixed[] = [
                    ltrim($token[Lexer::VALUE_OFFSET], "\n\r"),
                    Lexer::TOKEN_HORIZONTAL_WS,
                    ($token[2] ?? 0) + 1,
                ];
                continue;
            }

            $fixed[] = $token;
        }

        return new TokenIterator($fixed);
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Extends_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class ExtendsFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ExtendsTagValueNode && $node->name === '@extends';
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, ExtendsTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Extends_(
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Types\Context as TypeContext;

interface Factory
{
    /**
     * Factory method responsible for instantiating the correct sub type.
     *
     * @param string $tagLine The text for this tag, including description.
     *
     * @return Tag A new tag object.
     *
     * @throws InvalidArgumentException If an invalid tag line was presented.
     */
    public function create(string $tagLine, ?TypeContext $context = null): Tag;
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Implements_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class ImplementsFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ImplementsTagValueNode && $node->name === '@implements';
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, ImplementsTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Implements_(
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlock\Tags\MethodParameter;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Void_;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;

use function array_map;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class MethodFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, MethodTagValueNode::class);

        return new Method(
            $tagValue->methodName,
            [],
            $this->createReturnType($tagValue, $context),
            $tagValue->isStatic,
            $this->descriptionFactory->create($tagValue->description, $context),
            false,
            array_map(
                function (MethodTagValueParameterNode $param) use ($context) {
                    return new MethodParameter(
                        trim($param->parameterName, '$'),
                        $param->type === null ? new Mixed_() : $this->typeResolver->createType(
                            $param->type,
                            $context
                        ),
                        $param->isReference,
                        $param->isVariadic,
                        $param->defaultValue === null ?
                            MethodParameter::NO_DEFAULT_VALUE :
                            (string) $param->defaultValue
                    );
                },
                $tagValue->parameters
            ),
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof MethodTagValueNode;
    }

    private function createReturnType(MethodTagValueNode $tagValue, Context $context): Type
    {
        if ($tagValue->returnType === null) {
            return new Void_();
        }

        return $this->typeResolver->createType($tagValue->returnType, $context);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use function array_key_last;
use function get_class;
use function gettype;
use function method_exists;
use function ucfirst;
use function var_export;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class MethodParameterFactory
{
    /**
     * Formats the given default value to a string-able mixin
     *
     * @param mixed $defaultValue
     */
    public function format($defaultValue): string
    {
        $method = 'format' . ucfirst(gettype($defaultValue));
        if (method_exists($this, $method)) {
            return ' = ' . $this->{$method}($defaultValue);
        }

        return '';
    }

    private function formatDouble(float $defaultValue): string
    {
        return var_export($defaultValue, true);
    }

    /**
     * @param mixed $defaultValue
     */
    private function formatNull($defaultValue): string
    {
        return 'null';
    }

    private function formatInteger(int $defaultValue): string
    {
        return var_export($defaultValue, true);
    }

    private function formatString(string $defaultValue): string
    {
        return var_export($defaultValue, true);
    }

    private function formatBoolean(bool $defaultValue): string
    {
        return var_export($defaultValue, true);
    }

    /**
     * @param array<(array<mixed>|int|float|bool|string|object|null)> $defaultValue
     */
    private function formatArray(array $defaultValue): string
    {
        $formatedValue = '[';

        foreach ($defaultValue as $key => $value) {
            $method = 'format' . ucfirst(gettype($value));
            if (!method_exists($this, $method)) {
                continue;
            }

            $formatedValue .= $this->{$method}($value);

            if ($key === array_key_last($defaultValue)) {
                continue;
            }

            $formatedValue .= ',';
        }

        return $formatedValue . ']';
    }

    private function formatObject(object $defaultValue): string
    {
        return 'new ' . get_class($defaultValue) . '()';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypelessParamTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use Webmozart\Assert\Assert;

use function is_string;
use function sprintf;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class ParamFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;

        if ($tagValue instanceof InvalidTagValueNode) {
            Deprecation::trigger(
                'phpdocumentor/reflection-docblock',
                'https://github.com/phpDocumentor/ReflectionDocBlock/issues/362',
                sprintf(
                    'Param tag value "%s" is invalid, falling back to legacy parsing. Please update your docblocks.',
                    $tagValue->value
                )
            );

            return Param::create($tagValue->value, $this->typeResolver, $this->descriptionFactory, $context);
        }

        Assert::isInstanceOfAny(
            $tagValue,
            [
                ParamTagValueNode::class,
                TypelessParamTagValueNode::class,
            ]
        );

        if (($tagValue->type ?? null) instanceof OffsetAccessTypeNode) {
            return InvalidTag::create(
                (string) $tagValue,
                'param'
            );
        }

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Param(
            trim($tagValue->parameterName, '$'),
            $this->typeResolver->createType($tagValue->type ?? new IdentifierTypeNode('mixed'), $context),
            $tagValue->isVariadic,
            $this->descriptionFactory->create($description, $context),
            $tagValue->isReference
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ParamTagValueNode
            || $node->value instanceof TypelessParamTagValueNode
            || $node->name === '@param';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;

interface PHPStanFactory
{
    public function create(PhpDocTagNode $node, Context $context): Tag;

    public function supports(PhpDocTagNode $node, Context $context): bool;
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Property;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class PropertyFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Property(
            trim($tagValue->propertyName, '$'),
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof PropertyTagValueNode && $node->name === '@property';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class PropertyReadFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->typeResolver = $typeResolver;
        $this->descriptionFactory = $descriptionFactory;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new PropertyRead(
            trim($tagValue->propertyName, '$'),
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof PropertyTagValueNode && $node->name === '@property-read';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class PropertyWriteFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new PropertyWrite(
            trim($tagValue->propertyName, '$'),
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof PropertyTagValueNode && $node->name === '@property-write';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class ReturnFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, ReturnTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Return_(
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ReturnTagValueNode;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

/**
 * @deprecated This contract is totally covered by Tag contract. Every class using StaticMethod also use Tag
 */
interface StaticMethod
{
    /**
     * @return mixed
     */
    public static function create(string $body);
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\TemplateExtends;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class TemplateExtendsFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ExtendsTagValueNode && $node->name === '@template-extends';
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, ExtendsTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new TemplateExtends(
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Template;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class TemplateFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;

        Assert::isInstanceOf($tagValue, TemplateTagValueNode::class);
        $name = $tagValue->name;

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Template(
            $name,
            $this->typeResolver->createType($tagValue->bound, $context),
            $this->typeResolver->createType($tagValue->default, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof TemplateTagValueNode && $node->name === '@template';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\TemplateImplements;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;

use function is_string;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class TemplateImplementsFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof ImplementsTagValueNode && $node->name === '@template-implements';
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, ImplementsTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new TemplateImplements(
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use Webmozart\Assert\Assert;

use function is_string;
use function trim;

/**
 * @internal This class is not part of the BC promise of this library.
 */
final class VarFactory implements PHPStanFactory
{
    private DescriptionFactory $descriptionFactory;
    private TypeResolver $typeResolver;

    public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->typeResolver = $typeResolver;
    }

    public function create(PhpDocTagNode $node, Context $context): Tag
    {
        $tagValue = $node->value;
        Assert::isInstanceOf($tagValue, VarTagValueNode::class);

        $description = $tagValue->getAttribute('description');
        if (is_string($description) === false) {
            $description = $tagValue->description;
        }

        return new Var_(
            trim($tagValue->variableName, '$'),
            $this->typeResolver->createType($tagValue->type, $context),
            $this->descriptionFactory->create($description, $context)
        );
    }

    public function supports(PhpDocTagNode $node, Context $context): bool
    {
        return $node->value instanceof VarTagValueNode;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use function max;
use function str_repeat;
use function strlen;

class AlignFormatter implements Formatter
{
    /** @var int The maximum tag name length. */
    protected int $maxLen = 0;

    /**
     * @param Tag[] $tags All tags that should later be aligned with the formatter.
     */
    public function __construct(array $tags)
    {
        foreach ($tags as $tag) {
            $this->maxLen = max($this->maxLen, strlen($tag->getName()));
        }
    }

    /**
     * Formats the given tag to return a simple plain text version.
     */
    public function format(Tag $tag): string
    {
        return '@' . $tag->getName() .
            str_repeat(
                ' ',
                $this->maxLen - strlen($tag->getName()) + 1
            ) .
            $tag;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;

use function trim;

class PassthroughFormatter implements Formatter
{
    /**
     * Formats the given tag to return a simple plain text version.
     */
    public function format(Tag $tag): string
    {
        return trim('@' . $tag->getName() . ' ' . $tag);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Tag;

interface Formatter
{
    /**
     * Formats a tag into a string representation according to a specific format, such as Markdown.
     */
    public function format(Tag $tag): string;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;

/**
 * Parses a tag definition for a DocBlock.
 */
final class Generic extends BaseTag implements Factory\StaticMethod
{
    /**
     * Parses a tag and populates the member variables.
     *
     * @param string      $name        Name of the tag.
     * @param Description $description The contents of the given tag.
     */
    public function __construct(string $name, ?Description $description = null)
    {
        $this->validateTagName($name);

        $this->name        = $name;
        $this->description = $description;
    }

    /**
     * Creates a new tag that represents any unknown tag type.
     *
     * @return static
     */
    public static function create(
        string $body,
        string $name = '',
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::stringNotEmpty($name);
        Assert::notNull($descriptionFactory);

        $description = $body !== '' ? $descriptionFactory->create($body, $context) : null;

        return new static($name, $description);
    }

    /**
     * Returns the tag as a serialized string
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        return $description;
    }

    /**
     * Validates if the tag name matches the expected format, otherwise throws an exception.
     */
    private function validateTagName(string $name): void
    {
        if (!preg_match('/^' . StandardTagFactory::REGEX_TAGNAME . '$/u', $name)) {
            throw new InvalidArgumentException(
                'The tag name "' . $name . '" is not wellformed. Tags may only consist of letters, underscores, '
                . 'hyphens and backslashes.'
            );
        }
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Type;

/**
 * Reflection class for a {@}implements tag in a Docblock.
 */
class Implements_ extends TagWithType
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'implements';
        $this->type        = $type;
        $this->description = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(string $body): ?Tag
    {
        Deprecation::trigger(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        return null;
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Closure;
use Exception;
use phpDocumentor\Reflection\DocBlock\Tag;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use Throwable;

use function array_map;
use function get_class;
use function get_resource_type;
use function is_array;
use function is_object;
use function is_resource;
use function sprintf;

/**
 * This class represents an exception during the tag creation
 *
 * Since the internals of the library are relaying on the correct syntax of a docblock
 * we cannot simply throw exceptions at all time because the exceptions will break the creation of a
 * docklock. Just silently ignore the exceptions is not an option because the user as an issue to fix.
 *
 * This tag holds that error information until a using application is able to display it. The object will just behave
 * like any normal tag. So the normal application flow will not break.
 */
final class InvalidTag implements Tag
{
    private string $name;

    private string $body;

    private ?Throwable $throwable = null;

    private function __construct(string $name, string $body)
    {
        $this->name = $name;
        $this->body = $body;
    }

    public function getException(): ?Throwable
    {
        return $this->throwable;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public static function create(string $body, string $name = ''): self
    {
        return new self($name, $body);
    }

    public function withError(Throwable $exception): self
    {
        $this->flattenExceptionBacktrace($exception);
        $tag            = new self($this->name, $this->body);
        $tag->throwable = $exception;

        return $tag;
    }

    /**
     * Removes all complex types from backtrace
     *
     * Not all objects are serializable. So we need to remove them from the
     * stored exception to be sure that we do not break existing library usage.
     */
    private function flattenExceptionBacktrace(Throwable $exception): void
    {
        $traceProperty = (new ReflectionClass(Exception::class))->getProperty('trace');
        if (PHP_VERSION_ID < 80100) {
            $traceProperty->setAccessible(true);
        }

        do {
            $trace = $exception->getTrace();
            if (isset($trace[0]['args'])) {
                $trace = array_map(
                    function (array $call): array {
                        $call['args'] = array_map([$this, 'flattenArguments'], $call['args'] ?? []);

                        return $call;
                    },
                    $trace
                );
            }

            $traceProperty->setValue($exception, $trace);
            $exception = $exception->getPrevious();
        } while ($exception !== null);

        if (PHP_VERSION_ID < 80100) {
            $traceProperty->setAccessible(false);
        }
    }

    /**
     * @param mixed $value
     *
     * @return mixed
     *
     * @throws ReflectionException
     */
    private function flattenArguments($value)
    {
        if ($value instanceof Closure) {
            $closureReflection = new ReflectionFunction($value);
            $value             = sprintf(
                '(Closure at %s:%s)',
                $closureReflection->getFileName(),
                $closureReflection->getStartLine()
            );
        } elseif (is_object($value)) {
            $value = sprintf('object(%s)', get_class($value));
        } elseif (is_resource($value)) {
            $value = sprintf('resource(%s)', get_resource_type($value));
        } elseif (is_array($value)) {
            $value = array_map([$this, 'flattenArguments'], $value);
        }

        return $value;
    }

    public function render(?Formatter $formatter = null): string
    {
        if ($formatter === null) {
            $formatter = new Formatter\PassthroughFormatter();
        }

        return $formatter->format($this);
    }

    public function __toString(): string
    {
        return $this->body;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

/**
 * Reflection class for a {@}link tag in a Docblock.
 */
final class Link extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'link';

    private string $link;

    /**
     * Initializes a link to a URL.
     */
    public function __construct(string $link, ?Description $description = null)
    {
        $this->link        = $link;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($descriptionFactory);

        $parts = Utils::pregSplit('/\s+/Su', $body, 2);
        $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;

        return new static($parts[0], $description);
    }

    /**
     * Gets the link
     */
    public function getLink(): string
    {
        return $this->link;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $link = $this->link;

        return $link . ($description !== '' ? ($link !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Void_;
use Webmozart\Assert\Assert;

use function array_keys;
use function array_map;
use function explode;
use function implode;
use function is_string;
use function preg_match;
use function sort;
use function strpos;
use function substr;
use function trigger_error;
use function trim;
use function var_export;

use const E_USER_DEPRECATED;

/**
 * Reflection class for an {@}method in a Docblock.
 */
final class Method extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'method';

    private string $methodName;

    private bool $isStatic;

    private Type $returnType;

    private bool $returnsReference;

    /** @var MethodParameter[] */
    private array $parameters;

    /**
     * @param array<int, array<string, Type|string>> $arguments
     * @param MethodParameter[] $parameters
     * @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
     */
    public function __construct(
        string $methodName,
        array $arguments = [],
        ?Type $returnType = null,
        bool $static = false,
        ?Description $description = null,
        bool $returnsReference = false,
        ?array $parameters = null
    ) {
        Assert::stringNotEmpty($methodName);

        if ($returnType === null) {
            $returnType = new Void_();
        }

        $arguments = $this->filterArguments($arguments);

        $this->methodName       = $methodName;
        $this->returnType       = $returnType;
        $this->isStatic         = $static;
        $this->description      = $description;
        $this->returnsReference = $returnsReference;
        $this->parameters = $parameters ?? $this->fromLegacyArguments($arguments);
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): ?self {
        trigger_error(
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
            E_USER_DEPRECATED
        );
        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        // 1. none or more whitespace
        // 2. optionally the keyword "static" followed by whitespace
        // 3. optionally a word with underscores followed by whitespace : as
        //    type for the return value
        // 4. optionally an ampersand followed or not by whitespace : as
        //    a reference
        // 5. then optionally a word with underscores followed by () and
        //    whitespace : as method name as used by phpDocumentor
        // 6. then a word with underscores, followed by ( and any character
        //    until a ) and whitespace : as method name with signature
        // 7. any remaining text : as description
        if (
            !preg_match(
                '/^
                # Static keyword
                # Declares a static method ONLY if type is also present
                (?:
                    (static)
                    \s+
                )?
                # Return type
                (?:
                    (
                        (?:[\w\|_\\\\]*\$this[\w\|_\\\\]*)
                        |
                        (?:
                            (?:[\w\|_\\\\]+)
                            # array notation
                            (?:\[\])*
                        )*+
                    )
                    \s+
                )?
                # Returns reference
                (?:
                    (&)
                    \s*
                )?
                # Method name
                ([\w_]+)
                # Arguments
                (?:
                    \(([^\)]*)\)
                )?
                \s*
                # Description
                (.*)
            $/sux',
                $body,
                $matches
            )
        ) {
            return null;
        }

        [, $static, $returnType, $returnsReference, $methodName, $argumentLines, $description] = $matches;

        $static = $static === 'static';

        if ($returnType === '') {
            $returnType = 'void';
        }

        $returnsReference = $returnsReference === '&';

        $returnType  = $typeResolver->resolve($returnType, $context);
        $description = $descriptionFactory->create($description, $context);

        /** @phpstan-var array<int, array{name: string, type: Type}> $arguments */
        $arguments = [];
        if ($argumentLines !== '') {
            $argumentsExploded = explode(',', $argumentLines);
            foreach ($argumentsExploded as $argument) {
                $argument = explode(' ', self::stripRestArg(trim($argument)), 2);
                if (strpos($argument[0], '$') === 0) {
                    $argumentName = substr($argument[0], 1);
                    $argumentType = new Mixed_();
                } else {
                    $argumentType = $typeResolver->resolve($argument[0], $context);
                    $argumentName = '';
                    if (isset($argument[1])) {
                        $argument[1]  = self::stripRestArg($argument[1]);
                        $argumentName = substr($argument[1], 1);
                    }
                }

                $arguments[] = ['name' => $argumentName, 'type' => $argumentType];
            }
        }

        return new static(
            $methodName,
            $arguments,
            $returnType,
            $static,
            $description,
            $returnsReference
        );
    }

    /**
     * Retrieves the method name.
     */
    public function getMethodName(): string
    {
        return $this->methodName;
    }

    /**
     * @deprecated Method deprecated, use {@see self::getParameters()}
     *
     * @return array<int, array<string, Type|string>>
     * @phpstan-return array<int, array{name: string, type: Type}>
     */
    public function getArguments(): array
    {
        trigger_error('Method deprecated, use ::getParameters()', E_USER_DEPRECATED);

        return array_map(
            static function (MethodParameter $methodParameter) {
                return ['name' => $methodParameter->getName(), 'type' => $methodParameter->getType()];
            },
            $this->parameters
        );
    }

    /** @return MethodParameter[] */
    public function getParameters(): array
    {
        return $this->parameters;
    }

    /**
     * Checks whether the method tag describes a static method or not.
     *
     * @return bool TRUE if the method declaration is for a static method, FALSE otherwise.
     */
    public function isStatic(): bool
    {
        return $this->isStatic;
    }

    public function getReturnType(): Type
    {
        return $this->returnType;
    }

    public function returnsReference(): bool
    {
        return $this->returnsReference;
    }

    public function __toString(): string
    {
        $arguments = [];
        foreach ($this->parameters as $parameter) {
            $arguments[] = (string) $parameter;
        }

        $argumentStr = '(' . implode(', ', $arguments) . ')';

        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $static = $this->isStatic ? 'static' : '';

        $returnType = (string) $this->returnType;

        $methodName = $this->methodName;

        $reference = $this->returnsReference ? '&' : '';

        return $static
            . ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
            . ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $reference . $methodName : '')
            . $argumentStr
            . ($description !== '' ? ' ' . $description : '');
    }

    /**
     * @param mixed[][]|string[] $arguments
     * @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
     *
     * @return mixed[][]
     * @phpstan-return array<int, array{name: string, type: Type}>
     */
    private function filterArguments(array $arguments = []): array
    {
        $result = [];
        foreach ($arguments as $argument) {
            if (is_string($argument)) {
                $argument = ['name' => $argument];
            }

            if (!isset($argument['type'])) {
                $argument['type'] = new Mixed_();
            }

            $keys = array_keys($argument);
            sort($keys);
            if ($keys !== ['name', 'type']) {
                throw new InvalidArgumentException(
                    'Arguments can only have the "name" and "type" fields, found: ' . var_export($keys, true)
                );
            }

            $result[] = $argument;
        }

        return $result;
    }

    private static function stripRestArg(string $argument): string
    {
        if (strpos($argument, '...') === 0) {
            $argument = trim(substr($argument, 3));
        }

        return $argument;
    }

    /**
     * @param array{name: string, type: Type} $arguments
     * @phpstan-param array<int, array{name: string, type: Type}> $arguments
     *
     * @return MethodParameter[]
     */
    private function fromLegacyArguments(array $arguments): array
    {
        trigger_error(
            'Create method parameters via legacy format is deprecated add parameters via the constructor',
            E_USER_DEPRECATED
        );

        return array_map(
            static function ($arg) {
                return new MethodParameter(
                    $arg['name'],
                    $arg['type']
                );
            },
            $arguments
        );
    }
}
<?php
/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodParameterFactory;
use phpDocumentor\Reflection\Type;

final class MethodParameter
{
    private Type $type;

    private bool $isReference;

    private bool $isVariadic;

    private string $name;

    /** @var mixed */
    private $defaultValue;

    public const NO_DEFAULT_VALUE = '__NO_VALUE__';

    /**
     * @param mixed $defaultValue
     */
    public function __construct(
        string $name,
        Type $type,
        bool $isReference = false,
        bool $isVariadic = false,
        $defaultValue = self::NO_DEFAULT_VALUE
    ) {
        $this->type = $type;
        $this->isReference = $isReference;
        $this->isVariadic = $isVariadic;
        $this->name = $name;
        $this->defaultValue = $defaultValue;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getType(): Type
    {
        return $this->type;
    }

    public function isReference(): bool
    {
        return $this->isReference;
    }

    public function isVariadic(): bool
    {
        return $this->isVariadic;
    }

    public function getDefaultValue(): ?string
    {
        if ($this->defaultValue === self::NO_DEFAULT_VALUE) {
            return null;
        }

        return (new MethodParameterFactory())->format($this->defaultValue);
    }

    public function __toString(): string
    {
        return $this->getType() . ' ' .
            ($this->isReference() ? '&' : '') .
            ($this->isVariadic() ? '...' : '') .
            '$' . $this->getName() .
            (
                $this->defaultValue !== self::NO_DEFAULT_VALUE ?
                (new MethodParameterFactory())->format($this->defaultValue) :
                ''
            );
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

/**
 * Reflection class for a {@}mixin tag in a Docblock.
 */
final class Mixin extends TagWithType implements Factory\StaticMethod
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'mixin';
        $this->type        = $type;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$type, $description] = self::extractTypeFromBody($body);

        $type        = $typeResolver->resolve($type, $context);
        $description = $descriptionFactory->create($description, $context);

        return new static($type, $description);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Reflection class for the {@}param tag in a Docblock.
 */
final class Param extends TagWithType implements Factory\StaticMethod
{
    private ?string $variableName = null;

    /** @var bool determines whether this is a variadic argument */
    private bool $isVariadic;

    /** @var bool determines whether this is passed by reference */
    private bool $isReference;

    public function __construct(
        ?string $variableName,
        ?Type $type = null,
        bool $isVariadic = false,
        ?Description $description = null,
        bool $isReference = false
    ) {
        $this->name         = 'param';
        $this->variableName = $variableName;
        $this->type         = $type;
        $this->isVariadic   = $isVariadic;
        $this->description  = $description;
        $this->isReference  = $isReference;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$firstPart, $body] = self::extractTypeFromBody($body);

        $type         = null;
        $parts        = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
        $variableName = '';
        $isVariadic   = false;
        $isReference   = false;

        // if the first item that is encountered is not a variable; it is a type
        if ($firstPart && !self::strStartsWithVariable($firstPart)) {
            $type = $typeResolver->resolve($firstPart, $context);
        } else {
            // first part is not a type; we should prepend it to the parts array for further processing
            array_unshift($parts, $firstPart);
        }

        // if the next item starts with a $ or ...$ or &$ or &...$ it must be the variable name
        if (isset($parts[0]) && self::strStartsWithVariable($parts[0])) {
            $variableName = array_shift($parts);
            if ($type) {
                array_shift($parts);
            }

            Assert::notNull($variableName);

            if (strpos($variableName, '$') === 0) {
                $variableName = substr($variableName, 1);
            } elseif (strpos($variableName, '&$') === 0) {
                $isReference = true;
                $variableName = substr($variableName, 2);
            } elseif (strpos($variableName, '...$') === 0) {
                $isVariadic = true;
                $variableName = substr($variableName, 4);
            } elseif (strpos($variableName, '&...$') === 0) {
                $isVariadic   = true;
                $isReference  = true;
                $variableName = substr($variableName, 5);
            }
        }

        $description = $descriptionFactory->create(implode('', $parts), $context);

        return new static($variableName, $type, $isVariadic, $description, $isReference);
    }

    /**
     * Returns the variable's name.
     */
    public function getVariableName(): ?string
    {
        return $this->variableName;
    }

    /**
     * Returns whether this tag is variadic.
     */
    public function isVariadic(): bool
    {
        return $this->isVariadic;
    }

    /**
     * Returns whether this tag is passed by reference.
     */
    public function isReference(): bool
    {
        return $this->isReference;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $variableName = '';
        if ($this->variableName !== null && $this->variableName !== '') {
            $variableName .= ($this->isReference ? '&' : '') . ($this->isVariadic ? '...' : '');
            $variableName .= '$' . $this->variableName;
        }

        $type = (string) $this->type;

        return $type
            . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
            . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
    }

    private static function strStartsWithVariable(string $str): bool
    {
        return strpos($str, '$') === 0
               ||
               strpos($str, '...$') === 0
               ||
               strpos($str, '&$') === 0
               ||
               strpos($str, '&...$') === 0;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Reflection class for a {@}property tag in a Docblock.
 */
final class Property extends TagWithType implements Factory\StaticMethod
{
    protected ?string $variableName = null;

    public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
    {
        Assert::string($variableName);

        $this->name         = 'property';
        $this->variableName = $variableName;
        $this->type         = $type;
        $this->description  = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$firstPart, $body] = self::extractTypeFromBody($body);
        $type               = null;
        $parts              = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
        $variableName = '';

        // if the first item that is encountered is not a variable; it is a type
        if ($firstPart && $firstPart[0] !== '$') {
            $type = $typeResolver->resolve($firstPart, $context);
        } else {
            // first part is not a type; we should prepend it to the parts array for further processing
            array_unshift($parts, $firstPart);
        }

        // if the next item starts with a $ it must be the variable name
        if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
            $variableName = array_shift($parts);
            if ($type) {
                array_shift($parts);
            }

            Assert::notNull($variableName);

            $variableName = substr($variableName, 1);
        }

        $description = $descriptionFactory->create(implode('', $parts), $context);

        return new static($variableName, $type, $description);
    }

    /**
     * Returns the variable's name.
     */
    public function getVariableName(): ?string
    {
        return $this->variableName;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description !== null) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        if ($this->variableName !== null && $this->variableName !== '') {
            $variableName = '$' . $this->variableName;
        } else {
            $variableName = '';
        }

        $type = (string) $this->type;

        return $type
            . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
            . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Reflection class for a {@}property-read tag in a Docblock.
 */
final class PropertyRead extends TagWithType implements Factory\StaticMethod
{
    protected ?string $variableName = null;

    public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
    {
        Assert::string($variableName);

        $this->name         = 'property-read';
        $this->variableName = $variableName;
        $this->type         = $type;
        $this->description  = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$firstPart, $body] = self::extractTypeFromBody($body);
        $type               = null;
        $parts              = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
        $variableName = '';

        // if the first item that is encountered is not a variable; it is a type
        if ($firstPart && $firstPart[0] !== '$') {
            $type = $typeResolver->resolve($firstPart, $context);
        } else {
            // first part is not a type; we should prepend it to the parts array for further processing
            array_unshift($parts, $firstPart);
        }

        // if the next item starts with a $ it must be the variable name
        if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
            $variableName = array_shift($parts);
            if ($type) {
                array_shift($parts);
            }

            Assert::notNull($variableName);

            $variableName = substr($variableName, 1);
        }

        $description = $descriptionFactory->create(implode('', $parts), $context);

        return new static($variableName, $type, $description);
    }

    /**
     * Returns the variable's name.
     */
    public function getVariableName(): ?string
    {
        return $this->variableName;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description !== null) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        if ($this->variableName !== null && $this->variableName !== '') {
            $variableName = '$' . $this->variableName;
        } else {
            $variableName = '';
        }

        $type = (string) $this->type;

        return $type
            . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
            . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Reflection class for a {@}property-write tag in a Docblock.
 */
final class PropertyWrite extends TagWithType implements Factory\StaticMethod
{
    protected string $variableName;

    public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
    {
        Assert::string($variableName);

        $this->name         = 'property-write';
        $this->variableName = $variableName;
        $this->type         = $type;
        $this->description  = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$firstPart, $body] = self::extractTypeFromBody($body);
        $type               = null;
        $parts              = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
        $variableName = '';

        // if the first item that is encountered is not a variable; it is a type
        if ($firstPart && $firstPart[0] !== '$') {
            $type = $typeResolver->resolve($firstPart, $context);
        } else {
            // first part is not a type; we should prepend it to the parts array for further processing
            array_unshift($parts, $firstPart);
        }

        // if the next item starts with a $ it must be the variable name
        if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
            $variableName = array_shift($parts);
            if ($type) {
                array_shift($parts);
            }

            Assert::notNull($variableName);

            $variableName = substr($variableName, 1);
        }

        $description = $descriptionFactory->create(implode('', $parts), $context);

        return new static($variableName, $type, $description);
    }

    /**
     * Returns the variable's name.
     */
    public function getVariableName(): ?string
    {
        return $this->variableName;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        if ($this->variableName) {
            $variableName = '$' . $this->variableName;
        } else {
            $variableName = '';
        }

        $type = (string) $this->type;

        return $type
            . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
            . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;

use phpDocumentor\Reflection\Fqsen as RealFqsen;

/**
 * Fqsen reference used by {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
 */
final class Fqsen implements Reference
{
    private RealFqsen $fqsen;

    public function __construct(RealFqsen $fqsen)
    {
        $this->fqsen = $fqsen;
    }

    /**
     * @return string string representation of the referenced fqsen
     */
    public function __toString(): string
    {
        return (string) $this->fqsen;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;

/**
 * Interface for references in {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
 */
interface Reference
{
    public function __toString(): string;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;

use Webmozart\Assert\Assert;

/**
 * Url reference used by {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
 */
final class Url implements Reference
{
    private string $uri;

    public function __construct(string $uri)
    {
        Assert::stringNotEmpty($uri);
        $this->uri = $uri;
    }

    public function __toString(): string
    {
        return $this->uri;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

/**
 * Reflection class for a {@}return tag in a Docblock.
 */
final class Return_ extends TagWithType implements Factory\StaticMethod
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'return';
        $this->type        = $type;
        $this->description = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$type, $description] = self::extractTypeFromBody($body);

        $type        = $typeResolver->resolve($type, $context);
        $description = $descriptionFactory->create($description, $context);

        return new static($type, $description);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen as FqsenRef;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Reference;
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;
use function preg_match;

/**
 * Reflection class for an {@}see tag in a Docblock.
 */
final class See extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'see';

    protected Reference $refers;

    /**
     * Initializes this tag.
     */
    public function __construct(Reference $refers, ?Description $description = null)
    {
        $this->refers      = $refers;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?FqsenResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($descriptionFactory);

        $parts = Utils::pregSplit('/\s+/Su', $body, 2);
        $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;

        // https://tools.ietf.org/html/rfc2396#section-3
        if (preg_match('#\w://\w#', $parts[0])) {
            return new static(new Url($parts[0]), $description);
        }

        return new static(new FqsenRef(self::resolveFqsen($parts[0], $typeResolver, $context)), $description);
    }

    private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
    {
        Assert::notNull($fqsenResolver);
        $fqsenParts = explode('::', $parts);
        $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

        if (!array_key_exists(1, $fqsenParts)) {
            return $resolved;
        }

        return new Fqsen($resolved . '::' . $fqsenParts[1]);
    }

    /**
     * Returns the ref of this tag.
     */
    public function getReference(): Reference
    {
        return $this->refers;
    }

    /**
     * Returns a string representation of this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $refers = (string) $this->refers;

        return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;

/**
 * Reflection class for a {@}since tag in a Docblock.
 */
final class Since extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'since';

    /**
     * PCRE regular expression matching a version vector.
     * Assumes the "x" modifier.
     */
    public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';

    /** @var string|null The version vector. */
    private ?string $version = null;

    public function __construct(?string $version = null, ?Description $description = null)
    {
        Assert::nullOrNotEmpty($version);

        $this->version     = $version;
        $this->description = $description;
    }

    public static function create(
        ?string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): ?self {
        if ($body === null || $body === '') {
            return new static();
        }

        $matches = [];
        if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
            return null;
        }

        Assert::notNull($descriptionFactory);

        return new static(
            $matches[1],
            $descriptionFactory->create($matches[2] ?? '', $context)
        );
    }

    /**
     * Gets the version section of the tag.
     */
    public function getVersion(): ?string
    {
        return $this->version;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description !== null) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $version = (string) $this->version;

        return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;

/**
 * Reflection class for a {@}source tag in a Docblock.
 */
final class Source extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'source';

    /** @var int The starting line, relative to the structural element's location. */
    private int $startingLine;

    /** @var int|null The number of lines, relative to the starting line. NULL means "to the end". */
    private ?int $lineCount = null;

    /**
     * @param int|string      $startingLine should be a to int convertible value
     * @param int|string|null $lineCount    should be a to int convertible value
     */
    public function __construct($startingLine, $lineCount = null, ?Description $description = null)
    {
        Assert::integerish($startingLine);
        Assert::nullOrIntegerish($lineCount);

        $this->startingLine = (int) $startingLine;
        $this->lineCount    = $lineCount !== null ? (int) $lineCount : null;
        $this->description  = $description;
    }

    public static function create(
        string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::stringNotEmpty($body);
        Assert::notNull($descriptionFactory);

        $startingLine = 1;
        $lineCount    = null;
        $description  = null;

        // Starting line / Number of lines / Description
        if (preg_match('/^([1-9]\d*)\s*(?:((?1))\s+)?(.*)$/sux', $body, $matches)) {
            $startingLine = (int) $matches[1];
            if (isset($matches[2]) && $matches[2] !== '') {
                $lineCount = (int) $matches[2];
            }

            $description = $matches[3];
        }

        return new static($startingLine, $lineCount, $descriptionFactory->create($description ?? '', $context));
    }

    /**
     * Gets the starting line.
     *
     * @return int The starting line, relative to the structural element's
     *     location.
     */
    public function getStartingLine(): int
    {
        return $this->startingLine;
    }

    /**
     * Returns the number of lines.
     *
     * @return int|null The number of lines, relative to the starting line. NULL
     *     means "to the end".
     */
    public function getLineCount(): ?int
    {
        return $this->lineCount;
    }

    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $startingLine = (string) $this->startingLine;

        $lineCount = $this->lineCount !== null ? ' ' . $this->lineCount : '';

        return $startingLine
            . $lineCount
            . ($description !== ''
                ? ' ' . $description
                : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use InvalidArgumentException;
use phpDocumentor\Reflection\Type;

use function in_array;
use function sprintf;
use function strlen;
use function substr;
use function trim;

abstract class TagWithType extends BaseTag
{
    /** @var ?Type */
    protected ?Type $type = null;

    /**
     * Returns the type section of the variable.
     */
    public function getType(): ?Type
    {
        return $this->type;
    }

    /**
     * @return string[]
     */
    protected static function extractTypeFromBody(string $body): array
    {
        $type         = '';
        $nestingLevel = 0;
        for ($i = 0, $iMax = strlen($body); $i < $iMax; $i++) {
            $character = $body[$i];

            if ($nestingLevel === 0 && trim($character) === '') {
                break;
            }

            $type .= $character;
            if (in_array($character, ['<', '(', '[', '{'])) {
                $nestingLevel++;
                continue;
            }

            if (in_array($character, ['>', ')', ']', '}'])) {
                $nestingLevel--;
                continue;
            }
        }

        if ($nestingLevel < 0 || $nestingLevel > 0) {
            throw new InvalidArgumentException(
                sprintf('Could not find type in %s, please check for malformed notations', $body)
            );
        }

        $description = trim(substr($body, strlen($type)));

        return [$type, $description];
    }

    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $type = (string) $this->type;

        return $type . ($description !== '' ? ($type !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Type;

/**
 * Reflection class for a {@}template tag in a Docblock.
 */
final class Template extends BaseTag
{
    /** @var non-empty-string */
    private string $templateName;

    /** @var ?Type The real type */
    private ?Type $bound;

    private ?Type $default;

    /** @param non-empty-string $templateName */
    public function __construct(
        string $templateName,
        ?Type $bound = null,
        ?Type $default = null,
        ?Description $description = null
    ) {
        $this->name = 'template';
        $this->templateName = $templateName;
        $this->bound = $bound;
        $this->default = $default;
        $this->description = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(string $body): ?Tag
    {
        Deprecation::trigger(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );

        return null;
    }

    public function getTemplateName(): string
    {
        return $this->templateName;
    }

    public function getBound(): ?Type
    {
        return $this->bound;
    }

    public function getDefault(): ?Type
    {
        return $this->default;
    }

    public function __toString(): string
    {
        $bound = $this->bound !== null ? ' of ' . $this->bound : '';
        $default = $this->default !== null ? ' = ' . $this->default : '';

        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        return $this->templateName . $bound . $default . ($description !== '' ? ' ' . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

/**
 * Reflection class for a {@}template-covariant tag in a Docblock.
 */
final class TemplateCovariant extends TagWithType implements Factory\StaticMethod
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'template-covariant';
        $this->type        = $type;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$type, $description] = self::extractTypeFromBody($body);

        $type        = $typeResolver->resolve($type, $context);
        $description = $descriptionFactory->create($description, $context);

        return new static($type, $description);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\Type;

/**
 * Reflection class for a {@}template-extends tag in a Docblock.
 */
final class TemplateExtends extends Extends_
{
    public function __construct(Type $type, ?Description $description = null)
    {
        parent::__construct($type, $description);
        $this->name = 'template-extends';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\Type;

/**
 * Reflection class for a {@}template-implements tag in a Docblock.
 */
final class TemplateImplements extends Implements_
{
    public function __construct(Type $type, ?Description $description = null)
    {
        parent::__construct($type, $description);
        $this->name = 'template-implements';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

/**
 * Reflection class for a {@}throws tag in a Docblock.
 */
final class Throws extends TagWithType implements Factory\StaticMethod
{
    public function __construct(Type $type, ?Description $description = null)
    {
        $this->name        = 'throws';
        $this->type        = $type;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$type, $description] = self::extractTypeFromBody($body);

        $type        = $typeResolver->resolve($type, $context);
        $description = $descriptionFactory->create($description, $context);

        return new static($type, $description);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function explode;

/**
 * Reflection class for a {@}uses tag in a Docblock.
 */
final class Uses extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'uses';

    protected Fqsen $refers;

    /**
     * Initializes this tag.
     */
    public function __construct(Fqsen $refers, ?Description $description = null)
    {
        $this->refers      = $refers;
        $this->description = $description;
    }

    public static function create(
        string $body,
        ?FqsenResolver $resolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Assert::notNull($resolver);
        Assert::notNull($descriptionFactory);

        $parts = Utils::pregSplit('/\s+/Su', $body, 2);

        return new static(
            self::resolveFqsen($parts[0], $resolver, $context),
            $descriptionFactory->create($parts[1] ?? '', $context)
        );
    }

    private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
    {
        Assert::notNull($fqsenResolver);
        $fqsenParts = explode('::', $parts);
        $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);

        if (!array_key_exists(1, $fqsenParts)) {
            return $resolved;
        }

        return new Fqsen($resolved . '::' . $fqsenParts[1]);
    }

    /**
     * Returns the structural element this tag refers to.
     */
    public function getReference(): Fqsen
    {
        return $this->refers;
    }

    /**
     * Returns a string representation of this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $refers = (string) $this->refers;

        return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
use Webmozart\Assert\Assert;

use function array_shift;
use function array_unshift;
use function implode;
use function strpos;
use function substr;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
 * Reflection class for a {@}var tag in a Docblock.
 */
final class Var_ extends TagWithType implements Factory\StaticMethod
{
    protected ?string $variableName = '';

    public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
    {
        Assert::string($variableName);

        $this->name         = 'var';
        $this->variableName = $variableName;
        $this->type         = $type;
        $this->description  = $description;
    }

    /**
     * @deprecated Create using static factory is deprecated,
     *  this method should not be called directly by library consumers
     */
    public static function create(
        string $body,
        ?TypeResolver $typeResolver = null,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): self {
        Deprecation::triggerIfCalledFromOutside(
            'phpdocumentor/reflection-docblock',
            'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
            'Create using static factory is deprecated, this method should not be called directly
             by library consumers',
        );
        Assert::stringNotEmpty($body);
        Assert::notNull($typeResolver);
        Assert::notNull($descriptionFactory);

        [$firstPart, $body] = self::extractTypeFromBody($body);

        $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
        $type         = null;
        $variableName = '';

        // if the first item that is encountered is not a variable; it is a type
        if ($firstPart && $firstPart[0] !== '$') {
            $type = $typeResolver->resolve($firstPart, $context);
        } else {
            // first part is not a type; we should prepend it to the parts array for further processing
            array_unshift($parts, $firstPart);
        }

        // if the next item starts with a $ it must be the variable name
        if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
            $variableName = array_shift($parts);
            if ($type) {
                array_shift($parts);
            }

            Assert::notNull($variableName);

            $variableName = substr($variableName, 1);
        }

        $description = $descriptionFactory->create(implode('', $parts), $context);

        return new static($variableName, $type, $description);
    }

    /**
     * Returns the variable's name.
     */
    public function getVariableName(): ?string
    {
        return $this->variableName;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description !== null) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        if ($this->variableName !== null && $this->variableName !== '') {
            $variableName = '$' . $this->variableName;
        } else {
            $variableName = '';
        }

        $type = (string) $this->type;

        return $type
            . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
            . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\DocBlock\Tags;

use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use Webmozart\Assert\Assert;

use function preg_match;

/**
 * Reflection class for a {@}version tag in a Docblock.
 */
final class Version extends BaseTag implements Factory\StaticMethod
{
    protected string $name = 'version';

    /**
     * PCRE regular expression matching a version vector.
     * Assumes the "x" modifier.
     */
    public const REGEX_VECTOR = '(?:
        # Normal release vectors.
        \d\S*
        |
        # VCS version vectors. Per PHPCS, they are expected to
        # follow the form of the VCS name, followed by ":", followed
        # by the version vector itself.
        # By convention, popular VCSes like CVS, SVN and GIT use "$"
        # around the actual version vector.
        [^\s\:]+\:\s*\$[^\$]+\$
    )';

    /** @var string|null The version vector. */
    private ?string $version = null;

    public function __construct(?string $version = null, ?Description $description = null)
    {
        Assert::nullOrStringNotEmpty($version);

        $this->version     = $version;
        $this->description = $description;
    }

    public static function create(
        ?string $body,
        ?DescriptionFactory $descriptionFactory = null,
        ?TypeContext $context = null
    ): ?self {
        if ($body === null || $body === '') {
            return new static();
        }

        $matches = [];
        if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
            return null;
        }

        $description = null;
        if ($descriptionFactory !== null) {
            $description = $descriptionFactory->create($matches[2] ?? '', $context);
        }

        return new static(
            $matches[1],
            $description
        );
    }

    /**
     * Gets the version section of the tag.
     */
    public function getVersion(): ?string
    {
        return $this->version;
    }

    /**
     * Returns a string representation for this tag.
     */
    public function __toString(): string
    {
        if ($this->description) {
            $description = $this->description->render();
        } else {
            $description = '';
        }

        $version = (string) $this->version;

        return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
use Webmozart\Assert\Assert;

final class DocBlock
{
    /** @var string The opening line for this docblock. */
    private string $summary;

    /** @var DocBlock\Description The actual description for this docblock. */
    private DocBlock\Description $description;

    /** @var Tag[] An array containing all the tags in this docblock; except inline. */
    private array $tags = [];

    /** @var Types\Context|null Information about the context of this DocBlock. */
    private ?Types\Context $context = null;

    /** @var Location|null Information about the location of this DocBlock. */
    private ?Location $location = null;

    /** @var bool Is this DocBlock (the start of) a template? */
    private bool $isTemplateStart;

    /** @var bool Does this DocBlock signify the end of a DocBlock template? */
    private bool $isTemplateEnd;

    /**
     * @param DocBlock\Tag[] $tags
     * @param Types\Context  $context  The context in which the DocBlock occurs.
     * @param Location       $location The location within the file that this DocBlock occurs in.
     */
    public function __construct(
        string $summary = '',
        ?DocBlock\Description $description = null,
        array $tags = [],
        ?Types\Context $context = null,
        ?Location $location = null,
        bool $isTemplateStart = false,
        bool $isTemplateEnd = false
    ) {
        Assert::allIsInstanceOf($tags, Tag::class);

        $this->summary     = $summary;
        $this->description = $description ?: new DocBlock\Description('');
        foreach ($tags as $tag) {
            $this->addTag($tag);
        }

        $this->context  = $context;
        $this->location = $location;

        $this->isTemplateEnd   = $isTemplateEnd;
        $this->isTemplateStart = $isTemplateStart;
    }

    public function getSummary(): string
    {
        return $this->summary;
    }

    public function getDescription(): DocBlock\Description
    {
        return $this->description;
    }

    /**
     * Returns the current context.
     */
    public function getContext(): ?Types\Context
    {
        return $this->context;
    }

    /**
     * Returns the current location.
     */
    public function getLocation(): ?Location
    {
        return $this->location;
    }

    /**
     * Returns whether this DocBlock is the start of a Template section.
     *
     * A Docblock may serve as template for a series of subsequent DocBlocks. This is indicated by a special marker
     * (`#@+`) that is appended directly after the opening `/**` of a DocBlock.
     *
     * An example of such an opening is:
     *
     * ```
     * /**#@+
     *  * My DocBlock
     *  * /
     * ```
     *
     * The description and tags (not the summary!) are copied onto all subsequent DocBlocks and also applied to all
     * elements that follow until another DocBlock is found that contains the closing marker (`#@-`).
     *
     * @see self::isTemplateEnd() for the check whether a closing marker was provided.
     */
    public function isTemplateStart(): bool
    {
        return $this->isTemplateStart;
    }

    /**
     * Returns whether this DocBlock is the end of a Template section.
     *
     * @see self::isTemplateStart() for a more complete description of the Docblock Template functionality.
     */
    public function isTemplateEnd(): bool
    {
        return $this->isTemplateEnd;
    }

    /**
     * Returns the tags for this DocBlock.
     *
     * @return Tag[]
     */
    public function getTags(): array
    {
        return $this->tags;
    }

    /**
     * Returns an array of tags matching the given name. If no tags are found
     * an empty array is returned.
     *
     * @param string $name String to search by.
     *
     * @return Tag[]
     */
    public function getTagsByName(string $name): array
    {
        $result = [];

        foreach ($this->getTags() as $tag) {
            if ($tag->getName() !== $name) {
                continue;
            }

            $result[] = $tag;
        }

        return $result;
    }

    /**
     * Returns an array of tags with type matching the given name. If no tags are found
     * an empty array is returned.
     *
     * @param string $name String to search by.
     *
     * @return TagWithType[]
     */
    public function getTagsWithTypeByName(string $name): array
    {
        $result = [];

        foreach ($this->getTagsByName($name) as $tag) {
            if (!$tag instanceof TagWithType) {
                continue;
            }

            $result[] = $tag;
        }

        return $result;
    }

    /**
     * Checks if a tag of a certain type is present in this DocBlock.
     *
     * @param string $name Tag name to check for.
     */
    public function hasTag(string $name): bool
    {
        foreach ($this->getTags() as $tag) {
            if ($tag->getName() === $name) {
                return true;
            }
        }

        return false;
    }

    /**
     * Remove a tag from this DocBlock.
     *
     * @param Tag $tagToRemove The tag to remove.
     */
    public function removeTag(Tag $tagToRemove): void
    {
        foreach ($this->tags as $key => $tag) {
            if ($tag === $tagToRemove) {
                unset($this->tags[$key]);
                break;
            }
        }
    }

    /**
     * Adds a tag to this DocBlock.
     *
     * @param Tag $tag The tag to add.
     */
    private function addTag(Tag $tag): void
    {
        $this->tags[] = $tag;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use LogicException;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\TagFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ExtendsFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ImplementsFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateExtendsFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\TemplateImplementsFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory;
use Webmozart\Assert\Assert;

use function array_shift;
use function count;
use function explode;
use function is_object;
use function method_exists;
use function preg_match;
use function preg_replace;
use function str_replace;
use function strpos;
use function substr;
use function trim;

final class DocBlockFactory implements DocBlockFactoryInterface
{
    private DocBlock\DescriptionFactory $descriptionFactory;

    private TagFactory $tagFactory;

    /**
     * Initializes this factory with the required subcontractors.
     */
    public function __construct(DescriptionFactory $descriptionFactory, TagFactory $tagFactory)
    {
        $this->descriptionFactory = $descriptionFactory;
        $this->tagFactory = $tagFactory;
    }

    /**
     * Factory method for easy instantiation.
     *
     * @param array<string, class-string<Tag>|Factory> $additionalTags
     */
    public static function createInstance(array $additionalTags = []): DocBlockFactoryInterface
    {
        $fqsenResolver = new FqsenResolver();
        $tagFactory = new StandardTagFactory($fqsenResolver);
        $descriptionFactory = new DescriptionFactory($tagFactory);
        $typeResolver = new TypeResolver($fqsenResolver);

        $phpstanTagFactory = new AbstractPHPStanFactory(
            new ParamFactory($typeResolver, $descriptionFactory),
            new VarFactory($typeResolver, $descriptionFactory),
            new ReturnFactory($typeResolver, $descriptionFactory),
            new PropertyFactory($typeResolver, $descriptionFactory),
            new PropertyReadFactory($typeResolver, $descriptionFactory),
            new PropertyWriteFactory($typeResolver, $descriptionFactory),
            new MethodFactory($typeResolver, $descriptionFactory),
            new ImplementsFactory($typeResolver, $descriptionFactory),
            new ExtendsFactory($typeResolver, $descriptionFactory),
            new TemplateFactory($typeResolver, $descriptionFactory),
            new TemplateImplementsFactory($typeResolver, $descriptionFactory),
            new TemplateExtendsFactory($typeResolver, $descriptionFactory),
        );

        $tagFactory->addService($descriptionFactory);
        $tagFactory->addService($typeResolver);
        $tagFactory->registerTagHandler('param', $phpstanTagFactory);
        $tagFactory->registerTagHandler('var', $phpstanTagFactory);
        $tagFactory->registerTagHandler('return', $phpstanTagFactory);
        $tagFactory->registerTagHandler('property', $phpstanTagFactory);
        $tagFactory->registerTagHandler('property-read', $phpstanTagFactory);
        $tagFactory->registerTagHandler('property-write', $phpstanTagFactory);
        $tagFactory->registerTagHandler('method', $phpstanTagFactory);
        $tagFactory->registerTagHandler('extends', $phpstanTagFactory);
        $tagFactory->registerTagHandler('implements', $phpstanTagFactory);
        $tagFactory->registerTagHandler('template', $phpstanTagFactory);
        $tagFactory->registerTagHandler('template-extends', $phpstanTagFactory);
        $tagFactory->registerTagHandler('template-implements', $phpstanTagFactory);

        $docBlockFactory = new self($descriptionFactory, $tagFactory);
        foreach ($additionalTags as $tagName => $tagHandler) {
            $docBlockFactory->registerTagHandler($tagName, $tagHandler);
        }

        return $docBlockFactory;
    }

    /**
     * @param object|string $docblock A string containing the DocBlock to parse or an object supporting the
     *                                getDocComment method (such as a ReflectionClass object).
     */
    public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock
    {
        if (is_object($docblock)) {
            if (!method_exists($docblock, 'getDocComment')) {
                $exceptionMessage = 'Invalid object passed; the given object must support the getDocComment method';

                throw new InvalidArgumentException($exceptionMessage);
            }

            $docblock = $docblock->getDocComment();
            Assert::string($docblock);
        }

        Assert::stringNotEmpty($docblock);

        if ($context === null) {
            $context = new Types\Context('');
        }

        $parts = $this->splitDocBlock($this->stripDocComment($docblock));

        [$templateMarker, $summary, $description, $tags] = $parts;

        return new DocBlock(
            $summary,
            $description ? $this->descriptionFactory->create($description, $context) : null,
            $this->parseTagBlock($tags, $context),
            $context,
            $location,
            $templateMarker === '#@+',
            $templateMarker === '#@-'
        );
    }

    /**
     * @param class-string<Tag>|Factory $handler
     */
    public function registerTagHandler(string $tagName, $handler): void
    {
        $this->tagFactory->registerTagHandler($tagName, $handler);
    }

    /**
     * Strips the asterisks from the DocBlock comment.
     *
     * @param string $comment String containing the comment text.
     */
    private function stripDocComment(string $comment): string
    {
        $comment = preg_replace('#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]?(.*)?#u', '$1', $comment);
        Assert::string($comment);
        $comment = trim($comment);

        // reg ex above is not able to remove */ from a single line docblock
        if (substr($comment, -2) === '*/') {
            $comment = trim(substr($comment, 0, -2));
        }

        return str_replace(["\r\n", "\r"], "\n", $comment);
    }

    // phpcs:disable

    /**
     * Splits the DocBlock into a template marker, summary, description and block of tags.
     *
     * @param string $comment Comment to split into the sub-parts.
     *
     * @return string[] containing the template marker (if any), summary, description and a string containing the tags.
     *
     * @author Mike van Riel <me@mikevanriel.com> for extending the regex with template marker support.
     *
     * @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split.
     */
    private function splitDocBlock(string $comment): array
    {
        // phpcs:enable
        // Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This
        // method does not split tags so we return this verbatim as the fourth result (tags). This saves us the
        // performance impact of running a regular expression
        if (strpos($comment, '@') === 0) {
            return ['', '', '', $comment];
        }

        // clears all extra horizontal whitespace from the line endings to prevent parsing issues
        $comment = preg_replace('/\h*$/Sum', '', $comment);
        Assert::string($comment);
        /*
         * Splits the docblock into a template marker, summary, description and tags section.
         *
         * - The template marker is empty, #@+ or #@- if the DocBlock starts with either of those (a newline may
         *   occur after it and will be stripped).
         * - The short description is started from the first character until a dot is encountered followed by a
         *   newline OR two consecutive newlines (horizontal whitespace is taken into account to consider spacing
         *   errors). This is optional.
         * - The long description, any character until a new line is encountered followed by an @ and word
         *   characters (a tag). This is optional.
         * - Tags; the remaining characters
         *
         * Big thanks to RichardJ for contributing this Regular Expression
         */
        preg_match(
            '/
            \A
            # 1. Extract the template marker
            (?:(\#\@\+|\#\@\-)\n?)?

            # 2. Extract the summary
            (?:
              (?! @\pL ) # The summary may not start with an @
              (
                [^\n.]+
                (?:
                  (?! \. \n | \n{2} )     # End summary upon a dot followed by newline or two newlines
                  [\n.]* (?! [ \t]* @\pL ) # End summary when an @ is found as first character on a new line
                  [^\n.]+                 # Include anything else
                )*
                \.?
              )?
            )

            # 3. Extract the description
            (?:
              \s*        # Some form of whitespace _must_ precede a description because a summary must be there
              (?! @\pL ) # The description may not start with an @
              (
                [^\n]+
                (?: \n+
                  (?! [ \t]* @\pL ) # End description when an @ is found as first character on a new line
                  [^\n]+            # Include anything else
                )*
              )
            )?

            # 4. Extract the tags (anything that follows)
            (\s+ [\s\S]*)? # everything that follows
            /ux',
            $comment,
            $matches
        );
        array_shift($matches);

        while (count($matches) < 4) {
            $matches[] = '';
        }

        return $matches;
    }

    /**
     * Creates the tag objects.
     *
     * @param string $tags Tag block to parse.
     * @param Types\Context $context Context of the parsed Tag
     *
     * @return DocBlock\Tag[]
     */
    private function parseTagBlock(string $tags, Types\Context $context): array
    {
        $tags = $this->filterTagBlock($tags);
        if ($tags === null) {
            return [];
        }

        $result = [];
        $lines = $this->splitTagBlockIntoTagLines($tags);
        foreach ($lines as $key => $tagLine) {
            $result[$key] = $this->tagFactory->create(trim($tagLine), $context);
        }

        return $result;
    }

    /**
     * @return string[]
     */
    private function splitTagBlockIntoTagLines(string $tags): array
    {
        $result = [];
        foreach (explode("\n", $tags) as $tagLine) {
            if ($tagLine !== '' && strpos($tagLine, '@') === 0) {
                $result[] = $tagLine;
            } else {
                $result[count($result) - 1] .= "\n" . $tagLine;
            }
        }

        return $result;
    }

    private function filterTagBlock(string $tags): ?string
    {
        $tags = trim($tags);
        if (!$tags) {
            return null;
        }

        if ($tags[0] !== '@') {
            // @codeCoverageIgnoreStart
            // Can't simulate this; this only happens if there is an error with the parsing of the DocBlock that
            // we didn't foresee.

            throw new LogicException('A tag block started with text instead of an at-sign(@): ' . $tags);

            // @codeCoverageIgnoreEnd
        }

        return $tags;
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\DocBlock\Tag;

// phpcs:ignore SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming.SuperfluousSuffix
interface DocBlockFactoryInterface
{
    /**
     * Factory method for easy instantiation.
     *
     * @param array<string, class-string<Tag>> $additionalTags
     */
    public static function createInstance(array $additionalTags = []): self;

    /**
     * @param string|object $docblock
     */
    public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock;
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\Exception;

use InvalidArgumentException;

use const PREG_BACKTRACK_LIMIT_ERROR;
use const PREG_BAD_UTF8_ERROR;
use const PREG_BAD_UTF8_OFFSET_ERROR;
use const PREG_INTERNAL_ERROR;
use const PREG_JIT_STACKLIMIT_ERROR;
use const PREG_NO_ERROR;
use const PREG_RECURSION_LIMIT_ERROR;

final class PcreException extends InvalidArgumentException
{
    public static function createFromPhpError(int $errorCode): self
    {
        switch ($errorCode) {
            case PREG_BACKTRACK_LIMIT_ERROR:
                return new self('Backtrack limit error');

            case PREG_RECURSION_LIMIT_ERROR:
                return new self('Recursion limit error');

            case PREG_BAD_UTF8_ERROR:
                return new self('Bad UTF8 error');

            case PREG_BAD_UTF8_OFFSET_ERROR:
                return new self('Bad UTF8 offset error');

            case PREG_JIT_STACKLIMIT_ERROR:
                return new self('Jit stacklimit error');

            case PREG_NO_ERROR:
            case PREG_INTERNAL_ERROR:
            default:
        }

        return new self('Unknown Pcre error');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\Exception\PcreException;
use Webmozart\Assert\Assert;

use function preg_last_error;
use function preg_split as php_preg_split;

abstract class Utils
{
    /**
     * Wrapper function for phps preg_split
     *
     * This function is inspired by {@link https://github.com/thecodingmachine/safe/blob/master/generated/pcre.php}. But
     * since this library is all about performance we decided to strip everything we don't need. Reducing the amount
     * of files that have to be loaded, etc.
     *
     * @param string $pattern The pattern to search for, as a string.
     * @param string $subject The input string.
     * @param int $limit If specified, then only substrings up to limit are returned with the
     *      rest of the string being placed in the last substring. A limit of -1 or 0 means "no limit".
     * @param int $flags flags can be any combination of the following flags (combined with the | bitwise operator):
     * *PREG_SPLIT_NO_EMPTY*
     *      If this flag is set, only non-empty pieces will be returned by preg_split().
     * *PREG_SPLIT_DELIM_CAPTURE*
     *      If this flag is set, parenthesized expression in the delimiter pattern will be captured
     *      and returned as well.
     * *PREG_SPLIT_OFFSET_CAPTURE*
     *      If this flag is set, for every occurring match the appendant string offset will also be returned.
     *      Note that this changes the return value in an array where every element is an array consisting of the
     *      matched string at offset 0 and its string offset into subject at offset 1.
     *
     * @return string[] Returns an array containing substrings of subject
     *                                                      split along boundaries matched by pattern
     *
     * @throws PcreException
     */
    public static function pregSplit(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
    {
        $parts = php_preg_split($pattern, $subject, $limit, $flags);
        if ($parts === false) {
            throw PcreException::createFromPhpError(preg_last_error());
        }

        Assert::allString($parts);

        return $parts;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use InvalidArgumentException;
use phpDocumentor\Reflection\Types\Context;

use function explode;
use function implode;
use function strpos;

/**
 * Resolver for Fqsen using Context information
 *
 * @psalm-immutable
 */
class FqsenResolver
{
    /** @var string Definition of the NAMESPACE operator in PHP */
    private const OPERATOR_NAMESPACE = '\\';

    public function resolve(string $fqsen, ?Context $context = null): Fqsen
    {
        if ($context === null) {
            $context = new Context('');
        }

        if ($this->isFqsen($fqsen)) {
            return new Fqsen($fqsen);
        }

        return $this->resolvePartialStructuralElementName($fqsen, $context);
    }

    /**
     * Tests whether the given type is a Fully Qualified Structural Element Name.
     */
    private function isFqsen(string $type): bool
    {
        return strpos($type, self::OPERATOR_NAMESPACE) === 0;
    }

    /**
     * Resolves a partial Structural Element Name (i.e. `Reflection\DocBlock`) to its FQSEN representation
     * (i.e. `\phpDocumentor\Reflection\DocBlock`) based on the Namespace and aliases mentioned in the Context.
     *
     * @throws InvalidArgumentException When type is not a valid FQSEN.
     */
    private function resolvePartialStructuralElementName(string $type, Context $context): Fqsen
    {
        $typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2);

        $namespaceAliases = $context->getNamespaceAliases();

        // if the first segment is not an alias; prepend namespace name and return
        if (!isset($namespaceAliases[$typeParts[0]])) {
            $namespace = $context->getNamespace();
            if ($namespace !== '') {
                $namespace .= self::OPERATOR_NAMESPACE;
            }

            return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type);
        }

        $typeParts[0] = $namespaceAliases[$typeParts[0]];

        return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts));
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

interface PseudoType extends Type
{
    public function underlyingType(): Type;
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\Mixed_;

use function implode;

/** @psalm-immutable */
class ArrayShape implements PseudoType
{
    /** @var ArrayShapeItem[] */
    private $items;

    public function __construct(ArrayShapeItem ...$items)
    {
        $this->items = $items;
    }

    /**
     * @return ArrayShapeItem[]
     */
    public function getItems(): array
    {
        return $this->items;
    }

    public function underlyingType(): Type
    {
        return new Array_(new Mixed_(), new ArrayKey());
    }

    public function __toString(): string
    {
        return 'array{' . implode(', ', $this->items) . '}';
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

class ArrayShapeItem extends ShapeItem
{
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class CallableString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'callable-string';
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;

use function sprintf;

/** @psalm-immutable */
final class ConstExpression implements PseudoType
{
    /** @var Type */
    private $owner;
    /** @var string */
    private $expression;

    public function __construct(Type $owner, string $expression)
    {
        $this->owner = $owner;
        $this->expression = $expression;
    }

    public function getOwner(): Type
    {
        return $this->owner;
    }

    public function getExpression(): string
    {
        return $this->expression;
    }

    public function underlyingType(): Type
    {
        return new Mixed_();
    }

    public function __toString(): string
    {
        return sprintf('%s::%s', (string) $this->owner, $this->expression);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link https://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Boolean;

use function class_alias;

/**
 * Value Object representing the PseudoType 'False', which is a Boolean type.
 *
 * @psalm-immutable
 */
final class False_ extends Boolean implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Boolean();
    }

    public function __toString(): string
    {
        return 'false';
    }
}

class_alias(False_::class, 'phpDocumentor\Reflection\Types\False_', false);
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Float_;

/** @psalm-immutable */
class FloatValue implements PseudoType
{
    /** @var float */
    private $value;

    public function __construct(float $value)
    {
        $this->value = $value;
    }

    public function getValue(): float
    {
        return $this->value;
    }

    public function underlyingType(): Type
    {
        return new Float_();
    }

    public function __toString(): string
    {
        return (string) $this->value;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class HtmlEscapedString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'html-escaped-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;

/**
 * Value Object representing the type 'int'.
 *
 * @psalm-immutable
 */
final class IntegerRange extends Integer implements PseudoType
{
    /** @var string */
    private $minValue;

    /** @var string */
    private $maxValue;

    public function __construct(string $minValue, string $maxValue)
    {
        $this->minValue = $minValue;
        $this->maxValue = $maxValue;
    }

    public function underlyingType(): Type
    {
        return new Integer();
    }

    public function getMinValue(): string
    {
        return $this->minValue;
    }

    public function getMaxValue(): string
    {
        return $this->maxValue;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'int<' . $this->minValue . ', ' . $this->maxValue . '>';
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;

/** @psalm-immutable */
final class IntegerValue implements PseudoType
{
    /** @var int */
    private $value;

    public function __construct(int $value)
    {
        $this->value = $value;
    }

    public function getValue(): int
    {
        return $this->value;
    }

    public function underlyingType(): Type
    {
        return new Integer();
    }

    public function __toString(): string
    {
        return (string) $this->value;
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use function implode;

/** @psalm-immutable */
final class ListShape extends ArrayShape
{
    public function __toString(): string
    {
        return 'list{' . implode(', ', $this->getItems()) . '}';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

final class ListShapeItem extends ArrayShapeItem
{
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\Mixed_;

/**
 * Value Object representing the type 'list'.
 *
 * @psalm-immutable
 */
final class List_ extends Array_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Array_();
    }

    public function __construct(?Type $valueType = null)
    {
        parent::__construct($valueType, new Integer());
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->valueType instanceof Mixed_) {
            return 'list';
        }

        return 'list<' . $this->valueType . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class LiteralString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'literal-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class LowercaseString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'lowercase-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;

/**
 * Value Object representing the type 'int'.
 *
 * @psalm-immutable
 */
final class NegativeInteger extends Integer implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Integer();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'negative-int';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Mixed_;

/**
 * Value Object representing the type 'non-empty-array'.
 *
 * @psalm-immutable
 */
final class NonEmptyArray extends Array_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Array_($this->valueType, $this->keyType);
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->keyType) {
            return 'non-empty-array<' . $this->keyType . ',' . $this->valueType . '>';
        }

        if ($this->valueType instanceof Mixed_) {
            return 'non-empty-array';
        }

        return 'non-empty-array<' . $this->valueType . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\Mixed_;

/**
 * Value Object representing the type 'non-empty-list'.
 *
 * @psalm-immutable
 */
final class NonEmptyList extends Array_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Array_($this->valueType, $this->keyType);
    }

    public function __construct(?Type $valueType = null)
    {
        parent::__construct($valueType, new Integer());
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->valueType instanceof Mixed_) {
            return 'non-empty-list';
        }

        return 'non-empty-list<' . $this->valueType . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class NonEmptyLowercaseString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'non-empty-lowercase-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class NonEmptyString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'non-empty-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class NumericString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'numeric-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\AggregatedType;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Float_;
use phpDocumentor\Reflection\Types\Integer;

/**
 * Value Object representing the 'numeric' pseudo-type, which is either a numeric-string, integer or float.
 *
 * @psalm-immutable
 */
final class Numeric_ extends AggregatedType implements PseudoType
{
    public function __construct()
    {
        AggregatedType::__construct([new NumericString(), new Integer(), new Float_()], '|');
    }

    public function underlyingType(): Type
    {
        return new Compound([new NumericString(), new Integer(), new Float_()]);
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'numeric';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Object_;

use function implode;

/** @psalm-immutable */
final class ObjectShape implements PseudoType
{
    /** @var ObjectShapeItem[] */
    private $items;

    public function __construct(ObjectShapeItem ...$items)
    {
        $this->items = $items;
    }

    /**
     * @return ObjectShapeItem[]
     */
    public function getItems(): array
    {
        return $this->items;
    }

    public function underlyingType(): Type
    {
        return new Object_();
    }

    public function __toString(): string
    {
        return 'object{' . implode(', ', $this->items) . '}';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

final class ObjectShapeItem extends ShapeItem
{
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;

/**
 * Value Object representing the type 'int'.
 *
 * @psalm-immutable
 */
final class PositiveInteger extends Integer implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Integer();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'positive-int';
    }
}
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;

use function sprintf;

abstract class ShapeItem
{
    /** @var string|null */
    private $key;
    /** @var Type */
    private $value;
    /** @var bool */
    private $optional;

    public function __construct(?string $key, ?Type $value, bool $optional)
    {
        $this->key = $key;
        $this->value = $value ?? new Mixed_();
        $this->optional = $optional;
    }

    public function getKey(): ?string
    {
        return $this->key;
    }

    public function getValue(): Type
    {
        return $this->value;
    }

    public function isOptional(): bool
    {
        return $this->optional;
    }

    public function __toString(): string
    {
        if ($this->key !== null) {
            return sprintf(
                '%s%s: %s',
                $this->key,
                $this->optional ? '?' : '',
                (string) $this->value
            );
        }

        return (string) $this->value;
    }
}
<?php
/*
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 *
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

use function sprintf;

/** @psalm-immutable */
class StringValue implements PseudoType
{
    /** @var string */
    private $value;

    public function __construct(string $value)
    {
        $this->value = $value;
    }

    public function getValue(): string
    {
        return $this->value;
    }

    public function underlyingType(): Type
    {
        return new String_();
    }

    public function __toString(): string
    {
        return sprintf('"%s"', $this->value);
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\String_;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class TraitString extends String_ implements PseudoType
{
    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'trait-string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link https://phpdoc.org
 */

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Boolean;

use function class_alias;

/**
 * Value Object representing the PseudoType 'False', which is a Boolean type.
 *
 * @psalm-immutable
 */
final class True_ extends Boolean implements PseudoType
{
    public function underlyingType(): Type
    {
        return new Boolean();
    }

    public function __toString(): string
    {
        return 'true';
    }
}

class_alias(True_::class, 'phpDocumentor\Reflection\Types\True_', false);
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

/**
 * @psalm-immutable
 */
interface Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string;
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection;

use Doctrine\Deprecations\Deprecation;
use InvalidArgumentException;
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
use phpDocumentor\Reflection\PseudoTypes\CallableString;
use phpDocumentor\Reflection\PseudoTypes\ConstExpression;
use phpDocumentor\Reflection\PseudoTypes\False_;
use phpDocumentor\Reflection\PseudoTypes\FloatValue;
use phpDocumentor\Reflection\PseudoTypes\HtmlEscapedString;
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
use phpDocumentor\Reflection\PseudoTypes\List_;
use phpDocumentor\Reflection\PseudoTypes\ListShape;
use phpDocumentor\Reflection\PseudoTypes\ListShapeItem;
use phpDocumentor\Reflection\PseudoTypes\LiteralString;
use phpDocumentor\Reflection\PseudoTypes\LowercaseString;
use phpDocumentor\Reflection\PseudoTypes\NegativeInteger;
use phpDocumentor\Reflection\PseudoTypes\NonEmptyArray;
use phpDocumentor\Reflection\PseudoTypes\NonEmptyList;
use phpDocumentor\Reflection\PseudoTypes\NonEmptyLowercaseString;
use phpDocumentor\Reflection\PseudoTypes\NonEmptyString;
use phpDocumentor\Reflection\PseudoTypes\Numeric_;
use phpDocumentor\Reflection\PseudoTypes\NumericString;
use phpDocumentor\Reflection\PseudoTypes\ObjectShape;
use phpDocumentor\Reflection\PseudoTypes\ObjectShapeItem;
use phpDocumentor\Reflection\PseudoTypes\PositiveInteger;
use phpDocumentor\Reflection\PseudoTypes\StringValue;
use phpDocumentor\Reflection\PseudoTypes\TraitString;
use phpDocumentor\Reflection\PseudoTypes\True_;
use phpDocumentor\Reflection\Types\AggregatedType;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\Boolean;
use phpDocumentor\Reflection\Types\Callable_;
use phpDocumentor\Reflection\Types\CallableParameter;
use phpDocumentor\Reflection\Types\ClassString;
use phpDocumentor\Reflection\Types\Collection;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Expression;
use phpDocumentor\Reflection\Types\Float_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Iterable_;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Never_;
use phpDocumentor\Reflection\Types\Null_;
use phpDocumentor\Reflection\Types\Nullable;
use phpDocumentor\Reflection\Types\Object_;
use phpDocumentor\Reflection\Types\Parent_;
use phpDocumentor\Reflection\Types\Resource_;
use phpDocumentor\Reflection\Types\Scalar;
use phpDocumentor\Reflection\Types\Self_;
use phpDocumentor\Reflection\Types\Static_;
use phpDocumentor\Reflection\Types\String_;
use phpDocumentor\Reflection\Types\This;
use phpDocumentor\Reflection\Types\Void_;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\ParserException;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\PhpDocParser\ParserConfig;
use RuntimeException;

use function array_filter;
use function array_key_exists;
use function array_map;
use function array_reverse;
use function class_exists;
use function class_implements;
use function get_class;
use function in_array;
use function sprintf;
use function strpos;
use function strtolower;
use function trim;

final class TypeResolver
{
    /** @var string Definition of the NAMESPACE operator in PHP */
    private const OPERATOR_NAMESPACE = '\\';

    /**
     * @var array<string, string> List of recognized keywords and unto which Value Object they map
     * @psalm-var array<string, class-string<Type>>
     */
    private $keywords = [
        'string' => String_::class,
        'class-string' => ClassString::class,
        'interface-string' => InterfaceString::class,
        'html-escaped-string' => HtmlEscapedString::class,
        'lowercase-string' => LowercaseString::class,
        'non-empty-lowercase-string' => NonEmptyLowercaseString::class,
        'non-empty-string' => NonEmptyString::class,
        'numeric-string' => NumericString::class,
        'numeric' => Numeric_::class,
        'trait-string' => TraitString::class,
        'int' => Integer::class,
        'integer' => Integer::class,
        'positive-int' => PositiveInteger::class,
        'negative-int' => NegativeInteger::class,
        'bool' => Boolean::class,
        'boolean' => Boolean::class,
        'real' => Float_::class,
        'float' => Float_::class,
        'double' => Float_::class,
        'object' => Object_::class,
        'mixed' => Mixed_::class,
        'array' => Array_::class,
        'array-key' => ArrayKey::class,
        'non-empty-array' => NonEmptyArray::class,
        'resource' => Resource_::class,
        'void' => Void_::class,
        'null' => Null_::class,
        'scalar' => Scalar::class,
        'callback' => Callable_::class,
        'callable' => Callable_::class,
        'callable-string' => CallableString::class,
        'false' => False_::class,
        'true' => True_::class,
        'literal-string' => LiteralString::class,
        'self' => Self_::class,
        '$this' => This::class,
        'static' => Static_::class,
        'parent' => Parent_::class,
        'iterable' => Iterable_::class,
        'never' => Never_::class,
        'list' => List_::class,
        'non-empty-list' => NonEmptyList::class,
    ];

    /**
     * @psalm-readonly
     * @var FqsenResolver
     */
    private $fqsenResolver;
    /**
     * @psalm-readonly
     * @var TypeParser
     */
    private $typeParser;
    /**
     * @psalm-readonly
     * @var Lexer
     */
    private $lexer;

    /**
     * Initializes this TypeResolver with the means to create and resolve Fqsen objects.
     */
    public function __construct(?FqsenResolver $fqsenResolver = null)
    {
        $this->fqsenResolver = $fqsenResolver ?: new FqsenResolver();

        if (class_exists(ParserConfig::class)) {
            $this->typeParser = new TypeParser(new ParserConfig([]), new ConstExprParser(new ParserConfig([])));
            $this->lexer = new Lexer(new ParserConfig([]));
        } else {
            $this->typeParser = new TypeParser(new ConstExprParser());
            $this->lexer = new Lexer();
        }
    }

    /**
     * Analyzes the given type and returns the FQCN variant.
     *
     * When a type is provided this method checks whether it is not a keyword or
     * Fully Qualified Class Name. If so it will use the given namespace and
     * aliases to expand the type to a FQCN representation.
     *
     * This method only works as expected if the namespace and aliases are set;
     * no dynamic reflection is being performed here.
     *
     * @uses Context::getNamespace()        to determine with what to prefix the type name.
     * @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be
     * replaced with another namespace.
     *
     * @param string $type The relative or absolute type.
     */
    public function resolve(string $type, ?Context $context = null): Type
    {
        $type = trim($type);
        if (!$type) {
            throw new InvalidArgumentException('Attempted to resolve "' . $type . '" but it appears to be empty');
        }

        if ($context === null) {
            $context = new Context('');
        }

        $tokens = $this->lexer->tokenize($type);
        $tokenIterator = new TokenIterator($tokens);

        $ast = $this->parse($tokenIterator);
        $type = $this->createType($ast, $context);

        return $this->tryParseRemainingCompoundTypes($tokenIterator, $context, $type);
    }

    public function createType(?TypeNode $type, Context $context): Type
    {
        if ($type === null) {
            return new Mixed_();
        }

        switch (get_class($type)) {
            case ArrayTypeNode::class:
                return new Array_(
                    $this->createType($type->type, $context)
                );

            case ArrayShapeNode::class:
                switch ($type->kind) {
                    case ArrayShapeNode::KIND_ARRAY:
                        return new ArrayShape(
                            ...array_map(
                                function (ArrayShapeItemNode $item) use ($context): ArrayShapeItem {
                                    return new ArrayShapeItem(
                                        (string) $item->keyName,
                                        $this->createType($item->valueType, $context),
                                        $item->optional
                                    );
                                },
                                $type->items
                            )
                        );

                    case ArrayShapeNode::KIND_LIST:
                        return new ListShape(
                            ...array_map(
                                function (ArrayShapeItemNode $item) use ($context): ListShapeItem {
                                    return new ListShapeItem(
                                        null,
                                        $this->createType($item->valueType, $context),
                                        $item->optional
                                    );
                                },
                                $type->items
                            )
                        );

                    default:
                        throw new RuntimeException('Unsupported array shape kind');
                }
            case ObjectShapeNode::class:
                return new ObjectShape(
                    ...array_map(
                        function (ObjectShapeItemNode $item) use ($context): ObjectShapeItem {
                            return new ObjectShapeItem(
                                (string) $item->keyName,
                                $this->createType($item->valueType, $context),
                                $item->optional
                            );
                        },
                        $type->items
                    )
                );

            case CallableTypeNode::class:
                return $this->createFromCallable($type, $context);

            case ConstTypeNode::class:
                return $this->createFromConst($type, $context);

            case GenericTypeNode::class:
                return $this->createFromGeneric($type, $context);

            case IdentifierTypeNode::class:
                return $this->resolveSingleType($type->name, $context);

            case IntersectionTypeNode::class:
                return new Intersection(
                    array_filter(
                        array_map(
                            function (TypeNode $nestedType) use ($context): Type {
                                $type = $this->createType($nestedType, $context);
                                if ($type instanceof AggregatedType) {
                                    return new Expression($type);
                                }

                                return $type;
                            },
                            $type->types
                        )
                    )
                );

            case NullableTypeNode::class:
                $nestedType = $this->createType($type->type, $context);

                return new Nullable($nestedType);

            case UnionTypeNode::class:
                return new Compound(
                    array_filter(
                        array_map(
                            function (TypeNode $nestedType) use ($context): Type {
                                $type = $this->createType($nestedType, $context);
                                if ($type instanceof AggregatedType) {
                                    return new Expression($type);
                                }

                                return $type;
                            },
                            $type->types
                        )
                    )
                );

            case ThisTypeNode::class:
                return new This();

            case ConditionalTypeNode::class:
            case ConditionalTypeForParameterNode::class:
            case OffsetAccessTypeNode::class:
            default:
                return new Mixed_();
        }
    }

    private function createFromGeneric(GenericTypeNode $type, Context $context): Type
    {
        switch (strtolower($type->type->name)) {
            case 'array':
                return $this->createArray($type->genericTypes, $context);

            case 'class-string':
                $subType = $this->createType($type->genericTypes[0], $context);
                if (!$subType instanceof Object_ || $subType->getFqsen() === null) {
                    throw new RuntimeException(
                        $subType . ' is not a class string'
                    );
                }

                return new ClassString(
                    $subType->getFqsen()
                );

            case 'interface-string':
                $subType = $this->createType($type->genericTypes[0], $context);
                if (!$subType instanceof Object_ || $subType->getFqsen() === null) {
                    throw new RuntimeException(
                        $subType . ' is not a class string'
                    );
                }

                return new InterfaceString(
                    $subType->getFqsen()
                );

            case 'list':
                return new List_(
                    $this->createType($type->genericTypes[0], $context)
                );

            case 'non-empty-list':
                return new NonEmptyList(
                    $this->createType($type->genericTypes[0], $context)
                );

            case 'int':
                if (isset($type->genericTypes[1]) === false) {
                    throw new RuntimeException('int<min,max> has not the correct format');
                }

                return new IntegerRange((string) $type->genericTypes[0], (string) $type->genericTypes[1]);

            case 'iterable':
                return new Iterable_(
                    ...array_reverse(
                        array_map(
                            function (TypeNode $genericType) use ($context): Type {
                                return $this->createType($genericType, $context);
                            },
                            $type->genericTypes
                        )
                    )
                );

            default:
                $collectionType = $this->createType($type->type, $context);
                if ($collectionType instanceof Object_ === false) {
                    throw new RuntimeException(sprintf('%s is not a collection', (string) $collectionType));
                }

                return new Collection(
                    $collectionType->getFqsen(),
                    ...array_reverse(
                        array_map(
                            function (TypeNode $genericType) use ($context): Type {
                                return $this->createType($genericType, $context);
                            },
                            $type->genericTypes
                        )
                    )
                );
        }
    }

    private function createFromCallable(CallableTypeNode $type, Context $context): Callable_
    {
        return new Callable_(array_map(
            function (CallableTypeParameterNode $param) use ($context): CallableParameter {
                return new CallableParameter(
                    $this->createType($param->type, $context),
                    $param->parameterName !== '' ? trim($param->parameterName, '$') : null,
                    $param->isReference,
                    $param->isVariadic,
                    $param->isOptional
                );
            },
            $type->parameters
        ), $this->createType($type->returnType, $context));
    }

    private function createFromConst(ConstTypeNode $type, Context $context): Type
    {
        switch (true) {
            case $type->constExpr instanceof ConstExprIntegerNode:
                return new IntegerValue((int) $type->constExpr->value);

            case $type->constExpr instanceof ConstExprFloatNode:
                return new FloatValue((float) $type->constExpr->value);

            case $type->constExpr instanceof ConstExprStringNode:
                return new StringValue($type->constExpr->value);

            case $type->constExpr instanceof ConstFetchNode:
                return new ConstExpression(
                    $this->resolve($type->constExpr->className, $context),
                    $type->constExpr->name
                );

            default:
                throw new RuntimeException(sprintf('Unsupported constant type %s', get_class($type)));
        }
    }

    /**
     * resolve the given type into a type object
     *
     * @param string $type the type string, representing a single type
     *
     * @return Type|Array_|Object_
     *
     * @psalm-mutation-free
     */
    private function resolveSingleType(string $type, Context $context): object
    {
        switch (true) {
            case $this->isKeyword($type):
                return $this->resolveKeyword($type);

            case $this->isFqsen($type):
                return $this->resolveTypedObject($type);

            case $this->isPartialStructuralElementName($type):
                return $this->resolveTypedObject($type, $context);

            // @codeCoverageIgnoreStart
            default:
                // I haven't got the foggiest how the logic would come here but added this as a defense.
                throw new RuntimeException(
                    'Unable to resolve type "' . $type . '", there is no known method to resolve it'
                );
        }

        // @codeCoverageIgnoreEnd
    }

    /**
     * Adds a keyword to the list of Keywords and associates it with a specific Value Object.
     *
     * @psalm-param class-string<Type> $typeClassName
     */
    public function addKeyword(string $keyword, string $typeClassName): void
    {
        if (!class_exists($typeClassName)) {
            throw new InvalidArgumentException(
                'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
                . ' but we could not find the class ' . $typeClassName
            );
        }

        $interfaces = class_implements($typeClassName);
        if ($interfaces === false) {
            throw new InvalidArgumentException(
                'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
                . ' but we could not find the class ' . $typeClassName
            );
        }

        if (!in_array(Type::class, $interfaces, true)) {
            throw new InvalidArgumentException(
                'The class "' . $typeClassName . '" must implement the interface "phpDocumentor\Reflection\Type"'
            );
        }

        $this->keywords[$keyword] = $typeClassName;
    }

    /**
     * Detects whether the given type represents a PHPDoc keyword.
     *
     * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
     *
     * @psalm-mutation-free
     */
    private function isKeyword(string $type): bool
    {
        return array_key_exists(strtolower($type), $this->keywords);
    }

    /**
     * Detects whether the given type represents a relative structural element name.
     *
     * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
     *
     * @psalm-mutation-free
     */
    private function isPartialStructuralElementName(string $type): bool
    {
        return (isset($type[0]) && $type[0] !== self::OPERATOR_NAMESPACE) && !$this->isKeyword($type);
    }

    /**
     * Tests whether the given type is a Fully Qualified Structural Element Name.
     *
     * @psalm-mutation-free
     */
    private function isFqsen(string $type): bool
    {
        return strpos($type, self::OPERATOR_NAMESPACE) === 0;
    }

    /**
     * Resolves the given keyword (such as `string`) into a Type object representing that keyword.
     *
     * @psalm-mutation-free
     */
    private function resolveKeyword(string $type): Type
    {
        $className = $this->keywords[strtolower($type)];

        return new $className();
    }

    /**
     * Resolves the given FQSEN string into an FQSEN object.
     *
     * @psalm-mutation-free
     */
    private function resolveTypedObject(string $type, ?Context $context = null): Object_
    {
        return new Object_($this->fqsenResolver->resolve($type, $context));
    }

    /** @param TypeNode[] $typeNodes */
    private function createArray(array $typeNodes, Context $context): Array_
    {
        $types = array_reverse(
            array_map(
                function (TypeNode $node) use ($context): Type {
                    return $this->createType($node, $context);
                },
                $typeNodes
            )
        );

        if (isset($types[1]) === false) {
            return new Array_(...$types);
        }

        if ($this->validArrayKeyType($types[1]) || $types[1] instanceof ArrayKey) {
            return new Array_(...$types);
        }

        if ($types[1] instanceof Compound && $types[1]->getIterator()->count() === 2) {
            if ($this->validArrayKeyType($types[1]->get(0)) && $this->validArrayKeyType($types[1]->get(1))) {
                return new Array_(...$types);
            }
        }

        throw new RuntimeException('An array can have only integers or strings as keys');
    }

    private function validArrayKeyType(?Type $type): bool
    {
        return $type instanceof String_ || $type instanceof Integer;
    }

    private function parse(TokenIterator $tokenIterator): TypeNode
    {
        try {
            $ast = $this->typeParser->parse($tokenIterator);
        } catch (ParserException $e) {
            throw new RuntimeException($e->getMessage(), 0, $e);
        }

        return $ast;
    }

    /**
     * Will try to parse unsupported type notations by phpstan
     *
     * The phpstan parser doesn't support the illegal nullable combinations like this library does.
     * This method will warn the user about those notations but for bc purposes we will still have it here.
     */
    private function tryParseRemainingCompoundTypes(TokenIterator $tokenIterator, Context $context, Type $type): Type
    {
        if (
            $tokenIterator->isCurrentTokenType(Lexer::TOKEN_UNION) ||
            $tokenIterator->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)
        ) {
            Deprecation::trigger(
                'phpdocumentor/type-resolver',
                'https://github.com/phpDocumentor/TypeResolver/issues/184',
                'Legacy nullable type detected, please update your code as
                you are using nullable types in a docblock. support will be removed in v2.0.0'
            );
        }

        $continue = true;
        while ($continue) {
            $continue = false;
            while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
                $ast = $this->parse($tokenIterator);
                $type2 = $this->createType($ast, $context);
                $type = new Compound([$type, $type2]);
                $continue = true;
            }

            while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
                $ast = $this->typeParser->parse($tokenIterator);
                $type2 = $this->createType($ast, $context);
                $type = new Intersection([$type, $type2]);
                $continue = true;
            }
        }

        return $type;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Represents a list of values. This is an abstract class for Array_ and Collection.
 *
 * @psalm-immutable
 */
abstract class AbstractList implements Type
{
    /** @var Type */
    protected $valueType;

    /** @var Type|null */
    protected $keyType;

    /** @var Type */
    protected $defaultKeyType;

    /**
     * Initializes this representation of an array with the given Type.
     */
    public function __construct(?Type $valueType = null, ?Type $keyType = null)
    {
        if ($valueType === null) {
            $valueType = new Mixed_();
        }

        $this->valueType      = $valueType;
        $this->defaultKeyType = new Compound([new String_(), new Integer()]);
        $this->keyType        = $keyType;
    }

    /**
     * Returns the type for the keys of this array.
     */
    public function getKeyType(): Type
    {
        return $this->keyType ?? $this->defaultKeyType;
    }

    /**
     * Returns the type for the values of this array.
     */
    public function getValueType(): Type
    {
        return $this->valueType;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->keyType) {
            return 'array<' . $this->keyType . ',' . $this->valueType . '>';
        }

        if ($this->valueType instanceof Mixed_) {
            return 'array';
        }

        if ($this->valueType instanceof Compound) {
            return '(' . $this->valueType . ')[]';
        }

        return $this->valueType . '[]';
    }
}
<?php
/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use ArrayIterator;
use IteratorAggregate;
use phpDocumentor\Reflection\Type;

use function array_key_exists;
use function implode;

/**
 * Base class for aggregated types like Compound and Intersection
 *
 * A Aggregated Type is not so much a special keyword or object reference but is a series of Types that are separated
 * using separator.
 *
 * @psalm-immutable
 * @template-implements IteratorAggregate<int, Type>
 */
abstract class AggregatedType implements Type, IteratorAggregate
{
    /**
     * @psalm-allow-private-mutation
     * @var array<int, Type>
     */
    private $types = [];

    /** @var string */
    private $token;

    /**
     * @param array<Type> $types
     */
    public function __construct(array $types, string $token)
    {
        foreach ($types as $type) {
            $this->add($type);
        }

        $this->token = $token;
    }

    /**
     * Returns the type at the given index.
     */
    public function get(int $index): ?Type
    {
        if (!$this->has($index)) {
            return null;
        }

        return $this->types[$index];
    }

    /**
     * Tests if this compound type has a type with the given index.
     */
    public function has(int $index): bool
    {
        return array_key_exists($index, $this->types);
    }

    /**
     * Tests if this compound type contains the given type.
     */
    public function contains(Type $type): bool
    {
        foreach ($this->types as $typePart) {
            // if the type is duplicate; do not add it
            if ((string) $typePart === (string) $type) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return implode($this->token, $this->types);
    }

    /**
     * @return ArrayIterator<int, Type>
     */
    public function getIterator(): ArrayIterator
    {
        return new ArrayIterator($this->types);
    }

    /**
     * @psalm-suppress ImpureMethodCall
     */
    private function add(Type $type): void
    {
        if ($type instanceof static) {
            foreach ($type->getIterator() as $subType) {
                $this->add($subType);
            }

            return;
        }

        // if the type is duplicate; do not add it
        if ($this->contains($type)) {
            return;
        }

        $this->types[] = $type;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a array-key Type.
 *
 * A array-key Type is the supertype (but not a union) of int and string.
 *
 * @psalm-immutable
 */
final class ArrayKey extends AggregatedType implements PseudoType
{
    public function __construct()
    {
        parent::__construct([new String_(), new Integer()], '|');
    }

    public function underlyingType(): Type
    {
        return new Compound([new String_(), new Integer()]);
    }

    public function __toString(): string
    {
        return 'array-key';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

/**
 * Represents an array type as described in the PSR-5, the PHPDoc Standard.
 *
 * An array can be represented in two forms:
 *
 * 1. Untyped (`array`), where the key and value type is unknown and hence classified as 'Mixed_'.
 * 2. Types (`string[]`), where the value type is provided by preceding an opening and closing square bracket with a
 *    type name.
 *
 * @psalm-immutable
 */
class Array_ extends AbstractList
{
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Boolean type.
 *
 * @psalm-immutable
 */
class Boolean implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'bool';
    }
}
<?php
/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Callable parameters.
 *
 * @psalm-immutable
 */
final class CallableParameter
{
    /** @var Type */
    private $type;

    /** @var bool */
    private $isReference;

    /** @var bool */
    private $isVariadic;

    /** @var bool */
    private $isOptional;

    /** @var string|null */
    private $name;

    public function __construct(
        Type $type,
        ?string $name = null,
        bool $isReference = false,
        bool $isVariadic = false,
        bool $isOptional = false
    ) {
        $this->type = $type;
        $this->isReference = $isReference;
        $this->isVariadic = $isVariadic;
        $this->isOptional = $isOptional;
        $this->name = $name;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function getType(): Type
    {
        return $this->type;
    }

    public function isReference(): bool
    {
        return $this->isReference;
    }

    public function isVariadic(): bool
    {
        return $this->isVariadic;
    }

    public function isOptional(): bool
    {
        return $this->isOptional;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Callable type.
 *
 * @psalm-immutable
 */
final class Callable_ implements Type
{
    /** @var Type|null */
    private $returnType;
    /** @var CallableParameter[] */
    private $parameters;

    /**
     * @param CallableParameter[] $parameters
     */
    public function __construct(array $parameters = [], ?Type $returnType = null)
    {
        $this->parameters = $parameters;
        $this->returnType = $returnType;
    }

    /** @return CallableParameter[] */
    public function getParameters(): array
    {
        return $this->parameters;
    }

    public function getReturnType(): ?Type
    {
        return $this->returnType;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'callable';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class ClassString extends String_ implements PseudoType
{
    /** @var Fqsen|null */
    private $fqsen;

    /**
     * Initializes this representation of a class string with the given Fqsen.
     */
    public function __construct(?Fqsen $fqsen = null)
    {
        $this->fqsen = $fqsen;
    }

    public function underlyingType(): Type
    {
        return new String_();
    }

    /**
     * Returns the FQSEN associated with this object.
     */
    public function getFqsen(): ?Fqsen
    {
        return $this->fqsen;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->fqsen === null) {
            return 'class-string';
        }

        return 'class-string<' . (string) $this->fqsen . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;

/**
 * Represents a collection type as described in the PSR-5, the PHPDoc Standard.
 *
 * A collection can be represented in two forms:
 *
 * 1. `ACollectionObject<aValueType>`
 * 2. `ACollectionObject<aValueType,aKeyType>`
 *
 * - ACollectionObject can be 'array' or an object that can act as an array
 * - aValueType and aKeyType can be any type expression
 *
 * @psalm-immutable
 */
final class Collection extends AbstractList
{
    /** @var Fqsen|null */
    private $fqsen;

    /**
     * Initializes this representation of an array with the given Type or Fqsen.
     */
    public function __construct(?Fqsen $fqsen, Type $valueType, ?Type $keyType = null)
    {
        parent::__construct($valueType, $keyType);

        $this->fqsen = $fqsen;
    }

    /**
     * Returns the FQSEN associated with this object.
     */
    public function getFqsen(): ?Fqsen
    {
        return $this->fqsen;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        $objectType = (string) ($this->fqsen ?? 'object');

        if ($this->keyType === null) {
            return $objectType . '<' . $this->valueType . '>';
        }

        return $objectType . '<' . $this->keyType . ',' . $this->valueType . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Compound Type.
 *
 * A Compound Type is not so much a special keyword or object reference but is a series of Types that are separated
 * using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
 * may contain a value with any of the given types.
 *
 * @psalm-immutable
 */
final class Compound extends AggregatedType
{
    /**
     * Initializes a compound type (i.e. `string|int`) and tests if the provided types all implement the Type interface.
     *
     * @param array<Type> $types
     */
    public function __construct(array $types)
    {
        parent::__construct($types, '|');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use function strlen;
use function substr;
use function trim;

/**
 * Provides information about the Context in which the DocBlock occurs that receives this context.
 *
 * A DocBlock does not know of its own accord in which namespace it occurs and which namespace aliases are applicable
 * for the block of code in which it is in. This information is however necessary to resolve Class names in tags since
 * you can provide a short form or make use of namespace aliases.
 *
 * The phpDocumentor Reflection component knows how to create this class but if you use the DocBlock parser from your
 * own application it is possible to generate a Context class using the ContextFactory; this will analyze the file in
 * which an associated class resides for its namespace and imports.
 *
 * @see ContextFactory::createFromClassReflector()
 * @see ContextFactory::createForNamespace()
 *
 * @psalm-immutable
 */
final class Context
{
    /** @var string The current namespace. */
    private $namespace;

    /**
     * @var string[] List of namespace aliases => Fully Qualified Namespace.
     * @psalm-var array<string, string>
     */
    private $namespaceAliases;

    /**
     * Initializes the new context and normalizes all passed namespaces to be in Qualified Namespace Name (QNN)
     * format (without a preceding `\`).
     *
     * @param string   $namespace        The namespace where this DocBlock resides in.
     * @param string[] $namespaceAliases List of namespace aliases => Fully Qualified Namespace.
     * @psalm-param array<string, string> $namespaceAliases
     */
    public function __construct(string $namespace, array $namespaceAliases = [])
    {
        $this->namespace = $namespace !== 'global' && $namespace !== 'default'
            ? trim($namespace, '\\')
            : '';

        foreach ($namespaceAliases as $alias => $fqnn) {
            if ($fqnn[0] === '\\') {
                $fqnn = substr($fqnn, 1);
            }

            if ($fqnn[strlen($fqnn) - 1] === '\\') {
                $fqnn = substr($fqnn, 0, -1);
            }

            $namespaceAliases[$alias] = $fqnn;
        }

        $this->namespaceAliases = $namespaceAliases;
    }

    /**
     * Returns the Qualified Namespace Name (thus without `\` in front) where the associated element is in.
     */
    public function getNamespace(): string
    {
        return $this->namespace;
    }

    /**
     * Returns a list of Qualified Namespace Names (thus without `\` in front) that are imported, the keys represent
     * the alias for the imported Namespace.
     *
     * @return string[]
     * @psalm-return array<string, string>
     */
    public function getNamespaceAliases(): array
    {
        return $this->namespaceAliases;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use ArrayIterator;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionClassConstant;
use ReflectionMethod;
use ReflectionParameter;
use ReflectionProperty;
use Reflector;
use RuntimeException;
use UnexpectedValueException;

use function define;
use function defined;
use function file_exists;
use function file_get_contents;
use function get_class;
use function in_array;
use function is_string;
use function strrpos;
use function substr;
use function token_get_all;
use function trim;

use const T_AS;
use const T_CLASS;
use const T_CURLY_OPEN;
use const T_DOLLAR_OPEN_CURLY_BRACES;
use const T_NAME_FULLY_QUALIFIED;
use const T_NAME_QUALIFIED;
use const T_NAMESPACE;
use const T_NS_SEPARATOR;
use const T_STRING;
use const T_TRAIT;
use const T_USE;

if (!defined('T_NAME_QUALIFIED')) {
    define('T_NAME_QUALIFIED', 10001);
}

if (!defined('T_NAME_FULLY_QUALIFIED')) {
    define('T_NAME_FULLY_QUALIFIED', 10002);
}

/**
 * Convenience class to create a Context for DocBlocks when not using the Reflection Component of phpDocumentor.
 *
 * For a DocBlock to be able to resolve types that use partial namespace names or rely on namespace imports we need to
 * provide a bit of context so that the DocBlock can read that and based on it decide how to resolve the types to
 * Fully Qualified names.
 *
 * @see Context for more information.
 */
final class ContextFactory
{
    /** The literal used at the end of a use statement. */
    private const T_LITERAL_END_OF_USE = ';';

    /** The literal used between sets of use statements */
    private const T_LITERAL_USE_SEPARATOR = ',';

    /**
     * Build a Context given a Class Reflection.
     *
     * @see Context for more information on Contexts.
     */
    public function createFromReflector(Reflector $reflector): Context
    {
        if ($reflector instanceof ReflectionClass) {
            //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
            /** @var ReflectionClass<object> $reflector */

            return $this->createFromReflectionClass($reflector);
        }

        if ($reflector instanceof ReflectionParameter) {
            return $this->createFromReflectionParameter($reflector);
        }

        if ($reflector instanceof ReflectionMethod) {
            return $this->createFromReflectionMethod($reflector);
        }

        if ($reflector instanceof ReflectionProperty) {
            return $this->createFromReflectionProperty($reflector);
        }

        if ($reflector instanceof ReflectionClassConstant) {
            return $this->createFromReflectionClassConstant($reflector);
        }

        throw new UnexpectedValueException('Unhandled \Reflector instance given:  ' . get_class($reflector));
    }

    private function createFromReflectionParameter(ReflectionParameter $parameter): Context
    {
        $class = $parameter->getDeclaringClass();
        if (!$class) {
            throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName());
        }

        return $this->createFromReflectionClass($class);
    }

    private function createFromReflectionMethod(ReflectionMethod $method): Context
    {
        $class = $method->getDeclaringClass();

        return $this->createFromReflectionClass($class);
    }

    private function createFromReflectionProperty(ReflectionProperty $property): Context
    {
        $class = $property->getDeclaringClass();

        return $this->createFromReflectionClass($class);
    }

    private function createFromReflectionClassConstant(ReflectionClassConstant $constant): Context
    {
        //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
        /** @phpstan-var ReflectionClass<object> $class */
        $class = $constant->getDeclaringClass();

        return $this->createFromReflectionClass($class);
    }

    /**
     * @phpstan-param ReflectionClass<object> $class
     */
    private function createFromReflectionClass(ReflectionClass $class): Context
    {
        $fileName  = $class->getFileName();
        $namespace = $class->getNamespaceName();

        if (is_string($fileName) && file_exists($fileName)) {
            $contents = file_get_contents($fileName);
            if ($contents === false) {
                throw new RuntimeException('Unable to read file "' . $fileName . '"');
            }

            return $this->createForNamespace($namespace, $contents);
        }

        return new Context($namespace, []);
    }

    /**
     * Build a Context for a namespace in the provided file contents.
     *
     * @see Context for more information on Contexts.
     *
     * @param string $namespace    It does not matter if a `\` precedes the namespace name,
     * this method first normalizes.
     * @param string $fileContents The file's contents to retrieve the aliases from with the given namespace.
     */
    public function createForNamespace(string $namespace, string $fileContents): Context
    {
        $namespace        = trim($namespace, '\\');
        $useStatements    = [];
        $currentNamespace = '';
        $tokens           = new ArrayIterator(token_get_all($fileContents));

        while ($tokens->valid()) {
            $currentToken = $tokens->current();
            switch ($currentToken[0]) {
                case T_NAMESPACE:
                    $currentNamespace = $this->parseNamespace($tokens);
                    break;
                case T_CLASS:
                case T_TRAIT:
                    // Fast-forward the iterator through the class so that any
                    // T_USE tokens found within are skipped - these are not
                    // valid namespace use statements so should be ignored.
                    $braceLevel      = 0;
                    $firstBraceFound = false;
                    while ($tokens->valid() && ($braceLevel > 0 || !$firstBraceFound)) {
                        $currentToken = $tokens->current();
                        if (
                            $currentToken === '{'
                            || in_array($currentToken[0], [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES], true)
                        ) {
                            if (!$firstBraceFound) {
                                $firstBraceFound = true;
                            }

                            ++$braceLevel;
                        }

                        if ($currentToken === '}') {
                            --$braceLevel;
                        }

                        $tokens->next();
                    }

                    break;
                case T_USE:
                    if ($currentNamespace === $namespace) {
                        $useStatements += $this->parseUseStatement($tokens);
                    }

                    break;
            }

            $tokens->next();
        }

        return new Context($namespace, $useStatements);
    }

    /**
     * Deduce the name from tokens when we are at the T_NAMESPACE token.
     *
     * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
     */
    private function parseNamespace(ArrayIterator $tokens): string
    {
        // skip to the first string or namespace separator
        $this->skipToNextStringOrNamespaceSeparator($tokens);

        $name = '';
        $acceptedTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED];
        while ($tokens->valid() && in_array($tokens->current()[0], $acceptedTokens, true)) {
            $name .= $tokens->current()[1];
            $tokens->next();
        }

        return $name;
    }

    /**
     * Deduce the names of all imports when we are at the T_USE token.
     *
     * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
     *
     * @return string[]
     * @psalm-return array<string, string>
     */
    private function parseUseStatement(ArrayIterator $tokens): array
    {
        $uses = [];

        while ($tokens->valid()) {
            $this->skipToNextStringOrNamespaceSeparator($tokens);

            $uses += $this->extractUseStatements($tokens);
            $currentToken = $tokens->current();
            if ($currentToken[0] === self::T_LITERAL_END_OF_USE) {
                return $uses;
            }
        }

        return $uses;
    }

    /**
     * Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token.
     *
     * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
     */
    private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens): void
    {
        while ($tokens->valid()) {
            $currentToken = $tokens->current();
            if (in_array($currentToken[0], [T_STRING, T_NS_SEPARATOR], true)) {
                break;
            }

            if ($currentToken[0] === T_NAME_QUALIFIED) {
                break;
            }

            if (defined('T_NAME_FULLY_QUALIFIED') && $currentToken[0] === T_NAME_FULLY_QUALIFIED) {
                break;
            }

            $tokens->next();
        }
    }

    /**
     * Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of
     * a USE statement yet. This will return a key/value array of the alias => namespace.
     *
     * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
     *
     * @return string[]
     * @psalm-return array<string, string>
     *
     * @psalm-suppress TypeDoesNotContainType
     */
    private function extractUseStatements(ArrayIterator $tokens): array
    {
        $extractedUseStatements = [];
        $groupedNs              = '';
        $currentNs              = '';
        $currentAlias           = '';
        $state                  = 'start';

        while ($tokens->valid()) {
            $currentToken = $tokens->current();
            $tokenId      = is_string($currentToken) ? $currentToken : $currentToken[0];
            $tokenValue   = is_string($currentToken) ? null : $currentToken[1];
            switch ($state) {
                case 'start':
                    switch ($tokenId) {
                        case T_STRING:
                        case T_NS_SEPARATOR:
                            $currentNs   .= (string) $tokenValue;
                            $currentAlias =  $tokenValue;
                            break;
                        case T_NAME_QUALIFIED:
                        case T_NAME_FULLY_QUALIFIED:
                            $currentNs   .= (string) $tokenValue;
                            $currentAlias = substr(
                                (string) $tokenValue,
                                (int) (strrpos((string) $tokenValue, '\\')) + 1
                            );
                            break;
                        case T_CURLY_OPEN:
                        case '{':
                            $state     = 'grouped';
                            $groupedNs = $currentNs;
                            break;
                        case T_AS:
                            $state = 'start-alias';
                            break;
                        case self::T_LITERAL_USE_SEPARATOR:
                        case self::T_LITERAL_END_OF_USE:
                            $state = 'end';
                            break;
                        default:
                            break;
                    }

                    break;
                case 'start-alias':
                    switch ($tokenId) {
                        case T_STRING:
                            $currentAlias = $tokenValue;
                            break;
                        case self::T_LITERAL_USE_SEPARATOR:
                        case self::T_LITERAL_END_OF_USE:
                            $state = 'end';
                            break;
                        default:
                            break;
                    }

                    break;
                case 'grouped':
                    switch ($tokenId) {
                        case T_STRING:
                        case T_NS_SEPARATOR:
                            $currentNs   .= (string) $tokenValue;
                            $currentAlias = $tokenValue;
                            break;
                        case T_AS:
                            $state = 'grouped-alias';
                            break;
                        case self::T_LITERAL_USE_SEPARATOR:
                            $state                                          = 'grouped';
                            $extractedUseStatements[(string) $currentAlias] = $currentNs;
                            $currentNs                                      = $groupedNs;
                            $currentAlias                                   = '';
                            break;
                        case self::T_LITERAL_END_OF_USE:
                            $state = 'end';
                            break;
                        default:
                            break;
                    }

                    break;
                case 'grouped-alias':
                    switch ($tokenId) {
                        case T_STRING:
                            $currentAlias = $tokenValue;
                            break;
                        case self::T_LITERAL_USE_SEPARATOR:
                            $state                                          = 'grouped';
                            $extractedUseStatements[(string) $currentAlias] = $currentNs;
                            $currentNs                                      = $groupedNs;
                            $currentAlias                                   = '';
                            break;
                        case self::T_LITERAL_END_OF_USE:
                            $state = 'end';
                            break;
                        default:
                            break;
                    }
            }

            if ($state === 'end') {
                break;
            }

            $tokens->next();
        }

        if ($groupedNs !== $currentNs) {
            $extractedUseStatements[(string) $currentAlias] = $currentNs;
        }

        return $extractedUseStatements;
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Represents an expression type as described in the PSR-5, the PHPDoc Standard.
 *
 * @psalm-immutable
 */
final class Expression implements Type
{
    /** @var Type */
    protected $valueType;

    /**
     * Initializes this representation of an array with the given Type.
     */
    public function __construct(Type $valueType)
    {
        $this->valueType = $valueType;
    }

    /**
     * Returns the value for the keys of this array.
     */
    public function getValueType(): Type
    {
        return $this->valueType;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return '(' . $this->valueType . ')';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Float.
 *
 * @psalm-immutable
 */
class Float_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'float';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value object representing Integer type
 *
 * @psalm-immutable
 */
class Integer implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'int';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
final class InterfaceString implements Type
{
    /** @var Fqsen|null */
    private $fqsen;

    /**
     * Initializes this representation of a class string with the given Fqsen.
     */
    public function __construct(?Fqsen $fqsen = null)
    {
        $this->fqsen = $fqsen;
    }

    /**
     * Returns the FQSEN associated with this object.
     */
    public function getFqsen(): ?Fqsen
    {
        return $this->fqsen;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->fqsen === null) {
            return 'interface-string';
        }

        return 'interface-string<' . (string) $this->fqsen . '>';
    }
}
<?php
/**
 * This file is part of phpDocumentor.
 *
 *  For the full copyright and license information, please view the LICENSE
 *  file that was distributed with this source code.
 *
 *  @link      http://phpdoc.org
 */

declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a Compound Type.
 *
 * A Intersection Type is not so much a special keyword or object reference but is a series of Types that are separated
 * using an AND operator (`&`). This combination of types signifies that whatever is associated with this Intersection
 * type may contain a value with any of the given types.
 *
 * @psalm-immutable
 */
final class Intersection extends AggregatedType
{
    /**
     * Initializes a intersection type (i.e. `\A&\B`) and tests if the provided types all implement the Type interface.
     *
     * @param array<Type> $types
     */
    public function __construct(array $types)
    {
        parent::__construct($types, '&');
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

/**
 * Value Object representing iterable type
 *
 * @psalm-immutable
 */
final class Iterable_ extends AbstractList
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        if ($this->keyType) {
            return 'iterable<' . $this->keyType . ',' . $this->valueType . '>';
        }

        if ($this->valueType instanceof Mixed_) {
            return 'iterable';
        }

        return 'iterable<' . $this->valueType . '>';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing an unknown, or mixed, type.
 *
 * @psalm-immutable
 */
final class Mixed_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'mixed';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the return-type 'never'.
 *
 * Never is generally only used when working with return types as it signifies that the method that only
 * ever throw or exit.
 *
 * @psalm-immutable
 */
final class Never_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'never';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a nullable type. The real type is wrapped.
 *
 * @psalm-immutable
 */
final class Nullable implements Type
{
    /** @var Type The actual type that is wrapped */
    private $realType;

    /**
     * Initialises this nullable type using the real type embedded
     */
    public function __construct(Type $realType)
    {
        $this->realType = $realType;
    }

    /**
     * Provide access to the actual type directly, if needed.
     */
    public function getActualType(): Type
    {
        return $this->realType;
    }

    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return '?' . $this->realType->__toString();
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing a null value or type.
 *
 * @psalm-immutable
 */
final class Null_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'null';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use InvalidArgumentException;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Type;

use function strpos;

/**
 * Value Object representing an object.
 *
 * An object can be either typed or untyped. When an object is typed it means that it has an identifier, the FQSEN,
 * pointing to an element in PHP. Object types that are untyped do not refer to a specific class but represent objects
 * in general.
 *
 * @psalm-immutable
 */
final class Object_ implements Type
{
    /** @var Fqsen|null */
    private $fqsen;

    /**
     * Initializes this object with an optional FQSEN, if not provided this object is considered 'untyped'.
     *
     * @throws InvalidArgumentException When provided $fqsen is not a valid type.
     */
    public function __construct(?Fqsen $fqsen = null)
    {
        if (strpos((string) $fqsen, '::') !== false || strpos((string) $fqsen, '()') !== false) {
            throw new InvalidArgumentException(
                'Object types can only refer to a class, interface or trait but a method, function, constant or '
                . 'property was received: ' . (string) $fqsen
            );
        }

        $this->fqsen = $fqsen;
    }

    /**
     * Returns the FQSEN associated with this object.
     */
    public function getFqsen(): ?Fqsen
    {
        return $this->fqsen;
    }

    public function __toString(): string
    {
        if ($this->fqsen) {
            return (string) $this->fqsen;
        }

        return 'object';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the 'parent' type.
 *
 * Parent, as a Type, represents the parent class of class in which the associated element was defined.
 *
 * @psalm-immutable
 */
final class Parent_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'parent';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the 'resource' Type.
 *
 * @psalm-immutable
 */
final class Resource_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'resource';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the 'scalar' pseudo-type, which is either a string, integer, float or boolean.
 *
 * @psalm-immutable
 */
final class Scalar implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'scalar';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the 'self' type.
 *
 * Self, as a Type, represents the class in which the associated element was defined.
 *
 * @psalm-immutable
 */
final class Self_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'self';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the 'static' type.
 *
 * Self, as a Type, represents the class in which the associated element was called. This differs from self as self does
 * not take inheritance into account but static means that the return type is always that of the class of the called
 * element.
 *
 * See the documentation on late static binding in the PHP Documentation for more information on the difference between
 * static and self.
 *
 * @psalm-immutable
 */
final class Static_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'static';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the type 'string'.
 *
 * @psalm-immutable
 */
class String_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'string';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the '$this' pseudo-type.
 *
 * $this, as a Type, represents the instance of the class associated with the element as it was called. $this is
 * commonly used when documenting fluent interfaces since it represents that the same object is returned.
 *
 * @psalm-immutable
 */
final class This implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return '$this';
    }
}
<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link      http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Types;

use phpDocumentor\Reflection\Type;

/**
 * Value Object representing the return-type 'void'.
 *
 * Void is generally only used when working with return types as it signifies that the method intentionally does not
 * return any value.
 *
 * @psalm-immutable
 */
final class Void_ implements Type
{
    /**
     * Returns a rendered output of the Type as it would be used in a DocBlock.
     */
    public function __toString(): string
    {
        return 'void';
    }
}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 */
abstract class AbstractNodeVisitor implements NodeVisitor // phpcs:ignore SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix
{

	public function beforeTraverse(array $nodes): ?array
	{
		return null;
	}

	public function enterNode(Node $node)
	{
		return null;
	}

	public function leaveNode(Node $node)
	{
		return null;
	}

	public function afterTraverse(array $nodes): ?array
	{
		return null;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

final class Attribute
{

	public const START_LINE = 'startLine';
	public const END_LINE = 'endLine';

	public const START_INDEX = 'startIndex';
	public const END_INDEX = 'endIndex';

	public const ORIGINAL_NODE = 'originalNode';

	public const COMMENTS = 'comments';

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

use function trim;

class Comment
{

	public string $text;

	public int $startLine;

	public int $startIndex;

	public function __construct(string $text, int $startLine = -1, int $startIndex = -1)
	{
		$this->text = $text;
		$this->startLine = $startLine;
		$this->startIndex = $startIndex;
	}

	public function getReformattedText(): string
	{
		return trim($this->text);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ConstExprArrayItemNode implements ConstExprNode
{

	use NodeAttributes;

	public ?ConstExprNode $key = null;

	public ConstExprNode $value;

	public function __construct(?ConstExprNode $key, ConstExprNode $value)
	{
		$this->key = $key;
		$this->value = $value;
	}


	public function __toString(): string
	{
		if ($this->key !== null) {
			return sprintf('%s => %s', $this->key, $this->value);

		}

		return (string) $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;

class ConstExprArrayNode implements ConstExprNode
{

	use NodeAttributes;

	/** @var ConstExprArrayItemNode[] */
	public array $items;

	/**
	 * @param ConstExprArrayItemNode[] $items
	 */
	public function __construct(array $items)
	{
		$this->items = $items;
	}


	public function __toString(): string
	{
		return '[' . implode(', ', $this->items) . ']';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstExprFalseNode implements ConstExprNode
{

	use NodeAttributes;

	public function __toString(): string
	{
		return 'false';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstExprFloatNode implements ConstExprNode
{

	use NodeAttributes;

	public string $value;

	public function __construct(string $value)
	{
		$this->value = $value;
	}


	public function __toString(): string
	{
		return $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstExprIntegerNode implements ConstExprNode
{

	use NodeAttributes;

	public string $value;

	public function __construct(string $value)
	{
		$this->value = $value;
	}


	public function __toString(): string
	{
		return $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\Node;

interface ConstExprNode extends Node
{

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstExprNullNode implements ConstExprNode
{

	use NodeAttributes;

	public function __toString(): string
	{
		return 'null';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function addcslashes;
use function assert;
use function dechex;
use function ord;
use function preg_replace_callback;
use function sprintf;
use function str_pad;
use function strlen;
use const STR_PAD_LEFT;

class ConstExprStringNode implements ConstExprNode
{

	public const SINGLE_QUOTED = 1;
	public const DOUBLE_QUOTED = 2;

	use NodeAttributes;

	public string $value;

	/** @var self::SINGLE_QUOTED|self::DOUBLE_QUOTED */
	public $quoteType;

	/**
	 * @param self::SINGLE_QUOTED|self::DOUBLE_QUOTED $quoteType
	 */
	public function __construct(string $value, int $quoteType)
	{
		$this->value = $value;
		$this->quoteType = $quoteType;
	}


	public function __toString(): string
	{
		if ($this->quoteType === self::SINGLE_QUOTED) {
			// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007
			return sprintf("'%s'", addcslashes($this->value, '\'\\'));
		}

		// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040
		return sprintf('"%s"', $this->escapeDoubleQuotedString());
	}

	private function escapeDoubleQuotedString(): string
	{
		$quote = '"';
		$escaped = addcslashes($this->value, "\n\r\t\f\v$" . $quote . '\\');

		// Escape control characters and non-UTF-8 characters.
		// Regex based on https://stackoverflow.com/a/11709412/385378.
		$regex = '/(
              [\x00-\x08\x0E-\x1F] # Control characters
            | [\xC0-\xC1] # Invalid UTF-8 Bytes
            | [\xF5-\xFF] # Invalid UTF-8 Bytes
            | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point
            | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point
            | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
            | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
            | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
            | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
            | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
            | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
            | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
            | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
        )/x';
		return preg_replace_callback($regex, static function ($matches) {
			assert(strlen($matches[0]) === 1);
			$hex = dechex(ord($matches[0]));

			return '\\x' . str_pad($hex, 2, '0', STR_PAD_LEFT);
		}, $escaped);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstExprTrueNode implements ConstExprNode
{

	use NodeAttributes;

	public function __toString(): string
	{
		return 'true';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstFetchNode implements ConstExprNode
{

	use NodeAttributes;

	/** @var string class name for class constants or empty string for non-class constants */
	public string $className;

	public string $name;

	public function __construct(string $className, string $name)
	{
		$this->className = $className;
		$this->name = $name;
	}


	public function __toString(): string
	{
		if ($this->className === '') {
			return $this->name;

		}

		return "{$this->className}::{$this->name}";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\ConstExpr;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;
use function str_replace;
use function strlen;
use function substr;

class DoctrineConstExprStringNode extends ConstExprStringNode
{

	use NodeAttributes;

	public string $value;

	public function __construct(string $value)
	{
		parent::__construct($value, self::DOUBLE_QUOTED);
		$this->value = $value;
	}

	public function __toString(): string
	{
		return self::escape($this->value);
	}

	public static function unescape(string $value): string
	{
		// from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107
		return str_replace('""', '"', substr($value, 1, strlen($value) - 2));
	}

	private static function escape(string $value): string
	{
		// from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656
		return sprintf('"%s"', str_replace('"', '""', $value));
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

interface Node
{

	public function __toString(): string;

	/**
	 * @param mixed $value
	 */
	public function setAttribute(string $key, $value): void;

	public function hasAttribute(string $key): bool;

	/**
	 * @return mixed
	 */
	public function getAttribute(string $key);

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

use function array_key_exists;

trait NodeAttributes
{

	/** @var array<string, mixed> */
	private array $attributes = [];

	/**
	 * @param mixed $value
	 */
	public function setAttribute(string $key, $value): void
	{
		if ($value === null) {
			unset($this->attributes[$key]);
			return;
		}
		$this->attributes[$key] = $value;
	}

	public function hasAttribute(string $key): bool
	{
		return array_key_exists($key, $this->attributes);
	}

	/**
	 * @return mixed
	 */
	public function getAttribute(string $key)
	{
		if ($this->hasAttribute($key)) {
			return $this->attributes[$key];
		}

		return null;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

use LogicException;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function array_keys;
use function array_pop;
use function array_splice;
use function count;
use function get_class;
use function get_object_vars;
use function gettype;
use function is_array;
use function sprintf;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 */
final class NodeTraverser
{

	/**
	 * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
	 * of the current node will not be traversed for any visitors.
	 *
	 * For subsequent visitors enterNode() will still be called on the current
	 * node and leaveNode() will also be invoked for the current node.
	 */
	public const DONT_TRAVERSE_CHILDREN = 1;

	/**
	 * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns
	 * STOP_TRAVERSAL, traversal is aborted.
	 *
	 * The afterTraverse() method will still be invoked.
	 */
	public const STOP_TRAVERSAL = 2;

	/**
	 * If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
	 * in an array, it will be removed from the array.
	 *
	 * For subsequent visitors leaveNode() will still be invoked for the
	 * removed node.
	 */
	public const REMOVE_NODE = 3;

	/**
	 * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes
	 * of the current node will not be traversed for any visitors.
	 *
	 * For subsequent visitors enterNode() will not be called as well.
	 * leaveNode() will be invoked for visitors that has enterNode() method invoked.
	 */
	public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;

	/** @var list<NodeVisitor> Visitors */
	private array $visitors = [];

	/** @var bool Whether traversal should be stopped */
	private bool $stopTraversal;

	/**
	 * @param list<NodeVisitor> $visitors
	 */
	public function __construct(array $visitors)
	{
		$this->visitors = $visitors;
	}

	/**
	 * Traverses an array of nodes using the registered visitors.
	 *
	 * @param Node[] $nodes Array of nodes
	 *
	 * @return Node[] Traversed array of nodes
	 */
	public function traverse(array $nodes): array
	{
		$this->stopTraversal = false;

		foreach ($this->visitors as $visitor) {
			$return = $visitor->beforeTraverse($nodes);
			if ($return === null) {
				continue;
			}

			$nodes = $return;
		}

		$nodes = $this->traverseArray($nodes);

		foreach ($this->visitors as $visitor) {
			$return = $visitor->afterTraverse($nodes);
			if ($return === null) {
				continue;
			}

			$nodes = $return;
		}

		return $nodes;
	}

	/**
	 * Recursively traverse a node.
	 *
	 * @param Node $node Node to traverse.
	 *
	 * @return Node Result of traversal (may be original node or new one)
	 */
	private function traverseNode(Node $node): Node
	{
		$subNodeNames = array_keys(get_object_vars($node));
		foreach ($subNodeNames as $name) {
			$subNode =& $node->$name;

			if (is_array($subNode)) {
				$subNode = $this->traverseArray($subNode);
				if ($this->stopTraversal) {
					break;
				}
			} elseif ($subNode instanceof Node) {
				$traverseChildren = true;
				$breakVisitorIndex = null;

				foreach ($this->visitors as $visitorIndex => $visitor) {
					$return = $visitor->enterNode($subNode);
					if ($return === null) {
						continue;
					}

					if ($return instanceof Node) {
						$this->ensureReplacementReasonable($subNode, $return);
						$subNode = $return;
					} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {
						$traverseChildren = false;
					} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {
						$traverseChildren = false;
						$breakVisitorIndex = $visitorIndex;
						break;
					} elseif ($return === self::STOP_TRAVERSAL) {
						$this->stopTraversal = true;
						break 2;
					} else {
						throw new LogicException(
							'enterNode() returned invalid value of type ' . gettype($return),
						);
					}
				}

				if ($traverseChildren) {
					$subNode = $this->traverseNode($subNode);
					if ($this->stopTraversal) {
						break;
					}
				}

				foreach ($this->visitors as $visitorIndex => $visitor) {
					$return = $visitor->leaveNode($subNode);

					if ($return !== null) {
						if ($return instanceof Node) {
							$this->ensureReplacementReasonable($subNode, $return);
							$subNode = $return;
						} elseif ($return === self::STOP_TRAVERSAL) {
							$this->stopTraversal = true;
							break 2;
						} elseif (is_array($return)) {
							throw new LogicException(
								'leaveNode() may only return an array ' .
								'if the parent structure is an array',
							);
						} else {
							throw new LogicException(
								'leaveNode() returned invalid value of type ' . gettype($return),
							);
						}
					}

					if ($breakVisitorIndex === $visitorIndex) {
						break;
					}
				}
			}
		}

		return $node;
	}

	/**
	 * Recursively traverse array (usually of nodes).
	 *
	 * @param mixed[] $nodes Array to traverse
	 *
	 * @return mixed[] Result of traversal (may be original array or changed one)
	 */
	private function traverseArray(array $nodes): array
	{
		$doNodes = [];

		foreach ($nodes as $i => &$node) {
			if ($node instanceof Node) {
				$traverseChildren = true;
				$breakVisitorIndex = null;

				foreach ($this->visitors as $visitorIndex => $visitor) {
					$return = $visitor->enterNode($node);
					if ($return === null) {
						continue;
					}

					if ($return instanceof Node) {
						$this->ensureReplacementReasonable($node, $return);
						$node = $return;
					} elseif (is_array($return)) {
						$doNodes[] = [$i, $return];
						continue 2;
					} elseif ($return === self::REMOVE_NODE) {
						$doNodes[] = [$i, []];
						continue 2;
					} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {
						$traverseChildren = false;
					} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {
						$traverseChildren = false;
						$breakVisitorIndex = $visitorIndex;
						break;
					} elseif ($return === self::STOP_TRAVERSAL) {
						$this->stopTraversal = true;
						break 2;
					} else {
						throw new LogicException(
							'enterNode() returned invalid value of type ' . gettype($return),
						);
					}
				}

				if ($traverseChildren) {
					$node = $this->traverseNode($node);
					if ($this->stopTraversal) {
						break;
					}
				}

				foreach ($this->visitors as $visitorIndex => $visitor) {
					$return = $visitor->leaveNode($node);

					if ($return !== null) {
						if ($return instanceof Node) {
							$this->ensureReplacementReasonable($node, $return);
							$node = $return;
						} elseif (is_array($return)) {
							$doNodes[] = [$i, $return];
							break;
						} elseif ($return === self::REMOVE_NODE) {
							$doNodes[] = [$i, []];
							break;
						} elseif ($return === self::STOP_TRAVERSAL) {
							$this->stopTraversal = true;
							break 2;
						} else {
							throw new LogicException(
								'leaveNode() returned invalid value of type ' . gettype($return),
							);
						}
					}

					if ($breakVisitorIndex === $visitorIndex) {
						break;
					}
				}
			} elseif (is_array($node)) {
				throw new LogicException('Invalid node structure: Contains nested arrays');
			}
		}

		if (count($doNodes) > 0) {
			while ([$i, $replace] = array_pop($doNodes)) {
				array_splice($nodes, $i, 1, $replace);
			}
		}

		return $nodes;
	}

	private function ensureReplacementReasonable(Node $old, Node $new): void
	{
		if ($old instanceof TypeNode && !$new instanceof TypeNode) {
			throw new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new)));
		}

		if ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) {
			throw new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new)));
		}

		if ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) {
			throw new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new)));
		}

		if ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) {
			throw new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new)));
		}
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\NodeVisitor;

use PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
use PHPStan\PhpDocParser\Ast\Attribute;
use PHPStan\PhpDocParser\Ast\Node;

final class CloningVisitor extends AbstractNodeVisitor
{

	public function enterNode(Node $originalNode): Node
	{
		$node = clone $originalNode;
		$node->setAttribute(Attribute::ORIGINAL_NODE, $originalNode);

		return $node;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 */
interface NodeVisitor
{

	/**
	 * Called once before traversal.
	 *
	 * Return value semantics:
	 *  * null:      $nodes stays as-is
	 *  * otherwise: $nodes is set to the return value
	 *
	 * @param Node[] $nodes Array of nodes
	 *
	 * @return Node[]|null Array of nodes
	 */
	public function beforeTraverse(array $nodes): ?array;

	/**
	 * Called when entering a node.
	 *
	 * Return value semantics:
	 *  * null
	 *        => $node stays as-is
	 *  * array (of Nodes)
	 *        => The return value is merged into the parent array (at the position of the $node)
	 *  * NodeTraverser::REMOVE_NODE
	 *        => $node is removed from the parent array
	 *  * NodeTraverser::DONT_TRAVERSE_CHILDREN
	 *        => Children of $node are not traversed. $node stays as-is
	 *  * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN
	 *        => Further visitors for the current node are skipped, and its children are not
	 *           traversed. $node stays as-is.
	 *  * NodeTraverser::STOP_TRAVERSAL
	 *        => Traversal is aborted. $node stays as-is
	 *  * otherwise
	 *        => $node is set to the return value
	 *
	 * @param Node $node Node
	 *
	 * @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value)
	 */
	public function enterNode(Node $node);

	/**
	 * Called when leaving a node.
	 *
	 * Return value semantics:
	 *  * null
	 *        => $node stays as-is
	 *  * NodeTraverser::REMOVE_NODE
	 *        => $node is removed from the parent array
	 *  * NodeTraverser::STOP_TRAVERSAL
	 *        => Traversal is aborted. $node stays as-is
	 *  * array (of Nodes)
	 *        => The return value is merged into the parent array (at the position of the $node)
	 *  * otherwise
	 *        => $node is set to the return value
	 *
	 * @param Node $node Node
	 *
	 * @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value)
	 */
	public function leaveNode(Node $node);

	/**
	 * Called once after traversal.
	 *
	 * Return value semantics:
	 *  * null:      $nodes stays as-is
	 *  * otherwise: $nodes is set to the return value
	 *
	 * @param Node[] $nodes Array of nodes
	 *
	 * @return Node[]|null Array of nodes
	 */
	public function afterTraverse(array $nodes): ?array;

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class AssertTagMethodValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $parameter;

	public string $method;

	public bool $isNegated;

	public bool $isEquality;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $parameter, string $method, bool $isNegated, string $description, bool $isEquality)
	{
		$this->type = $type;
		$this->parameter = $parameter;
		$this->method = $method;
		$this->isNegated = $isNegated;
		$this->isEquality = $isEquality;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$isNegated = $this->isNegated ? '!' : '';
		$isEquality = $this->isEquality ? '=' : '';
		return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->method}() {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class AssertTagPropertyValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $parameter;

	public string $property;

	public bool $isNegated;

	public bool $isEquality;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $parameter, string $property, bool $isNegated, string $description, bool $isEquality)
	{
		$this->type = $type;
		$this->parameter = $parameter;
		$this->property = $property;
		$this->isNegated = $isNegated;
		$this->isEquality = $isEquality;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$isNegated = $this->isNegated ? '!' : '';
		$isEquality = $this->isEquality ? '=' : '';
		return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->property} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class AssertTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $parameter;

	public bool $isNegated;

	public bool $isEquality;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $parameter, bool $isNegated, string $description, bool $isEquality)
	{
		$this->type = $type;
		$this->parameter = $parameter;
		$this->isNegated = $isNegated;
		$this->isEquality = $isEquality;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$isNegated = $this->isNegated ? '!' : '';
		$isEquality = $this->isEquality ? '=' : '';
		return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class DeprecatedTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(string $description)
	{
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim($this->description);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;

class DoctrineAnnotation implements Node
{

	use NodeAttributes;

	public string $name;

	/** @var list<DoctrineArgument> */
	public array $arguments;

	/**
	 * @param list<DoctrineArgument> $arguments
	 */
	public function __construct(string $name, array $arguments)
	{
		$this->name = $name;
		$this->arguments = $arguments;
	}

	public function __toString(): string
	{
		$arguments = implode(', ', $this->arguments);
		return $this->name . '(' . $arguments . ')';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;

/**
 * @phpstan-type ValueType = DoctrineAnnotation|IdentifierTypeNode|DoctrineArray|ConstExprNode
 */
class DoctrineArgument implements Node
{

	use NodeAttributes;

	public ?IdentifierTypeNode $key = null;

	/** @var ValueType */
	public $value;

	/**
	 * @param ValueType $value
	 */
	public function __construct(?IdentifierTypeNode $key, $value)
	{
		$this->key = $key;
		$this->value = $value;
	}


	public function __toString(): string
	{
		if ($this->key === null) {
			return (string) $this->value;
		}

		return $this->key . '=' . $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;

class DoctrineArray implements Node
{

	use NodeAttributes;

	/** @var list<DoctrineArrayItem> */
	public array $items;

	/**
	 * @param list<DoctrineArrayItem> $items
	 */
	public function __construct(array $items)
	{
		$this->items = $items;
	}

	public function __toString(): string
	{
		$items = implode(', ', $this->items);

		return '{' . $items . '}';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;

/**
 * @phpstan-import-type ValueType from DoctrineArgument
 * @phpstan-type KeyType = ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode|null
 */
class DoctrineArrayItem implements Node
{

	use NodeAttributes;

	/** @var KeyType */
	public $key;

	/** @var ValueType */
	public $value;

	/**
	 * @param KeyType $key
	 * @param ValueType $value
	 */
	public function __construct($key, $value)
	{
		$this->key = $key;
		$this->value = $value;
	}


	public function __toString(): string
	{
		if ($this->key === null) {
			return (string) $this->value;
		}

		return $this->key . '=' . $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use function trim;

class DoctrineTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public DoctrineAnnotation $annotation;

	/** @var string (may be empty) */
	public string $description;


	public function __construct(
		DoctrineAnnotation $annotation,
		string $description
	)
	{
		$this->annotation = $annotation;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->annotation} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use function trim;

class ExtendsTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public GenericTypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(GenericTypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class GenericTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	/** @var string (may be empty) */
	public string $value;

	public function __construct(string $value)
	{
		$this->value = $value;
	}


	public function __toString(): string
	{
		return $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use function trim;

class ImplementsTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public GenericTypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(GenericTypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Parser\ParserException;
use function sprintf;
use function trigger_error;
use const E_USER_WARNING;

/**
 * @property ParserException $exception
 */
class InvalidTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	/** @var string (may be empty) */
	public string $value;

	/** @var mixed[] */
	private array $exceptionArgs;

	public function __construct(string $value, ParserException $exception)
	{
		$this->value = $value;
		$this->exceptionArgs = [
			$exception->getCurrentTokenValue(),
			$exception->getCurrentTokenType(),
			$exception->getCurrentOffset(),
			$exception->getExpectedTokenType(),
			$exception->getExpectedTokenValue(),
			$exception->getCurrentTokenLine(),
		];
	}

	public function __get(string $name): ?ParserException
	{
		if ($name !== 'exception') {
			trigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING);
			return null;
		}

		return new ParserException(...$this->exceptionArgs);
	}

	public function __toString(): string
	{
		return $this->value;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function count;
use function implode;

class MethodTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public bool $isStatic;

	public ?TypeNode $returnType = null;

	public string $methodName;

	/** @var TemplateTagValueNode[] */
	public array $templateTypes;

	/** @var MethodTagValueParameterNode[] */
	public array $parameters;

	/** @var string (may be empty) */
	public string $description;

	/**
	 * @param MethodTagValueParameterNode[] $parameters
	 * @param TemplateTagValueNode[] $templateTypes
	 */
	public function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes)
	{
		$this->isStatic = $isStatic;
		$this->returnType = $returnType;
		$this->methodName = $methodName;
		$this->parameters = $parameters;
		$this->description = $description;
		$this->templateTypes = $templateTypes;
	}


	public function __toString(): string
	{
		$static = $this->isStatic ? 'static ' : '';
		$returnType = $this->returnType !== null ? "{$this->returnType} " : '';
		$parameters = implode(', ', $this->parameters);
		$description = $this->description !== '' ? " {$this->description}" : '';
		$templateTypes = count($this->templateTypes) > 0 ? '<' . implode(', ', $this->templateTypes) . '>' : '';
		return "{$static}{$returnType}{$this->methodName}{$templateTypes}({$parameters}){$description}";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;

class MethodTagValueParameterNode implements Node
{

	use NodeAttributes;

	public ?TypeNode $type = null;

	public bool $isReference;

	public bool $isVariadic;

	public string $parameterName;

	public ?ConstExprNode $defaultValue = null;

	public function __construct(?TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, ?ConstExprNode $defaultValue)
	{
		$this->type = $type;
		$this->isReference = $isReference;
		$this->isVariadic = $isVariadic;
		$this->parameterName = $parameterName;
		$this->defaultValue = $defaultValue;
	}


	public function __toString(): string
	{
		$type = $this->type !== null ? "{$this->type} " : '';
		$isReference = $this->isReference ? '&' : '';
		$isVariadic = $this->isVariadic ? '...' : '';
		$default = $this->defaultValue !== null ? " = {$this->defaultValue}" : '';
		return "{$type}{$isReference}{$isVariadic}{$this->parameterName}{$default}";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class MixinTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class ParamClosureThisTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $parameterName, string $description)
	{
		$this->type = $type;
		$this->parameterName = $parameterName;
		$this->description = $description;
	}

	public function __toString(): string
	{
		return trim("{$this->type} {$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class ParamImmediatelyInvokedCallableTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(string $parameterName, string $description)
	{
		$this->parameterName = $parameterName;
		$this->description = $description;
	}

	public function __toString(): string
	{
		return trim("{$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class ParamLaterInvokedCallableTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(string $parameterName, string $description)
	{
		$this->parameterName = $parameterName;
		$this->description = $description;
	}

	public function __toString(): string
	{
		return trim("{$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class ParamOutTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $parameterName, string $description)
	{
		$this->type = $type;
		$this->parameterName = $parameterName;
		$this->description = $description;
	}

	public function __toString(): string
	{
		return trim("{$this->type} {$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class ParamTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public bool $isReference;

	public bool $isVariadic;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, bool $isVariadic, string $parameterName, string $description, bool $isReference)
	{
		$this->type = $type;
		$this->isReference = $isReference;
		$this->isVariadic = $isVariadic;
		$this->parameterName = $parameterName;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$reference = $this->isReference ? '&' : '';
		$variadic = $this->isVariadic ? '...' : '';
		return trim("{$this->type} {$reference}{$variadic}{$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\Node;

interface PhpDocChildNode extends Node
{

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function array_column;
use function array_filter;
use function array_map;
use function implode;

class PhpDocNode implements Node
{

	use NodeAttributes;

	/** @var PhpDocChildNode[] */
	public array $children;

	/**
	 * @param PhpDocChildNode[] $children
	 */
	public function __construct(array $children)
	{
		$this->children = $children;
	}


	/**
	 * @return PhpDocTagNode[]
	 */
	public function getTags(): array
	{
		return array_filter($this->children, static fn (PhpDocChildNode $child): bool => $child instanceof PhpDocTagNode);
	}


	/**
	 * @return PhpDocTagNode[]
	 */
	public function getTagsByName(string $tagName): array
	{
		return array_filter($this->getTags(), static fn (PhpDocTagNode $tag): bool => $tag->name === $tagName);
	}


	/**
	 * @return VarTagValueNode[]
	 */
	public function getVarTagValues(string $tagName = '@var'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof VarTagValueNode,
		);
	}


	/**
	 * @return ParamTagValueNode[]
	 */
	public function getParamTagValues(string $tagName = '@param'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamTagValueNode,
		);
	}


	/**
	 * @return TypelessParamTagValueNode[]
	 */
	public function getTypelessParamTagValues(string $tagName = '@param'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypelessParamTagValueNode,
		);
	}


	/**
	 * @return ParamImmediatelyInvokedCallableTagValueNode[]
	 */
	public function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamImmediatelyInvokedCallableTagValueNode,
		);
	}


	/**
	 * @return ParamLaterInvokedCallableTagValueNode[]
	 */
	public function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamLaterInvokedCallableTagValueNode,
		);
	}


	/**
	 * @return ParamClosureThisTagValueNode[]
	 */
	public function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamClosureThisTagValueNode,
		);
	}

	/**
	 * @return PureUnlessCallableIsImpureTagValueNode[]
	 */
	public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessCallableIsImpureTagValueNode,
		);
	}

	/**
	 * @return TemplateTagValueNode[]
	 */
	public function getTemplateTagValues(string $tagName = '@template'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof TemplateTagValueNode,
		);
	}


	/**
	 * @return ExtendsTagValueNode[]
	 */
	public function getExtendsTagValues(string $tagName = '@extends'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ExtendsTagValueNode,
		);
	}


	/**
	 * @return ImplementsTagValueNode[]
	 */
	public function getImplementsTagValues(string $tagName = '@implements'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ImplementsTagValueNode,
		);
	}


	/**
	 * @return UsesTagValueNode[]
	 */
	public function getUsesTagValues(string $tagName = '@use'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof UsesTagValueNode,
		);
	}


	/**
	 * @return ReturnTagValueNode[]
	 */
	public function getReturnTagValues(string $tagName = '@return'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ReturnTagValueNode,
		);
	}


	/**
	 * @return ThrowsTagValueNode[]
	 */
	public function getThrowsTagValues(string $tagName = '@throws'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ThrowsTagValueNode,
		);
	}


	/**
	 * @return MixinTagValueNode[]
	 */
	public function getMixinTagValues(string $tagName = '@mixin'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof MixinTagValueNode,
		);
	}

	/**
	 * @return RequireExtendsTagValueNode[]
	 */
	public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireExtendsTagValueNode,
		);
	}

	/**
	 * @return RequireImplementsTagValueNode[]
	 */
	public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireImplementsTagValueNode,
		);
	}

	/**
	 * @return SealedTagValueNode[]
	 */
	public function getSealedTagValues(string $tagName = '@phpstan-sealed'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof SealedTagValueNode,
		);
	}

	/**
	 * @return DeprecatedTagValueNode[]
	 */
	public function getDeprecatedTagValues(): array
	{
		return array_filter(
			array_column($this->getTagsByName('@deprecated'), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,
		);
	}


	/**
	 * @return PropertyTagValueNode[]
	 */
	public function getPropertyTagValues(string $tagName = '@property'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
		);
	}


	/**
	 * @return PropertyTagValueNode[]
	 */
	public function getPropertyReadTagValues(string $tagName = '@property-read'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
		);
	}


	/**
	 * @return PropertyTagValueNode[]
	 */
	public function getPropertyWriteTagValues(string $tagName = '@property-write'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
		);
	}


	/**
	 * @return MethodTagValueNode[]
	 */
	public function getMethodTagValues(string $tagName = '@method'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,
		);
	}


	/**
	 * @return TypeAliasTagValueNode[]
	 */
	public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,
		);
	}


	/**
	 * @return TypeAliasImportTagValueNode[]
	 */
	public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,
		);
	}


	/**
	 * @return AssertTagValueNode[]
	 */
	public function getAssertTagValues(string $tagName = '@phpstan-assert'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,
		);
	}


	/**
	 * @return AssertTagPropertyValueNode[]
	 */
	public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,
		);
	}


	/**
	 * @return AssertTagMethodValueNode[]
	 */
	public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,
		);
	}


	/**
	 * @return SelfOutTagValueNode[]
	 */
	public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,
		);
	}


	/**
	 * @return ParamOutTagValueNode[]
	 */
	public function getParamOutTypeTagValues(string $tagName = '@param-out'): array
	{
		return array_filter(
			array_column($this->getTagsByName($tagName), 'value'),
			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,
		);
	}


	public function __toString(): string
	{
		$children = array_map(
			static function (PhpDocChildNode $child): string {
				$s = (string) $child;
				return $s === '' ? '' : ' ' . $s;
			},
			$this->children,
		);
		return "/**\n *" . implode("\n *", $children) . "\n */";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
use function trim;

class PhpDocTagNode implements PhpDocChildNode
{

	use NodeAttributes;

	public string $name;

	public PhpDocTagValueNode $value;

	public function __construct(string $name, PhpDocTagValueNode $value)
	{
		$this->name = $name;
		$this->value = $value;
	}


	public function __toString(): string
	{
		if ($this->value instanceof DoctrineTagValueNode) {
			return (string) $this->value;
		}

		return trim("{$this->name} {$this->value}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\Node;

interface PhpDocTagValueNode extends Node
{

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class PhpDocTextNode implements PhpDocChildNode
{

	use NodeAttributes;

	public string $text;

	public function __construct(string $text)
	{
		$this->text = $text;
	}


	public function __toString(): string
	{
		return $this->text;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class PropertyTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	public string $propertyName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $propertyName, string $description)
	{
		$this->type = $type;
		$this->propertyName = $propertyName;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->propertyName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class PureUnlessCallableIsImpureTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(string $parameterName, string $description)
	{
		$this->parameterName = $parameterName;
		$this->description = $description;
	}

	public function __toString(): string
	{
		return trim("{$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class RequireExtendsTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class RequireImplementsTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class ReturnTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class SealedTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class SelfOutTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim($this->type . ' ' . $this->description);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class TemplateTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	/** @var non-empty-string */
	public string $name;

	public ?TypeNode $bound;

	public ?TypeNode $default;

	public ?TypeNode $lowerBound;

	/** @var string (may be empty) */
	public string $description;

	/**
	 * @param non-empty-string $name
	 */
	public function __construct(string $name, ?TypeNode $bound, string $description, ?TypeNode $default = null, ?TypeNode $lowerBound = null)
	{
		$this->name = $name;
		$this->bound = $bound;
		$this->lowerBound = $lowerBound;
		$this->default = $default;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$upperBound = $this->bound !== null ? " of {$this->bound}" : '';
		$lowerBound = $this->lowerBound !== null ? " super {$this->lowerBound}" : '';
		$default = $this->default !== null ? " = {$this->default}" : '';
		return trim("{$this->name}{$upperBound}{$lowerBound}{$default} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class ThrowsTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use function trim;

class TypeAliasImportTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public string $importedAlias;

	public IdentifierTypeNode $importedFrom;

	public ?string $importedAs = null;

	public function __construct(string $importedAlias, IdentifierTypeNode $importedFrom, ?string $importedAs)
	{
		$this->importedAlias = $importedAlias;
		$this->importedFrom = $importedFrom;
		$this->importedAs = $importedAs;
	}

	public function __toString(): string
	{
		return trim(
			"{$this->importedAlias} from {$this->importedFrom}"
			. ($this->importedAs !== null ? " as {$this->importedAs}" : ''),
		);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class TypeAliasTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public string $alias;

	public TypeNode $type;

	public function __construct(string $alias, TypeNode $type)
	{
		$this->alias = $alias;
		$this->type = $type;
	}


	public function __toString(): string
	{
		return trim("{$this->alias} {$this->type}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class TypelessParamTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public bool $isReference;

	public bool $isVariadic;

	public string $parameterName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(bool $isVariadic, string $parameterName, string $description, bool $isReference)
	{
		$this->isReference = $isReference;
		$this->isVariadic = $isVariadic;
		$this->parameterName = $parameterName;
		$this->description = $description;
	}


	public function __toString(): string
	{
		$reference = $this->isReference ? '&' : '';
		$variadic = $this->isVariadic ? '...' : '';
		return trim("{$reference}{$variadic}{$this->parameterName} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use function trim;

class UsesTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public GenericTypeNode $type;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(GenericTypeNode $type, string $description)
	{
		$this->type = $type;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("{$this->type} {$this->description}");
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class VarTagValueNode implements PhpDocTagValueNode
{

	use NodeAttributes;

	public TypeNode $type;

	/** @var string (may be empty) */
	public string $variableName;

	/** @var string (may be empty) */
	public string $description;

	public function __construct(TypeNode $type, string $variableName, string $description)
	{
		$this->type = $type;
		$this->variableName = $variableName;
		$this->description = $description;
	}


	public function __toString(): string
	{
		return trim("$this->type " . trim("{$this->variableName} {$this->description}"));
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ArrayShapeItemNode implements Node
{

	use NodeAttributes;

	/** @var ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null */
	public $keyName;

	public bool $optional;

	public TypeNode $valueType;

	/**
	 * @param ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null $keyName
	 */
	public function __construct($keyName, bool $optional, TypeNode $valueType)
	{
		$this->keyName = $keyName;
		$this->optional = $optional;
		$this->valueType = $valueType;
	}


	public function __toString(): string
	{
		if ($this->keyName !== null) {
			return sprintf(
				'%s%s: %s',
				(string) $this->keyName,
				$this->optional ? '?' : '',
				(string) $this->valueType,
			);
		}

		return (string) $this->valueType;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;

class ArrayShapeNode implements TypeNode
{

	public const KIND_ARRAY = 'array';
	public const KIND_LIST = 'list';
	public const KIND_NON_EMPTY_ARRAY = 'non-empty-array';
	public const KIND_NON_EMPTY_LIST = 'non-empty-list';

	use NodeAttributes;

	/** @var ArrayShapeItemNode[] */
	public array $items;

	public bool $sealed;

	/** @var self::KIND_* */
	public $kind;

	public ?ArrayShapeUnsealedTypeNode $unsealedType = null;

	/**
	 * @param ArrayShapeItemNode[] $items
	 * @param self::KIND_* $kind
	 */
	private function __construct(
		array $items,
		bool $sealed = true,
		?ArrayShapeUnsealedTypeNode $unsealedType = null,
		string $kind = self::KIND_ARRAY
	)
	{
		$this->items = $items;
		$this->sealed = $sealed;
		$this->unsealedType = $unsealedType;
		$this->kind = $kind;
	}


	/**
	 * @param ArrayShapeItemNode[] $items
	 * @param self::KIND_* $kind
	 */
	public static function createSealed(array $items, string $kind = self::KIND_ARRAY): self
	{
		return new self($items, true, null, $kind);
	}

	/**
	 * @param ArrayShapeItemNode[] $items
	 * @param self::KIND_* $kind
	 */
	public static function createUnsealed(array $items, ?ArrayShapeUnsealedTypeNode $unsealedType, string $kind = self::KIND_ARRAY): self
	{
		return new self($items, false, $unsealedType, $kind);
	}


	public function __toString(): string
	{
		$items = $this->items;

		if (! $this->sealed) {
			$items[] = '...' . $this->unsealedType;
		}

		return $this->kind . '{' . implode(', ', $items) . '}';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ArrayShapeUnsealedTypeNode implements Node
{

	use NodeAttributes;

	public TypeNode $valueType;

	public ?TypeNode $keyType = null;

	public function __construct(TypeNode $valueType, ?TypeNode $keyType)
	{
		$this->valueType = $valueType;
		$this->keyType = $keyType;
	}

	public function __toString(): string
	{
		if ($this->keyType !== null) {
			return sprintf('<%s, %s>', $this->keyType, $this->valueType);
		}
		return sprintf('<%s>', $this->valueType);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ArrayTypeNode implements TypeNode
{

	use NodeAttributes;

	public TypeNode $type;

	public function __construct(TypeNode $type)
	{
		$this->type = $type;
	}


	public function __toString(): string
	{
		if (
			$this->type instanceof CallableTypeNode
			|| $this->type instanceof ConstTypeNode
			|| $this->type instanceof NullableTypeNode
		) {
			return '(' . $this->type . ')[]';
		}

		return $this->type . '[]';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use function implode;

class CallableTypeNode implements TypeNode
{

	use NodeAttributes;

	public IdentifierTypeNode $identifier;

	/** @var TemplateTagValueNode[] */
	public array $templateTypes;

	/** @var CallableTypeParameterNode[] */
	public array $parameters;

	public TypeNode $returnType;

	/**
	 * @param CallableTypeParameterNode[] $parameters
	 * @param TemplateTagValueNode[]  $templateTypes
	 */
	public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templateTypes)
	{
		$this->identifier = $identifier;
		$this->parameters = $parameters;
		$this->returnType = $returnType;
		$this->templateTypes = $templateTypes;
	}


	public function __toString(): string
	{
		$returnType = $this->returnType;
		if ($returnType instanceof self) {
			$returnType = "({$returnType})";
		}
		$template = $this->templateTypes !== []
			? '<' . implode(', ', $this->templateTypes) . '>'
			: '';
		$parameters = implode(', ', $this->parameters);
		return "{$this->identifier}{$template}({$parameters}): {$returnType}";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function trim;

class CallableTypeParameterNode implements Node
{

	use NodeAttributes;

	public TypeNode $type;

	public bool $isReference;

	public bool $isVariadic;

	/** @var string (may be empty) */
	public string $parameterName;

	public bool $isOptional;

	public function __construct(TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, bool $isOptional)
	{
		$this->type = $type;
		$this->isReference = $isReference;
		$this->isVariadic = $isVariadic;
		$this->parameterName = $parameterName;
		$this->isOptional = $isOptional;
	}


	public function __toString(): string
	{
		$type = "{$this->type} ";
		$isReference = $this->isReference ? '&' : '';
		$isVariadic = $this->isVariadic ? '...' : '';
		$isOptional = $this->isOptional ? '=' : '';
		return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $isOptional;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ConditionalTypeForParameterNode implements TypeNode
{

	use NodeAttributes;

	public string $parameterName;

	public TypeNode $targetType;

	public TypeNode $if;

	public TypeNode $else;

	public bool $negated;

	public function __construct(string $parameterName, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
	{
		$this->parameterName = $parameterName;
		$this->targetType = $targetType;
		$this->if = $if;
		$this->else = $else;
		$this->negated = $negated;
	}

	public function __toString(): string
	{
		return sprintf(
			'(%s %s %s ? %s : %s)',
			$this->parameterName,
			$this->negated ? 'is not' : 'is',
			$this->targetType,
			$this->if,
			$this->else,
		);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ConditionalTypeNode implements TypeNode
{

	use NodeAttributes;

	public TypeNode $subjectType;

	public TypeNode $targetType;

	public TypeNode $if;

	public TypeNode $else;

	public bool $negated;

	public function __construct(TypeNode $subjectType, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
	{
		$this->subjectType = $subjectType;
		$this->targetType = $targetType;
		$this->if = $if;
		$this->else = $else;
		$this->negated = $negated;
	}

	public function __toString(): string
	{
		return sprintf(
			'(%s %s %s ? %s : %s)',
			$this->subjectType,
			$this->negated ? 'is not' : 'is',
			$this->targetType,
			$this->if,
			$this->else,
		);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ConstTypeNode implements TypeNode
{

	use NodeAttributes;

	public ConstExprNode $constExpr;

	public function __construct(ConstExprNode $constExpr)
	{
		$this->constExpr = $constExpr;
	}

	public function __toString(): string
	{
		return $this->constExpr->__toString();
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;
use function sprintf;

class GenericTypeNode implements TypeNode
{

	public const VARIANCE_INVARIANT = 'invariant';
	public const VARIANCE_COVARIANT = 'covariant';
	public const VARIANCE_CONTRAVARIANT = 'contravariant';
	public const VARIANCE_BIVARIANT = 'bivariant';

	use NodeAttributes;

	public IdentifierTypeNode $type;

	/** @var TypeNode[] */
	public array $genericTypes;

	/** @var (self::VARIANCE_*)[] */
	public array $variances;

	/**
	 * @param TypeNode[] $genericTypes
	 * @param (self::VARIANCE_*)[] $variances
	 */
	public function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = [])
	{
		$this->type = $type;
		$this->genericTypes = $genericTypes;
		$this->variances = $variances;
	}


	public function __toString(): string
	{
		$genericTypes = [];

		foreach ($this->genericTypes as $index => $type) {
			$variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT;
			if ($variance === self::VARIANCE_INVARIANT) {
				$genericTypes[] = (string) $type;
			} elseif ($variance === self::VARIANCE_BIVARIANT) {
				$genericTypes[] = '*';
			} else {
				$genericTypes[] = sprintf('%s %s', $variance, $type);
			}
		}

		return $this->type . '<' . implode(', ', $genericTypes) . '>';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class IdentifierTypeNode implements TypeNode
{

	use NodeAttributes;

	public string $name;

	public function __construct(string $name)
	{
		$this->name = $name;
	}


	public function __toString(): string
	{
		return $this->name;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function array_map;
use function implode;

class IntersectionTypeNode implements TypeNode
{

	use NodeAttributes;

	/** @var TypeNode[] */
	public array $types;

	/**
	 * @param TypeNode[] $types
	 */
	public function __construct(array $types)
	{
		$this->types = $types;
	}


	public function __toString(): string
	{
		return '(' . implode(' & ', array_map(static function (TypeNode $type): string {
			if ($type instanceof NullableTypeNode) {
				return '(' . $type . ')';
			}

			return (string) $type;
		}, $this->types)) . ')';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Parser\ParserException;

class InvalidTypeNode implements TypeNode
{

	use NodeAttributes;

	/** @var mixed[] */
	private array $exceptionArgs;

	public function __construct(ParserException $exception)
	{
		$this->exceptionArgs = [
			$exception->getCurrentTokenValue(),
			$exception->getCurrentTokenType(),
			$exception->getCurrentOffset(),
			$exception->getExpectedTokenType(),
			$exception->getExpectedTokenValue(),
			$exception->getCurrentTokenLine(),
		];
	}

	public function getException(): ParserException
	{
		return new ParserException(...$this->exceptionArgs);
	}

	public function __toString(): string
	{
		return '*Invalid type*';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class NullableTypeNode implements TypeNode
{

	use NodeAttributes;

	public TypeNode $type;

	public function __construct(TypeNode $type)
	{
		$this->type = $type;
	}


	public function __toString(): string
	{
		return '?' . $this->type;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;

class ObjectShapeItemNode implements Node
{

	use NodeAttributes;

	/** @var ConstExprStringNode|IdentifierTypeNode */
	public $keyName;

	public bool $optional;

	public TypeNode $valueType;

	/**
	 * @param ConstExprStringNode|IdentifierTypeNode $keyName
	 */
	public function __construct($keyName, bool $optional, TypeNode $valueType)
	{
		$this->keyName = $keyName;
		$this->optional = $optional;
		$this->valueType = $valueType;
	}


	public function __toString(): string
	{
		if ($this->keyName !== null) {
			return sprintf(
				'%s%s: %s',
				(string) $this->keyName,
				$this->optional ? '?' : '',
				(string) $this->valueType,
			);
		}

		return (string) $this->valueType;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;

class ObjectShapeNode implements TypeNode
{

	use NodeAttributes;

	/** @var ObjectShapeItemNode[] */
	public array $items;

	/**
	 * @param ObjectShapeItemNode[] $items
	 */
	public function __construct(array $items)
	{
		$this->items = $items;
	}

	public function __toString(): string
	{
		$items = $this->items;

		return 'object{' . implode(', ', $items) . '}';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class OffsetAccessTypeNode implements TypeNode
{

	use NodeAttributes;

	public TypeNode $type;

	public TypeNode $offset;

	public function __construct(TypeNode $type, TypeNode $offset)
	{
		$this->type = $type;
		$this->offset = $offset;
	}

	public function __toString(): string
	{
		if (
			$this->type instanceof CallableTypeNode
			|| $this->type instanceof NullableTypeNode
		) {
			return '(' . $this->type . ')[' . $this->offset . ']';
		}

		return $this->type . '[' . $this->offset . ']';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;

class ThisTypeNode implements TypeNode
{

	use NodeAttributes;

	public function __toString(): string
	{
		return '$this';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\Node;

interface TypeNode extends Node
{

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\Type;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function array_map;
use function implode;

class UnionTypeNode implements TypeNode
{

	use NodeAttributes;

	/** @var TypeNode[] */
	public array $types;

	/**
	 * @param TypeNode[] $types
	 */
	public function __construct(array $types)
	{
		$this->types = $types;
	}


	public function __toString(): string
	{
		return '(' . implode(' | ', array_map(static function (TypeNode $type): string {
			if ($type instanceof NullableTypeNode) {
				return '(' . $type . ')';
			}

				return (string) $type;
		}, $this->types)) . ')';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Lexer;

use PHPStan\PhpDocParser\ParserConfig;
use function implode;
use function preg_match_all;
use const PREG_SET_ORDER;

/**
 * Implementation based on Nette Tokenizer (New BSD License; https://github.com/nette/tokenizer)
 */
class Lexer
{

	public const TOKEN_REFERENCE = 0;
	public const TOKEN_UNION = 1;
	public const TOKEN_INTERSECTION = 2;
	public const TOKEN_NULLABLE = 3;
	public const TOKEN_OPEN_PARENTHESES = 4;
	public const TOKEN_CLOSE_PARENTHESES = 5;
	public const TOKEN_OPEN_ANGLE_BRACKET = 6;
	public const TOKEN_CLOSE_ANGLE_BRACKET = 7;
	public const TOKEN_OPEN_SQUARE_BRACKET = 8;
	public const TOKEN_CLOSE_SQUARE_BRACKET = 9;
	public const TOKEN_COMMA = 10;
	public const TOKEN_VARIADIC = 11;
	public const TOKEN_DOUBLE_COLON = 12;
	public const TOKEN_DOUBLE_ARROW = 13;
	public const TOKEN_EQUAL = 14;
	public const TOKEN_OPEN_PHPDOC = 15;
	public const TOKEN_CLOSE_PHPDOC = 16;
	public const TOKEN_PHPDOC_TAG = 17;
	public const TOKEN_DOCTRINE_TAG = 18;
	public const TOKEN_FLOAT = 19;
	public const TOKEN_INTEGER = 20;
	public const TOKEN_SINGLE_QUOTED_STRING = 21;
	public const TOKEN_DOUBLE_QUOTED_STRING = 22;
	public const TOKEN_DOCTRINE_ANNOTATION_STRING = 23;
	public const TOKEN_IDENTIFIER = 24;
	public const TOKEN_THIS_VARIABLE = 25;
	public const TOKEN_VARIABLE = 26;
	public const TOKEN_HORIZONTAL_WS = 27;
	public const TOKEN_PHPDOC_EOL = 28;
	public const TOKEN_OTHER = 29;
	public const TOKEN_END = 30;
	public const TOKEN_COLON = 31;
	public const TOKEN_WILDCARD = 32;
	public const TOKEN_OPEN_CURLY_BRACKET = 33;
	public const TOKEN_CLOSE_CURLY_BRACKET = 34;
	public const TOKEN_NEGATED = 35;
	public const TOKEN_ARROW = 36;

	public const TOKEN_COMMENT = 37;

	public const TOKEN_LABELS = [
		self::TOKEN_REFERENCE => '\'&\'',
		self::TOKEN_UNION => '\'|\'',
		self::TOKEN_INTERSECTION => '\'&\'',
		self::TOKEN_NULLABLE => '\'?\'',
		self::TOKEN_NEGATED => '\'!\'',
		self::TOKEN_OPEN_PARENTHESES => '\'(\'',
		self::TOKEN_CLOSE_PARENTHESES => '\')\'',
		self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'',
		self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'',
		self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'',
		self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'',
		self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'',
		self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'',
		self::TOKEN_COMMA => '\',\'',
		self::TOKEN_COMMENT => '\'//\'',
		self::TOKEN_COLON => '\':\'',
		self::TOKEN_VARIADIC => '\'...\'',
		self::TOKEN_DOUBLE_COLON => '\'::\'',
		self::TOKEN_DOUBLE_ARROW => '\'=>\'',
		self::TOKEN_ARROW => '\'->\'',
		self::TOKEN_EQUAL => '\'=\'',
		self::TOKEN_OPEN_PHPDOC => '\'/**\'',
		self::TOKEN_CLOSE_PHPDOC => '\'*/\'',
		self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG',
		self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG',
		self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL',
		self::TOKEN_FLOAT => 'TOKEN_FLOAT',
		self::TOKEN_INTEGER => 'TOKEN_INTEGER',
		self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING',
		self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING',
		self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING',
		self::TOKEN_IDENTIFIER => 'type',
		self::TOKEN_THIS_VARIABLE => '\'$this\'',
		self::TOKEN_VARIABLE => 'variable',
		self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS',
		self::TOKEN_OTHER => 'TOKEN_OTHER',
		self::TOKEN_END => 'TOKEN_END',
		self::TOKEN_WILDCARD => '*',
	];

	public const VALUE_OFFSET = 0;
	public const TYPE_OFFSET = 1;
	public const LINE_OFFSET = 2;

	private ParserConfig $config; // @phpstan-ignore property.onlyWritten

	private ?string $regexp = null;

	public function __construct(ParserConfig $config)
	{
		$this->config = $config;
	}


	/**
	 * @return list<array{string, int, int}>
	 */
	public function tokenize(string $s): array
	{
		if ($this->regexp === null) {
			$this->regexp = $this->generateRegexp();
		}

		preg_match_all($this->regexp, $s, $matches, PREG_SET_ORDER);

		$tokens = [];
		$line = 1;
		foreach ($matches as $match) {
			$type = (int) $match['MARK'];
			$tokens[] = [$match[0], $type, $line];
			if ($type !== self::TOKEN_PHPDOC_EOL) {
				continue;
			}

			$line++;
		}

		$tokens[] = ['', self::TOKEN_END, $line];

		return $tokens;
	}


	private function generateRegexp(): string
	{
		$patterns = [
			self::TOKEN_HORIZONTAL_WS => '[\\x09\\x20]++',

			self::TOKEN_IDENTIFIER => '(?:[\\\\]?+[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF-]*+)++',
			self::TOKEN_THIS_VARIABLE => '\\$this(?![0-9a-z_\\x80-\\xFF])',
			self::TOKEN_VARIABLE => '\\$[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF]*+',

			// '&' followed by TOKEN_VARIADIC, TOKEN_VARIABLE, TOKEN_EQUAL, TOKEN_EQUAL or TOKEN_CLOSE_PARENTHESES
			self::TOKEN_REFERENCE => '&(?=\\s*+(?:[.,=)]|(?:\\$(?!this(?![0-9a-z_\\x80-\\xFF])))))',
			self::TOKEN_UNION => '\\|',
			self::TOKEN_INTERSECTION => '&',
			self::TOKEN_NULLABLE => '\\?',
			self::TOKEN_NEGATED => '!',

			self::TOKEN_OPEN_PARENTHESES => '\\(',
			self::TOKEN_CLOSE_PARENTHESES => '\\)',
			self::TOKEN_OPEN_ANGLE_BRACKET => '<',
			self::TOKEN_CLOSE_ANGLE_BRACKET => '>',
			self::TOKEN_OPEN_SQUARE_BRACKET => '\\[',
			self::TOKEN_CLOSE_SQUARE_BRACKET => '\\]',
			self::TOKEN_OPEN_CURLY_BRACKET => '\\{',
			self::TOKEN_CLOSE_CURLY_BRACKET => '\\}',

			self::TOKEN_COMMA => ',',
			self::TOKEN_COMMENT => '\/\/[^\\r\\n]*(?=\n|\r|\*/)',
			self::TOKEN_VARIADIC => '\\.\\.\\.',
			self::TOKEN_DOUBLE_COLON => '::',
			self::TOKEN_DOUBLE_ARROW => '=>',
			self::TOKEN_ARROW => '->',
			self::TOKEN_EQUAL => '=',
			self::TOKEN_COLON => ':',

			self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)\\x20?+',
			self::TOKEN_CLOSE_PHPDOC => '\\*/',
			self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+',
			self::TOKEN_DOCTRINE_TAG => '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*',
			self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?',

			self::TOKEN_FLOAT => '[+\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\-]?[0-9]++(_[0-9]++)*))',
			self::TOKEN_INTEGER => '[+\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))',
			self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'',
			self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"',
			self::TOKEN_DOCTRINE_ANNOTATION_STRING => '"(?:""|[^"])*+"',

			self::TOKEN_WILDCARD => '\\*',

			// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
			self::TOKEN_OTHER => '(?:(?!\\*/)[^\\s])++',
		];

		foreach ($patterns as $type => &$pattern) {
			$pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')';
		}

		return '~' . implode('|', $patterns) . '~Asi';
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use PHPStan\PhpDocParser\Ast;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\ParserConfig;
use function str_replace;
use function strtolower;

class ConstExprParser
{

	private ParserConfig $config;

	private bool $parseDoctrineStrings;

	public function __construct(
		ParserConfig $config
	)
	{
		$this->config = $config;
		$this->parseDoctrineStrings = false;
	}

	/**
	 * @internal
	 */
	public function toDoctrine(): self
	{
		$self = new self($this->config);
		$self->parseDoctrineStrings = true;
		return $self;
	}

	public function parse(TokenIterator $tokens): Ast\ConstExpr\ConstExprNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) {
			$value = $tokens->currentTokenValue();
			$tokens->next();

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)),
				$startLine,
				$startIndex,
			);
		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
			$value = $tokens->currentTokenValue();
			$tokens->next();

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)),
				$startLine,
				$startIndex,
			);
		}

		if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
			$value = $tokens->currentTokenValue();
			$tokens->next();

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)),
				$startLine,
				$startIndex,
			);
		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
			if ($this->parseDoctrineStrings) {
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
					throw new ParserException(
						$tokens->currentTokenValue(),
						$tokens->currentTokenType(),
						$tokens->currentTokenOffset(),
						Lexer::TOKEN_DOUBLE_QUOTED_STRING,
						null,
						$tokens->currentTokenLine(),
					);
				}

				$value = $tokens->currentTokenValue();
				$tokens->next();

				return $this->enrichWithAttributes(
					$tokens,
					$this->parseDoctrineString($value, $tokens),
					$startLine,
					$startIndex,
				);
			}

			$value = StringUnescaper::unescapeString($tokens->currentTokenValue());
			$type = $tokens->currentTokenType();
			$tokens->next();

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\ConstExpr\ConstExprStringNode(
					$value,
					$type === Lexer::TOKEN_SINGLE_QUOTED_STRING
						? Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED
						: Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED,
				),
				$startLine,
				$startIndex,
			);

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
			$identifier = $tokens->currentTokenValue();
			$tokens->next();

			switch (strtolower($identifier)) {
				case 'true':
					return $this->enrichWithAttributes(
						$tokens,
						new Ast\ConstExpr\ConstExprTrueNode(),
						$startLine,
						$startIndex,
					);
				case 'false':
					return $this->enrichWithAttributes(
						$tokens,
						new Ast\ConstExpr\ConstExprFalseNode(),
						$startLine,
						$startIndex,
					);
				case 'null':
					return $this->enrichWithAttributes(
						$tokens,
						new Ast\ConstExpr\ConstExprNullNode(),
						$startLine,
						$startIndex,
					);
				case 'array':
					$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
					return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex);
			}

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
				$classConstantName = '';
				$lastType = null;
				while (true) {
					if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) {
						$classConstantName .= $tokens->currentTokenValue();
						$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
						$lastType = Lexer::TOKEN_IDENTIFIER;

						continue;
					}

					if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
						$classConstantName .= '*';
						$lastType = Lexer::TOKEN_WILDCARD;

						if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') {
							break;
						}

						continue;
					}

					if ($lastType === null) {
						// trigger parse error if nothing valid was consumed
						$tokens->consumeTokenType(Lexer::TOKEN_WILDCARD);
					}

					break;
				}

				return $this->enrichWithAttributes(
					$tokens,
					new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName),
					$startLine,
					$startIndex,
				);

			}

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\ConstExpr\ConstFetchNode('', $identifier),
				$startLine,
				$startIndex,
			);

		} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
			return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex);
		}

		throw new ParserException(
			$tokens->currentTokenValue(),
			$tokens->currentTokenType(),
			$tokens->currentTokenOffset(),
			Lexer::TOKEN_IDENTIFIER,
			null,
			$tokens->currentTokenLine(),
		);
	}


	private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex): Ast\ConstExpr\ConstExprArrayNode
	{
		$items = [];

		$startLine = $tokens->currentTokenLine();

		if (!$tokens->tryConsumeTokenType($endToken)) {
			do {
				$items[] = $this->parseArrayItem($tokens);
			} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken));
			$tokens->consumeTokenType($endToken);
		}

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\ConstExpr\ConstExprArrayNode($items),
			$startLine,
			$startIndex,
		);
	}


	/**
	 * This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
	 * to the next token.
	 */
	public function parseDoctrineString(string $text, TokenIterator $tokens): Ast\ConstExpr\DoctrineConstExprStringNode
	{
		// Because of how Lexer works, a valid Doctrine string
		// can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING
		while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
			$text .= $tokens->currentTokenValue();
			$tokens->next();
		}

		return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text));
	}


	private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		$expr = $this->parse($tokens);

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) {
			$key = $expr;
			$value = $this->parse($tokens);

		} else {
			$key = null;
			$value = $expr;
		}

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\ConstExpr\ConstExprArrayItemNode($key, $value),
			$startLine,
			$startIndex,
		);
	}

	/**
	 * @template T of Ast\ConstExpr\ConstExprNode
	 * @param T $node
	 * @return T
	 */
	private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode
	{
		if ($this->config->useLinesAttributes) {
			$node->setAttribute(Ast\Attribute::START_LINE, $startLine);
			$node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
		}

		if ($this->config->useIndexAttributes) {
			$node->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
			$node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
		}

		return $node;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use Exception;
use PHPStan\PhpDocParser\Lexer\Lexer;
use function assert;
use function json_encode;
use function sprintf;
use const JSON_INVALID_UTF8_SUBSTITUTE;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;

class ParserException extends Exception
{

	private string $currentTokenValue;

	private int $currentTokenType;

	private int $currentOffset;

	private int $expectedTokenType;

	private ?string $expectedTokenValue;

	private ?int $currentTokenLine;

	public function __construct(
		string $currentTokenValue,
		int $currentTokenType,
		int $currentOffset,
		int $expectedTokenType,
		?string $expectedTokenValue,
		?int $currentTokenLine
	)
	{
		$this->currentTokenValue = $currentTokenValue;
		$this->currentTokenType = $currentTokenType;
		$this->currentOffset = $currentOffset;
		$this->expectedTokenType = $expectedTokenType;
		$this->expectedTokenValue = $expectedTokenValue;
		$this->currentTokenLine = $currentTokenLine;

		parent::__construct(sprintf(
			'Unexpected token %s, expected %s%s at offset %d%s',
			$this->formatValue($currentTokenValue),
			Lexer::TOKEN_LABELS[$expectedTokenType],
			$expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '',
			$currentOffset,
			$currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine),
		));
	}


	public function getCurrentTokenValue(): string
	{
		return $this->currentTokenValue;
	}


	public function getCurrentTokenType(): int
	{
		return $this->currentTokenType;
	}


	public function getCurrentOffset(): int
	{
		return $this->currentOffset;
	}


	public function getExpectedTokenType(): int
	{
		return $this->expectedTokenType;
	}


	public function getExpectedTokenValue(): ?string
	{
		return $this->expectedTokenValue;
	}


	public function getCurrentTokenLine(): ?int
	{
		return $this->currentTokenLine;
	}


	private function formatValue(string $value): string
	{
		$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);
		assert($json !== false);

		return $json;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use LogicException;
use PHPStan\PhpDocParser\Ast;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\ParserConfig;
use PHPStan\ShouldNotHappenException;
use function array_key_exists;
use function count;
use function rtrim;
use function str_replace;
use function trim;

/**
 * @phpstan-import-type ValueType from Doctrine\DoctrineArgument as DoctrineValueType
 */
class PhpDocParser
{

	private const DISALLOWED_DESCRIPTION_START_TOKENS = [
		Lexer::TOKEN_UNION,
		Lexer::TOKEN_INTERSECTION,
	];

	private ParserConfig $config;

	private TypeParser $typeParser;

	private ConstExprParser $constantExprParser;

	private ConstExprParser $doctrineConstantExprParser;

	public function __construct(
		ParserConfig $config,
		TypeParser $typeParser,
		ConstExprParser $constantExprParser
	)
	{
		$this->config = $config;
		$this->typeParser = $typeParser;
		$this->constantExprParser = $constantExprParser;
		$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();
	}


	public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC);
		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);

		$children = [];

		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
			$lastChild = $this->parseChild($tokens);
			$children[] = $lastChild;
			while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
				if (
					$lastChild instanceof Ast\PhpDoc\PhpDocTagNode
					&& (
						$lastChild->value instanceof Doctrine\DoctrineTagValueNode
						|| $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode
					)
				) {
					$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
					if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
						break;
					}
					$lastChild = $this->parseChild($tokens);
					$children[] = $lastChild;
					continue;
				}

				if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
					break;
				}
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
					break;
				}

				$lastChild = $this->parseChild($tokens);
				$children[] = $lastChild;
			}
		}

		try {
			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC);
		} catch (ParserException $e) {
			$name = '';
			$startLine = $tokens->currentTokenLine();
			$startIndex = $tokens->currentTokenIndex();
			if (count($children) > 0) {
				$lastChild = $children[count($children) - 1];
				if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode) {
					$name = $lastChild->name;
					$startLine = $tokens->currentTokenLine();
					$startIndex = $tokens->currentTokenIndex();
				}
			}

			$tag = new Ast\PhpDoc\PhpDocTagNode(
				$name,
				$this->enrichWithAttributes(
					$tokens,
					new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e),
					$startLine,
					$startIndex,
				),
			);

			$tokens->forwardToTheEnd();

			$comments = $tokens->flushComments();
			if ($comments !== []) {
				throw new LogicException('Comments should already be flushed');
			}

			return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);
		}

		$comments = $tokens->flushComments();
		if ($comments !== []) {
			throw new LogicException('Comments should already be flushed');
		}

		return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode($children), 1, 0);
	}


	/** @phpstan-impure */
	private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
	{
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
			$startLine = $tokens->currentTokenLine();
			$startIndex = $tokens->currentTokenIndex();
			return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex);
		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) {
			$startLine = $tokens->currentTokenLine();
			$startIndex = $tokens->currentTokenIndex();
			$tag = $tokens->currentTokenValue();
			$tokens->next();

			$tagStartLine = $tokens->currentTokenLine();
			$tagStartIndex = $tokens->currentTokenIndex();

			return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocTagNode(
				$tag,
				$this->enrichWithAttributes(
					$tokens,
					$this->parseDoctrineTagValue($tokens, $tag),
					$tagStartLine,
					$tagStartIndex,
				),
			), $startLine, $startIndex);
		}

		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		$text = $this->parseText($tokens);

		return $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex);
	}

	/**
	 * @template T of Ast\Node
	 * @param T $tag
	 * @return T
	 */
	private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node
	{
		if ($this->config->useLinesAttributes) {
			$tag->setAttribute(Ast\Attribute::START_LINE, $startLine);
			$tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
		}

		if ($this->config->useIndexAttributes) {
			$tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
			$tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
		}

		return $tag;
	}


	private function parseText(TokenIterator $tokens): Ast\PhpDoc\PhpDocTextNode
	{
		$text = '';

		$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];

		$savepoint = false;

		// if the next token is EOL, everything below is skipped and empty string is returned
		while (true) {
			$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
			$text .= $tmpText;

			// stop if we're not at EOL - meaning it's the end of PHPDoc
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {
				break;
			}

			if (!$savepoint) {
				$tokens->pushSavePoint();
				$savepoint = true;
			} elseif ($tmpText !== '') {
				$tokens->dropSavePoint();
				$tokens->pushSavePoint();
			}

			$tokens->pushSavePoint();
			$tokens->next();

			// if we're at EOL, check what's next
			// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
				$tokens->rollback();
				break;
			}

			// otherwise if the next is text, continue building the description string

			$tokens->dropSavePoint();
			$text .= $tokens->getDetectedNewline() ?? "\n";
		}

		if ($savepoint) {
			$tokens->rollback();
			$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
		}

		return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t"));
	}


	private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens): string
	{
		$text = '';

		$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];

		$savepoint = false;

		// if the next token is EOL, everything below is skipped and empty string is returned
		while (true) {
			$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
			$text .= $tmpText;

			// stop if we're not at EOL - meaning it's the end of PHPDoc
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {
				if (!$tokens->isPrecededByHorizontalWhitespace()) {
					return trim($text . $this->parseText($tokens)->text, " \t");
				}
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
					$tokens->pushSavePoint();
					$child = $this->parseChild($tokens);
					if ($child instanceof Ast\PhpDoc\PhpDocTagNode) {
						if (
							$child->value instanceof Ast\PhpDoc\GenericTagValueNode
							|| $child->value instanceof Doctrine\DoctrineTagValueNode
						) {
							$tokens->rollback();
							break;
						}
						if ($child->value instanceof Ast\PhpDoc\InvalidTagValueNode) {
							$tokens->rollback();
							$tokens->pushSavePoint();
							$tokens->next();
							if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
								$tokens->rollback();
								break;
							}
							$tokens->rollback();
							return trim($text . $this->parseText($tokens)->text, " \t");
						}
					}

					$tokens->rollback();
					return trim($text . $this->parseText($tokens)->text, " \t");
				}
				break;
			}

			if (!$savepoint) {
				$tokens->pushSavePoint();
				$savepoint = true;
			} elseif ($tmpText !== '') {
				$tokens->dropSavePoint();
				$tokens->pushSavePoint();
			}

			$tokens->pushSavePoint();
			$tokens->next();

			// if we're at EOL, check what's next
			// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
				$tokens->rollback();
				break;
			}

			// otherwise if the next is text, continue building the description string

			$tokens->dropSavePoint();
			$text .= $tokens->getDetectedNewline() ?? "\n";
		}

		if ($savepoint) {
			$tokens->rollback();
			$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
		}

		return trim($text, " \t");
	}


	public function parseTag(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagNode
	{
		$tag = $tokens->currentTokenValue();
		$tokens->next();
		$value = $this->parseTagValue($tokens, $tag);

		return new Ast\PhpDoc\PhpDocTagNode($tag, $value);
	}


	public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		try {
			$tokens->pushSavePoint();

			switch ($tag) {
				case '@param':
				case '@phpstan-param':
				case '@psalm-param':
				case '@phan-param':
					$tagValue = $this->parseParamTagValue($tokens);
					break;

				case '@param-immediately-invoked-callable':
				case '@phpstan-param-immediately-invoked-callable':
					$tagValue = $this->parseParamImmediatelyInvokedCallableTagValue($tokens);
					break;

				case '@param-later-invoked-callable':
				case '@phpstan-param-later-invoked-callable':
					$tagValue = $this->parseParamLaterInvokedCallableTagValue($tokens);
					break;

				case '@param-closure-this':
				case '@phpstan-param-closure-this':
					$tagValue = $this->parseParamClosureThisTagValue($tokens);
					break;

				case '@pure-unless-callable-is-impure':
				case '@phpstan-pure-unless-callable-is-impure':
					$tagValue = $this->parsePureUnlessCallableIsImpureTagValue($tokens);
					break;

				case '@var':
				case '@phpstan-var':
				case '@psalm-var':
				case '@phan-var':
					$tagValue = $this->parseVarTagValue($tokens);
					break;

				case '@return':
				case '@phpstan-return':
				case '@psalm-return':
				case '@phan-return':
				case '@phan-real-return':
					$tagValue = $this->parseReturnTagValue($tokens);
					break;

				case '@throws':
				case '@phpstan-throws':
					$tagValue = $this->parseThrowsTagValue($tokens);
					break;

				case '@mixin':
				case '@phan-mixin':
					$tagValue = $this->parseMixinTagValue($tokens);
					break;

				case '@psalm-require-extends':
				case '@phpstan-require-extends':
					$tagValue = $this->parseRequireExtendsTagValue($tokens);
					break;

				case '@psalm-require-implements':
				case '@phpstan-require-implements':
					$tagValue = $this->parseRequireImplementsTagValue($tokens);
					break;

				case '@psalm-inheritors':
				case '@phpstan-sealed':
					$tagValue = $this->parseSealedTagValue($tokens);
					break;

				case '@deprecated':
					$tagValue = $this->parseDeprecatedTagValue($tokens);
					break;

				case '@property':
				case '@property-read':
				case '@property-write':
				case '@phpstan-property':
				case '@phpstan-property-read':
				case '@phpstan-property-write':
				case '@psalm-property':
				case '@psalm-property-read':
				case '@psalm-property-write':
				case '@phan-property':
				case '@phan-property-read':
				case '@phan-property-write':
					$tagValue = $this->parsePropertyTagValue($tokens);
					break;

				case '@method':
				case '@phpstan-method':
				case '@psalm-method':
				case '@phan-method':
					$tagValue = $this->parseMethodTagValue($tokens);
					break;

				case '@template':
				case '@phpstan-template':
				case '@psalm-template':
				case '@phan-template':
				case '@template-covariant':
				case '@phpstan-template-covariant':
				case '@psalm-template-covariant':
				case '@template-contravariant':
				case '@phpstan-template-contravariant':
				case '@psalm-template-contravariant':
					$tagValue = $this->typeParser->parseTemplateTagValue(
						$tokens,
						fn ($tokens) => $this->parseOptionalDescription($tokens, true),
					);
					break;

				case '@extends':
				case '@phpstan-extends':
				case '@phan-extends':
				case '@phan-inherits':
				case '@template-extends':
					$tagValue = $this->parseExtendsTagValue('@extends', $tokens);
					break;

				case '@implements':
				case '@phpstan-implements':
				case '@template-implements':
					$tagValue = $this->parseExtendsTagValue('@implements', $tokens);
					break;

				case '@use':
				case '@phpstan-use':
				case '@template-use':
					$tagValue = $this->parseExtendsTagValue('@use', $tokens);
					break;

				case '@phpstan-type':
				case '@psalm-type':
				case '@phan-type':
					$tagValue = $this->parseTypeAliasTagValue($tokens);
					break;

				case '@phpstan-import-type':
				case '@psalm-import-type':
					$tagValue = $this->parseTypeAliasImportTagValue($tokens);
					break;

				case '@phpstan-assert':
				case '@phpstan-assert-if-true':
				case '@phpstan-assert-if-false':
				case '@psalm-assert':
				case '@psalm-assert-if-true':
				case '@psalm-assert-if-false':
				case '@phan-assert':
				case '@phan-assert-if-true':
				case '@phan-assert-if-false':
					$tagValue = $this->parseAssertTagValue($tokens);
					break;

				case '@phpstan-this-out':
				case '@phpstan-self-out':
				case '@psalm-this-out':
				case '@psalm-self-out':
					$tagValue = $this->parseSelfOutTagValue($tokens);
					break;

				case '@param-out':
				case '@phpstan-param-out':
				case '@psalm-param-out':
					$tagValue = $this->parseParamOutTagValue($tokens);
					break;

				default:
					if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
						$tagValue = $this->parseDoctrineTagValue($tokens, $tag);
					} else {
						$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));
					}
					break;
			}

			$tokens->dropSavePoint();

		} catch (ParserException $e) {
			$tokens->rollback();
			$tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens, false), $e);
		}

		return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex);
	}


	private function parseDoctrineTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		return new Doctrine\DoctrineTagValueNode(
			$this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, false)),
				$startLine,
				$startIndex,
			),
			$this->parseOptionalDescriptionAfterDoctrineTag($tokens),
		);
	}


	/**
	 * @return list<Doctrine\DoctrineArgument>
	 */
	private function parseDoctrineArguments(TokenIterator $tokens, bool $deep): array
	{
		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
			return [];
		}

		if (!$deep) {
			$tokens->addEndOfLineToSkippedTokens();
		}

		$arguments = [];

		try {
			$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);

			do {
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
					break;
				}
				$arguments[] = $this->parseDoctrineArgument($tokens);
			} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
		} finally {
			if (!$deep) {
				$tokens->removeEndOfLineFromSkippedTokens();
			}
		}

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);

		return $arguments;
	}


	private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\DoctrineArgument
	{
		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
			$startLine = $tokens->currentTokenLine();
			$startIndex = $tokens->currentTokenIndex();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
				$startLine,
				$startIndex,
			);
		}

		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		try {
			$tokens->pushSavePoint();
			$currentValue = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

			$key = $this->enrichWithAttributes(
				$tokens,
				new IdentifierTypeNode($currentValue),
				$startLine,
				$startIndex,
			);
			$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);

			$value = $this->parseDoctrineArgumentValue($tokens);

			$tokens->dropSavePoint();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArgument($key, $value),
				$startLine,
				$startIndex,
			);
		} catch (ParserException $e) {
			$tokens->rollback();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
				$startLine,
				$startIndex,
			);
		}
	}


	/**
	 * @return DoctrineValueType
	 */
	private function parseDoctrineArgumentValue(TokenIterator $tokens)
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) {
			$name = $tokens->currentTokenValue();
			$tokens->next();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, true)),
				$startLine,
				$startIndex,
			);
		}

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {
			$items = [];
			do {
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
					break;
				}
				$items[] = $this->parseDoctrineArrayItem($tokens);
			} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));

			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArray($items),
				$startLine,
				$startIndex,
			);
		}

		$currentTokenValue = $tokens->currentTokenValue();
		$tokens->pushSavePoint(); // because of ConstFetchNode
		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
			$identifier = $this->enrichWithAttributes(
				$tokens,
				new Ast\Type\IdentifierTypeNode($currentTokenValue),
				$startLine,
				$startIndex,
			);
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
				$tokens->dropSavePoint();
				return $identifier;
			}

			$tokens->rollback(); // because of ConstFetchNode
		} else {
			$tokens->dropSavePoint(); // because of ConstFetchNode
		}

		$currentTokenValue = $tokens->currentTokenValue();
		$currentTokenType = $tokens->currentTokenType();
		$currentTokenOffset = $tokens->currentTokenOffset();
		$currentTokenLine = $tokens->currentTokenLine();

		try {
			$constExpr = $this->doctrineConstantExprParser->parse($tokens);
			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
				throw new ParserException(
					$currentTokenValue,
					$currentTokenType,
					$currentTokenOffset,
					Lexer::TOKEN_IDENTIFIER,
					null,
					$currentTokenLine,
				);
			}

			return $constExpr;
		} catch (LogicException $e) {
			throw new ParserException(
				$currentTokenValue,
				$currentTokenType,
				$currentTokenOffset,
				Lexer::TOKEN_IDENTIFIER,
				null,
				$currentTokenLine,
			);
		}
	}


	private function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\DoctrineArrayItem
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		try {
			$tokens->pushSavePoint();

			$key = $this->parseDoctrineArrayKey($tokens);
			if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {
				if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) {
					$tokens->consumeTokenType(Lexer::TOKEN_EQUAL); // will throw exception
				}
			}

			$value = $this->parseDoctrineArgumentValue($tokens);

			$tokens->dropSavePoint();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArrayItem($key, $value),
				$startLine,
				$startIndex,
			);
		} catch (ParserException $e) {
			$tokens->rollback();

			return $this->enrichWithAttributes(
				$tokens,
				new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)),
				$startLine,
				$startIndex,
			);
		}
	}


	/**
	 * @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode
	 */
	private function parseDoctrineArrayKey(TokenIterator $tokens)
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
			$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
			$key = $this->doctrineConstantExprParser->parseDoctrineString($tokens->currentTokenValue(), $tokens);

			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
			$value = $tokens->currentTokenValue();
			$tokens->next();
			$key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens);

		} else {
			$currentTokenValue = $tokens->currentTokenValue();
			$tokens->pushSavePoint(); // because of ConstFetchNode
			if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
				$tokens->dropSavePoint();
				throw new ParserException(
					$tokens->currentTokenValue(),
					$tokens->currentTokenType(),
					$tokens->currentTokenOffset(),
					Lexer::TOKEN_IDENTIFIER,
					null,
					$tokens->currentTokenLine(),
				);
			}

			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
				$tokens->dropSavePoint();

				return $this->enrichWithAttributes(
					$tokens,
					new IdentifierTypeNode($currentTokenValue),
					$startLine,
					$startIndex,
				);
			}

			$tokens->rollback();
			$constExpr = $this->doctrineConstantExprParser->parse($tokens);
			if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
				throw new ParserException(
					$tokens->currentTokenValue(),
					$tokens->currentTokenType(),
					$tokens->currentTokenOffset(),
					Lexer::TOKEN_IDENTIFIER,
					null,
					$tokens->currentTokenLine(),
				);
			}

			return $constExpr;
		}

		return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
	}


	/**
	 * @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode
	 */
	private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
	{
		if (
			$tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE)
		) {
			$type = null;
		} else {
			$type = $this->typeParser->parse($tokens);
		}

		$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
		$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		if ($type !== null) {
			return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);
		}

		return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference);
	}


	private function parseParamImmediatelyInvokedCallableTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode
	{
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		return new Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode($parameterName, $description);
	}


	private function parseParamLaterInvokedCallableTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode
	{
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		return new Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode($parameterName, $description);
	}


	private function parseParamClosureThisTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamClosureThisTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		return new Ast\PhpDoc\ParamClosureThisTagValueNode($type, $parameterName, $description);
	}

	private function parsePureUnlessCallableIsImpureTagValue(TokenIterator $tokens): Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode
	{
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		return new Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode($parameterName, $description);
	}

	private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$variableName = $this->parseOptionalVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, $variableName === '');
		return new Ast\PhpDoc\VarTagValueNode($type, $variableName, $description);
	}


	private function parseReturnTagValue(TokenIterator $tokens): Ast\PhpDoc\ReturnTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\ReturnTagValueNode($type, $description);
	}


	private function parseThrowsTagValue(TokenIterator $tokens): Ast\PhpDoc\ThrowsTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\ThrowsTagValueNode($type, $description);
	}

	private function parseMixinTagValue(TokenIterator $tokens): Ast\PhpDoc\MixinTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\MixinTagValueNode($type, $description);
	}

	private function parseRequireExtendsTagValue(TokenIterator $tokens): Ast\PhpDoc\RequireExtendsTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\RequireExtendsTagValueNode($type, $description);
	}

	private function parseRequireImplementsTagValue(TokenIterator $tokens): Ast\PhpDoc\RequireImplementsTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\RequireImplementsTagValueNode($type, $description);
	}

	private function parseSealedTagValue(TokenIterator $tokens): Ast\PhpDoc\SealedTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);
		return new Ast\PhpDoc\SealedTagValueNode($type, $description);
	}

	private function parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode
	{
		$description = $this->parseOptionalDescription($tokens, false);
		return new Ast\PhpDoc\DeprecatedTagValueNode($description);
	}


	private function parsePropertyTagValue(TokenIterator $tokens): Ast\PhpDoc\PropertyTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);
		return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description);
	}


	private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueNode
	{
		$staticKeywordOrReturnTypeOrMethodName = $this->typeParser->parse($tokens);

		if ($staticKeywordOrReturnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode && $staticKeywordOrReturnTypeOrMethodName->name === 'static') {
			$isStatic = true;
			$returnTypeOrMethodName = $this->typeParser->parse($tokens);

		} else {
			$isStatic = false;
			$returnTypeOrMethodName = $staticKeywordOrReturnTypeOrMethodName;
		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
			$returnType = $returnTypeOrMethodName;
			$methodName = $tokens->currentTokenValue();
			$tokens->next();

		} elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) {
			$returnType = $isStatic ? $staticKeywordOrReturnTypeOrMethodName : null;
			$methodName = $returnTypeOrMethodName->name;
			$isStatic = false;

		} else {
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); // will throw exception
			exit;
		}

		$templateTypes = [];

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
			do {
				$startLine = $tokens->currentTokenLine();
				$startIndex = $tokens->currentTokenIndex();
				$templateTypes[] = $this->enrichWithAttributes(
					$tokens,
					$this->typeParser->parseTemplateTagValue($tokens),
					$startLine,
					$startIndex,
				);
			} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
		}

		$parameters = [];
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
			$parameters[] = $this->parseMethodTagValueParameter($tokens);
			while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
				$parameters[] = $this->parseMethodTagValueParameter($tokens);
			}
		}
		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);

		$description = $this->parseOptionalDescription($tokens, false);
		return new Ast\PhpDoc\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes);
	}

	private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueParameterNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		switch ($tokens->currentTokenType()) {
			case Lexer::TOKEN_IDENTIFIER:
			case Lexer::TOKEN_OPEN_PARENTHESES:
			case Lexer::TOKEN_NULLABLE:
				$parameterType = $this->typeParser->parse($tokens);
				break;

			default:
				$parameterType = null;
		}

		$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
		$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);

		$parameterName = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {
			$defaultValue = $this->constantExprParser->parse($tokens);

		} else {
			$defaultValue = null;
		}

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue),
			$startLine,
			$startIndex,
		);
	}

	private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		$baseType = new IdentifierTypeNode($tokens->currentTokenValue());
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

		$type = $this->typeParser->parseGeneric(
			$tokens,
			$this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex),
		);

		$description = $this->parseOptionalDescription($tokens, true);

		switch ($tagName) {
			case '@extends':
				return new Ast\PhpDoc\ExtendsTagValueNode($type, $description);
			case '@implements':
				return new Ast\PhpDoc\ImplementsTagValueNode($type, $description);
			case '@use':
				return new Ast\PhpDoc\UsesTagValueNode($type, $description);
		}

		throw new ShouldNotHappenException();
	}

	private function parseTypeAliasTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasTagValueNode
	{
		$alias = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

		// support phan-type/psalm-type syntax
		$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);

		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		try {
			$type = $this->typeParser->parse($tokens);
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
				if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
					throw new ParserException(
						$tokens->currentTokenValue(),
						$tokens->currentTokenType(),
						$tokens->currentTokenOffset(),
						Lexer::TOKEN_PHPDOC_EOL,
						null,
						$tokens->currentTokenLine(),
					);
				}
			}

			return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
		} catch (ParserException $e) {
			$this->parseOptionalDescription($tokens, false);
			return new Ast\PhpDoc\TypeAliasTagValueNode(
				$alias,
				$this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex),
			);
		}
	}

	private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasImportTagValueNode
	{
		$importedAlias = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

		$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from');

		$identifierStartLine = $tokens->currentTokenLine();
		$identifierStartIndex = $tokens->currentTokenIndex();
		$importedFrom = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
		$importedFromType = $this->enrichWithAttributes(
			$tokens,
			new IdentifierTypeNode($importedFrom),
			$identifierStartLine,
			$identifierStartIndex,
		);

		$importedAs = null;
		if ($tokens->tryConsumeTokenValue('as')) {
			$importedAs = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
		}

		return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs);
	}

	/**
	 * @return Ast\PhpDoc\AssertTagValueNode|Ast\PhpDoc\AssertTagPropertyValueNode|Ast\PhpDoc\AssertTagMethodValueNode
	 */
	private function parseAssertTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
	{
		$isNegated = $tokens->tryConsumeTokenType(Lexer::TOKEN_NEGATED);
		$isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
		$type = $this->typeParser->parse($tokens);
		$parameter = $this->parseAssertParameter($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		if (array_key_exists('method', $parameter)) {
			return new Ast\PhpDoc\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality);
		} elseif (array_key_exists('property', $parameter)) {
			return new Ast\PhpDoc\AssertTagPropertyValueNode($type, $parameter['parameter'], $parameter['property'], $isNegated, $description, $isEquality);
		}

		return new Ast\PhpDoc\AssertTagValueNode($type, $parameter['parameter'], $isNegated, $description, $isEquality);
	}

	/**
	 * @return array{parameter: string}|array{parameter: string, property: string}|array{parameter: string, method: string}
	 */
	private function parseAssertParameter(TokenIterator $tokens): array
	{
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
			$parameter = '$this';
			$tokens->next();
		} else {
			$parameter = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
			$tokens->consumeTokenType(Lexer::TOKEN_ARROW);

			$propertyOrMethod = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
				$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);

				return ['parameter' => $parameter, 'method' => $propertyOrMethod];
			}

			return ['parameter' => $parameter, 'property' => $propertyOrMethod];
		}

		return ['parameter' => $parameter];
	}

	private function parseSelfOutTagValue(TokenIterator $tokens): Ast\PhpDoc\SelfOutTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$description = $this->parseOptionalDescription($tokens, true);

		return new Ast\PhpDoc\SelfOutTagValueNode($type, $description);
	}

	private function parseParamOutTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamOutTagValueNode
	{
		$type = $this->typeParser->parse($tokens);
		$parameterName = $this->parseRequiredVariableName($tokens);
		$description = $this->parseOptionalDescription($tokens, false);

		return new Ast\PhpDoc\ParamOutTagValueNode($type, $parameterName, $description);
	}

	private function parseOptionalVariableName(TokenIterator $tokens): string
	{
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
			$parameterName = $tokens->currentTokenValue();
			$tokens->next();
		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
			$parameterName = '$this';
			$tokens->next();

		} else {
			$parameterName = '';
		}

		return $parameterName;
	}


	private function parseRequiredVariableName(TokenIterator $tokens): string
	{
		$parameterName = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);

		return $parameterName;
	}

	/**
	 * @param bool $limitStartToken true should be used when the description immediately follows a parsed type
	 */
	private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken): string
	{
		if ($limitStartToken) {
			foreach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) {
				if (!$tokens->isCurrentTokenType($disallowedStartToken)) {
					continue;
				}

				$tokens->consumeTokenType(Lexer::TOKEN_OTHER); // will throw exception
			}

			if (
				!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)
				&& !$tokens->isPrecededByHorizontalWhitespace()
			) {
				$tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception
			}
		}

		return $this->parseText($tokens)->text;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use PHPStan\ShouldNotHappenException;
use function chr;
use function hexdec;
use function octdec;
use function preg_replace_callback;
use function str_replace;
use function substr;

class StringUnescaper
{

	private const REPLACEMENTS = [
		'\\' => '\\',
		'n' => "\n",
		'r' => "\r",
		't' => "\t",
		'f' => "\f",
		'v' => "\v",
		'e' => "\x1B",
	];

	public static function unescapeString(string $string): string
	{
		$quote = $string[0];

		if ($quote === '\'') {
			return str_replace(
				['\\\\', '\\\''],
				['\\', '\''],
				substr($string, 1, -1),
			);
		}

		return self::parseEscapeSequences(substr($string, 1, -1), '"');
	}

	/**
	 * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130
	 */
	private static function parseEscapeSequences(string $str, string $quote): string
	{
		$str = str_replace('\\' . $quote, $quote, $str);

		return preg_replace_callback(
			'~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\{([0-9a-fA-F]+)\})~',
			static function ($matches) {
				$str = $matches[1];

				if (isset(self::REPLACEMENTS[$str])) {
					return self::REPLACEMENTS[$str];
				}
				if ($str[0] === 'x' || $str[0] === 'X') {
					return chr((int) hexdec(substr($str, 1)));
				}
				if ($str[0] === 'u') {
					if (!isset($matches[2])) {
						throw new ShouldNotHappenException();
					}
					return self::codePointToUtf8((int) hexdec($matches[2]));
				}

				return chr((int) octdec($str));
			},
			$str,
		);
	}

	/**
	 * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154
	 */
	private static function codePointToUtf8(int $num): string
	{
		if ($num <= 0x7F) {
			return chr($num);
		}
		if ($num <= 0x7FF) {
			return chr(($num >> 6) + 0xC0)
				. chr(($num & 0x3F) + 0x80);
		}
		if ($num <= 0xFFFF) {
			return chr(($num >> 12) + 0xE0)
				. chr((($num >> 6) & 0x3F) + 0x80)
				. chr(($num & 0x3F) + 0x80);
		}
		if ($num <= 0x1FFFFF) {
			return chr(($num >> 18) + 0xF0)
				. chr((($num >> 12) & 0x3F) + 0x80)
				. chr((($num >> 6) & 0x3F) + 0x80)
				. chr(($num & 0x3F) + 0x80);
		}

		// Invalid UTF-8 codepoint escape sequence: Codepoint too large
		return "\xef\xbf\xbd";
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use LogicException;
use PHPStan\PhpDocParser\Ast\Comment;
use PHPStan\PhpDocParser\Lexer\Lexer;
use function array_pop;
use function assert;
use function count;
use function in_array;
use function strlen;
use function substr;

class TokenIterator
{

	/** @var list<array{string, int, int}> */
	private array $tokens;

	private int $index;

	/** @var list<Comment> */
	private array $comments = [];

	/** @var list<array{int, list<Comment>}> */
	private array $savePoints = [];

	/** @var list<int> */
	private array $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];

	private ?string $newline = null;

	/**
	 * @param list<array{string, int, int}> $tokens
	 */
	public function __construct(array $tokens, int $index = 0)
	{
		$this->tokens = $tokens;
		$this->index = $index;

		$this->skipIrrelevantTokens();
	}


	/**
	 * @return list<array{string, int, int}>
	 */
	public function getTokens(): array
	{
		return $this->tokens;
	}


	public function getContentBetween(int $startPos, int $endPos): string
	{
		if ($startPos < 0 || $endPos > count($this->tokens)) {
			throw new LogicException();
		}

		$content = '';
		for ($i = $startPos; $i < $endPos; $i++) {
			$content .= $this->tokens[$i][Lexer::VALUE_OFFSET];
		}

		return $content;
	}


	public function getTokenCount(): int
	{
		return count($this->tokens);
	}


	public function currentTokenValue(): string
	{
		return $this->tokens[$this->index][Lexer::VALUE_OFFSET];
	}


	public function currentTokenType(): int
	{
		return $this->tokens[$this->index][Lexer::TYPE_OFFSET];
	}


	public function currentTokenOffset(): int
	{
		$offset = 0;
		for ($i = 0; $i < $this->index; $i++) {
			$offset += strlen($this->tokens[$i][Lexer::VALUE_OFFSET]);
		}

		return $offset;
	}


	public function currentTokenLine(): int
	{
		return $this->tokens[$this->index][Lexer::LINE_OFFSET];
	}


	public function currentTokenIndex(): int
	{
		return $this->index;
	}


	public function endIndexOfLastRelevantToken(): int
	{
		$endIndex = $this->currentTokenIndex();
		$endIndex--;
		while (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {
			if (!isset($this->tokens[$endIndex - 1])) {
				break;
			}
			$endIndex--;
		}

		return $endIndex;
	}


	public function isCurrentTokenValue(string $tokenValue): bool
	{
		return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue;
	}


	public function isCurrentTokenType(int ...$tokenType): bool
	{
		return in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true);
	}


	public function isPrecededByHorizontalWhitespace(): bool
	{
		return ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS;
	}


	/**
	 * @throws ParserException
	 */
	public function consumeTokenType(int $tokenType): void
	{
		if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {
			$this->throwError($tokenType);
		}

		if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
			if ($this->newline === null) {
				$this->detectNewline();
			}
		}

		$this->next();
	}


	/**
	 * @throws ParserException
	 */
	public function consumeTokenValue(int $tokenType, string $tokenValue): void
	{
		if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
			$this->throwError($tokenType, $tokenValue);
		}

		$this->next();
	}


	/** @phpstan-impure */
	public function tryConsumeTokenValue(string $tokenValue): bool
	{
		if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
			return false;
		}

		$this->next();

		return true;
	}

	/**
	 * @return list<Comment>
	 */
	public function flushComments(): array
	{
		$res = $this->comments;
		$this->comments = [];
		return $res;
	}

	/** @phpstan-impure */
	public function tryConsumeTokenType(int $tokenType): bool
	{
		if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {
			return false;
		}

		if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
			if ($this->newline === null) {
				$this->detectNewline();
			}
		}

		$this->next();

		return true;
	}


	/**
	 * @deprecated Use skipNewLineTokensAndConsumeComments instead (when parsing a type)
	 */
	public function skipNewLineTokens(): void
	{
		if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
			return;
		}

		do {
			$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
		} while ($foundNewLine === true);
	}


	public function skipNewLineTokensAndConsumeComments(): void
	{
		if ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {
			$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
			$this->next();
		}

		if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
			return;
		}

		do {
			$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
			if ($this->currentTokenType() !== Lexer::TOKEN_COMMENT) {
				continue;
			}

			$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
			$this->next();
		} while ($foundNewLine === true);
	}


	private function detectNewline(): void
	{
		$value = $this->currentTokenValue();
		if (substr($value, 0, 2) === "\r\n") {
			$this->newline = "\r\n";
		} elseif (substr($value, 0, 1) === "\n") {
			$this->newline = "\n";
		}
	}


	public function getSkippedHorizontalWhiteSpaceIfAny(): string
	{
		if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
			return $this->tokens[$this->index - 1][Lexer::VALUE_OFFSET];
		}

		return '';
	}


	/** @phpstan-impure */
	public function joinUntil(int ...$tokenType): string
	{
		$s = '';
		while (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true)) {
			$s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET];
		}
		return $s;
	}


	public function next(): void
	{
		$this->index++;
		$this->skipIrrelevantTokens();
	}


	private function skipIrrelevantTokens(): void
	{
		if (!isset($this->tokens[$this->index])) {
			return;
		}

		while (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {
			if (!isset($this->tokens[$this->index + 1])) {
				break;
			}
			$this->index++;
		}
	}


	public function addEndOfLineToSkippedTokens(): void
	{
		$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL];
	}


	public function removeEndOfLineFromSkippedTokens(): void
	{
		$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
	}

	/** @phpstan-impure */
	public function forwardToTheEnd(): void
	{
		$lastToken = count($this->tokens) - 1;
		$this->index = $lastToken;
	}


	public function pushSavePoint(): void
	{
		$this->savePoints[] = [$this->index, $this->comments];
	}


	public function dropSavePoint(): void
	{
		array_pop($this->savePoints);
	}


	public function rollback(): void
	{
		$savepoint = array_pop($this->savePoints);
		assert($savepoint !== null);
		[$this->index, $this->comments] = $savepoint;
	}


	/**
	 * @throws ParserException
	 */
	private function throwError(int $expectedTokenType, ?string $expectedTokenValue = null): void
	{
		throw new ParserException(
			$this->currentTokenValue(),
			$this->currentTokenType(),
			$this->currentTokenOffset(),
			$expectedTokenType,
			$expectedTokenValue,
			$this->currentTokenLine(),
		);
	}

	/**
	 * Check whether the position is directly preceded by a certain token type.
	 *
	 * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
	 */
	public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType): bool
	{
		$tokens = $this->tokens;
		$pos--;
		for (; $pos >= 0; $pos--) {
			$token = $tokens[$pos];
			$type = $token[Lexer::TYPE_OFFSET];
			if ($type === $expectedTokenType) {
				return true;
			}
			if (!in_array($type, [
				Lexer::TOKEN_HORIZONTAL_WS,
				Lexer::TOKEN_PHPDOC_EOL,
			], true)) {
				break;
			}
		}
		return false;
	}

	/**
	 * Check whether the position is directly followed by a certain token type.
	 *
	 * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
	 */
	public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType): bool
	{
		$tokens = $this->tokens;
		$pos++;
		for ($c = count($tokens); $pos < $c; $pos++) {
			$token = $tokens[$pos];
			$type = $token[Lexer::TYPE_OFFSET];
			if ($type === $expectedTokenType) {
				return true;
			}
			if (!in_array($type, [
				Lexer::TOKEN_HORIZONTAL_WS,
				Lexer::TOKEN_PHPDOC_EOL,
			], true)) {
				break;
			}
		}

		return false;
	}

	public function getDetectedNewline(): ?string
	{
		return $this->newline;
	}

	/**
	 * Whether the given position is immediately surrounded by parenthesis.
	 */
	public function hasParentheses(int $startPos, int $endPos): bool
	{
		return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES)
			&& $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Parser;

use LogicException;
use PHPStan\PhpDocParser\Ast;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\ParserConfig;
use function in_array;
use function str_replace;
use function strlen;
use function strpos;
use function substr_compare;

class TypeParser
{

	private ParserConfig $config;

	private ConstExprParser $constExprParser;

	public function __construct(
		ParserConfig $config,
		ConstExprParser $constExprParser
	)
	{
		$this->config = $config;
		$this->constExprParser = $constExprParser;
	}

	/** @phpstan-impure */
	public function parse(TokenIterator $tokens): Ast\Type\TypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
			$type = $this->parseNullable($tokens);

		} else {
			$type = $this->parseAtomic($tokens);

			$tokens->pushSavePoint();
			$tokens->skipNewLineTokensAndConsumeComments();

			try {
				$enrichedType = $this->enrichTypeOnUnionOrIntersection($tokens, $type);

			} catch (ParserException $parserException) {
				$enrichedType = null;
			}

			if ($enrichedType !== null) {
				$type = $enrichedType;
				$tokens->dropSavePoint();

			} else {
				$tokens->rollback();
				$type = $this->enrichTypeOnUnionOrIntersection($tokens, $type) ?? $type;
			}
		}

		return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
	}

	/** @phpstan-impure */
	private function enrichTypeOnUnionOrIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): ?Ast\Type\TypeNode
	{
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
			return $this->parseUnion($tokens, $type);

		}

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
			return $this->parseIntersection($tokens, $type);
		}

		return null;
	}

	/**
	 * @internal
	 * @template T of Ast\Node
	 * @param T $type
	 * @return T
	 */
	public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
	{
		if ($this->config->useLinesAttributes) {
			$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
			$type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
		}

		$comments = $tokens->flushComments();
		if ($this->config->useCommentsAttributes) {
			$type->setAttribute(Ast\Attribute::COMMENTS, $comments);
		}

		if ($this->config->useIndexAttributes) {
			$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
			$type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
		}

		return $type;
	}

	/** @phpstan-impure */
	private function subParse(TokenIterator $tokens): Ast\Type\TypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
			$type = $this->parseNullable($tokens);

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
			$type = $this->parseConditionalForParameter($tokens, $tokens->currentTokenValue());

		} else {
			$type = $this->parseAtomic($tokens);

			if ($tokens->isCurrentTokenValue('is')) {
				$type = $this->parseConditional($tokens, $type);
			} else {
				$tokens->skipNewLineTokensAndConsumeComments();

				if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
					$type = $this->subParseUnion($tokens, $type);

				} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
					$type = $this->subParseIntersection($tokens, $type);
				}
			}
		}

		return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
	}


	/** @phpstan-impure */
	private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
			$tokens->skipNewLineTokensAndConsumeComments();
			$type = $this->subParse($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();

			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);

			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
			}

			return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
		}

		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
			$type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex);

			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
			}

			return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
		}

		$currentTokenValue = $tokens->currentTokenValue();
		$tokens->pushSavePoint(); // because of ConstFetchNode
		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
			$type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);

			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
				$tokens->dropSavePoint(); // because of ConstFetchNode
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
					$tokens->pushSavePoint();

					$isHtml = $this->isHtml($tokens);
					$tokens->rollback();
					if ($isHtml) {
						return $type;
					}

					$origType = $type;
					$type = $this->tryParseCallable($tokens, $type, true);
					if ($type === $origType) {
						$type = $this->parseGeneric($tokens, $type);

						if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
							$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
						}
					}
				} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
					$type = $this->tryParseCallable($tokens, $type, false);

				} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
					$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);

				} elseif (in_array($type->name, [
					Ast\Type\ArrayShapeNode::KIND_ARRAY,
					Ast\Type\ArrayShapeNode::KIND_LIST,
					Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,
					Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_LIST,
					'object',
				], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
					if ($type->name === 'object') {
						$type = $this->parseObjectShape($tokens);
					} else {
						$type = $this->parseArrayShape($tokens, $type, $type->name);
					}

					if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
						$type = $this->tryParseArrayOrOffsetAccess(
							$tokens,
							$this->enrichWithAttributes($tokens, $type, $startLine, $startIndex),
						);
					}
				}

				return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
			} else {
				$tokens->rollback(); // because of ConstFetchNode
			}
		} else {
			$tokens->dropSavePoint(); // because of ConstFetchNode
		}

		$currentTokenValue = $tokens->currentTokenValue();
		$currentTokenType = $tokens->currentTokenType();
		$currentTokenOffset = $tokens->currentTokenOffset();
		$currentTokenLine = $tokens->currentTokenLine();

		try {
			$constExpr = $this->constExprParser->parse($tokens);
			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
				throw new ParserException(
					$currentTokenValue,
					$currentTokenType,
					$currentTokenOffset,
					Lexer::TOKEN_IDENTIFIER,
					null,
					$currentTokenLine,
				);
			}

			$type = $this->enrichWithAttributes(
				$tokens,
				new Ast\Type\ConstTypeNode($constExpr),
				$startLine,
				$startIndex,
			);
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
			}

			return $type;
		} catch (LogicException $e) {
			throw new ParserException(
				$currentTokenValue,
				$currentTokenType,
				$currentTokenOffset,
				Lexer::TOKEN_IDENTIFIER,
				null,
				$currentTokenLine,
			);
		}
	}


	/** @phpstan-impure */
	private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
	{
		$types = [$type];

		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
			$types[] = $this->parseAtomic($tokens);
			$tokens->pushSavePoint();
			$tokens->skipNewLineTokensAndConsumeComments();
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
				$tokens->rollback();
				break;
			}

			$tokens->dropSavePoint();
		}

		return new Ast\Type\UnionTypeNode($types);
	}


	/** @phpstan-impure */
	private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
	{
		$types = [$type];

		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
			$tokens->skipNewLineTokensAndConsumeComments();
			$types[] = $this->parseAtomic($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
		}

		return new Ast\Type\UnionTypeNode($types);
	}


	/** @phpstan-impure */
	private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
	{
		$types = [$type];

		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
			$types[] = $this->parseAtomic($tokens);
			$tokens->pushSavePoint();
			$tokens->skipNewLineTokensAndConsumeComments();
			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
				$tokens->rollback();
				break;
			}

			$tokens->dropSavePoint();
		}

		return new Ast\Type\IntersectionTypeNode($types);
	}


	/** @phpstan-impure */
	private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
	{
		$types = [$type];

		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
			$tokens->skipNewLineTokensAndConsumeComments();
			$types[] = $this->parseAtomic($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
		}

		return new Ast\Type\IntersectionTypeNode($types);
	}


	/** @phpstan-impure */
	private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subjectType): Ast\Type\TypeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

		$negated = false;
		if ($tokens->isCurrentTokenValue('not')) {
			$negated = true;
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
		}

		$targetType = $this->parse($tokens);

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
		$tokens->skipNewLineTokensAndConsumeComments();

		$ifType = $this->parse($tokens);

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
		$tokens->skipNewLineTokensAndConsumeComments();

		$elseType = $this->subParse($tokens);

		return new Ast\Type\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated);
	}

	/** @phpstan-impure */
	private function parseConditionalForParameter(TokenIterator $tokens, string $parameterName): Ast\Type\TypeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
		$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'is');

		$negated = false;
		if ($tokens->isCurrentTokenValue('not')) {
			$negated = true;
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
		}

		$targetType = $this->parse($tokens);

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
		$tokens->skipNewLineTokensAndConsumeComments();

		$ifType = $this->parse($tokens);

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
		$tokens->skipNewLineTokensAndConsumeComments();

		$elseType = $this->subParse($tokens);

		return new Ast\Type\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated);
	}


	/** @phpstan-impure */
	private function parseNullable(TokenIterator $tokens): Ast\Type\TypeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);

		$type = $this->parseAtomic($tokens);

		return new Ast\Type\NullableTypeNode($type);
	}

	/** @phpstan-impure */
	public function isHtml(TokenIterator $tokens): bool
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);

		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
			return false;
		}

		$htmlTagName = $tokens->currentTokenValue();

		$tokens->next();

		if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
			return false;
		}

		$endTag = '</' . $htmlTagName . '>';
		$endTagSearchOffset = - strlen($endTag);

		while (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) {
			if (
				(
					$tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)
					&& strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== false
				)
				|| substr_compare($tokens->currentTokenValue(), $endTag, $endTagSearchOffset) === 0
			) {
				return true;
			}

			$tokens->next();
		}

		return false;
	}

	/** @phpstan-impure */
	public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType): Ast\Type\GenericTypeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
		$tokens->skipNewLineTokensAndConsumeComments();

		$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
		$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
		$genericTypes = [];
		$variances = [];

		$isFirst = true;
		while (
			$isFirst
			|| $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)
		) {
			$tokens->skipNewLineTokensAndConsumeComments();

			// trailing comma case
			if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
				break;
			}
			$isFirst = false;

			[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
		}

		$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
		if ($startLine !== null && $startIndex !== null) {
			$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
		}

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);

		return $type;
	}


	/**
	 * @phpstan-impure
	 * @return array{Ast\Type\TypeNode, Ast\Type\GenericTypeNode::VARIANCE_*}
	 */
	public function parseGenericTypeArgument(TokenIterator $tokens): array
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
			return [
				$this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex),
				Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT,
			];
		}

		if ($tokens->tryConsumeTokenValue('contravariant')) {
			$variance = Ast\Type\GenericTypeNode::VARIANCE_CONTRAVARIANT;
		} elseif ($tokens->tryConsumeTokenValue('covariant')) {
			$variance = Ast\Type\GenericTypeNode::VARIANCE_COVARIANT;
		} else {
			$variance = Ast\Type\GenericTypeNode::VARIANCE_INVARIANT;
		}

		$type = $this->parse($tokens);
		return [$type, $variance];
	}

	/**
	 * @throws ParserException
	 * @param ?callable(TokenIterator): string $parseDescription
	 */
	public function parseTemplateTagValue(
		TokenIterator $tokens,
		?callable $parseDescription = null
	): TemplateTagValueNode
	{
		$name = $tokens->currentTokenValue();
		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

		$upperBound = $lowerBound = null;

		if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
			$upperBound = $this->parse($tokens);
		}

		if ($tokens->tryConsumeTokenValue('super')) {
			$lowerBound = $this->parse($tokens);
		}

		if ($tokens->tryConsumeTokenValue('=')) {
			$default = $this->parse($tokens);
		} else {
			$default = null;
		}

		if ($parseDescription !== null) {
			$description = $parseDescription($tokens);
		} else {
			$description = '';
		}

		if ($name === '') {
			throw new LogicException('Template tag name cannot be empty.');
		}

		return new Ast\PhpDoc\TemplateTagValueNode($name, $upperBound, $description, $default, $lowerBound);
	}


	/** @phpstan-impure */
	private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier, bool $hasTemplate): Ast\Type\TypeNode
	{
		$templates = $hasTemplate
			? $this->parseCallableTemplates($tokens)
			: [];

		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
		$tokens->skipNewLineTokensAndConsumeComments();

		$parameters = [];
		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
			$parameters[] = $this->parseCallableParameter($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
			while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
				$tokens->skipNewLineTokensAndConsumeComments();
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
					break;
				}
				$parameters[] = $this->parseCallableParameter($tokens);
				$tokens->skipNewLineTokensAndConsumeComments();
			}
		}

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
		$tokens->consumeTokenType(Lexer::TOKEN_COLON);

		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		$returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex);

		return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType, $templates);
	}


	/**
	 * @return Ast\PhpDoc\TemplateTagValueNode[]
	 *
	 * @phpstan-impure
	 */
	private function parseCallableTemplates(TokenIterator $tokens): array
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);

		$templates = [];

		$isFirst = true;
		while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
			$tokens->skipNewLineTokensAndConsumeComments();

			// trailing comma case
			if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
				break;
			}
			$isFirst = false;

			$templates[] = $this->parseCallableTemplateArgument($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
		}

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);

		return $templates;
	}


	private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\PhpDoc\TemplateTagValueNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		return $this->enrichWithAttributes(
			$tokens,
			$this->parseTemplateTagValue($tokens),
			$startLine,
			$startIndex,
		);
	}


	/** @phpstan-impure */
	private function parseCallableParameter(TokenIterator $tokens): Ast\Type\CallableTypeParameterNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		$type = $this->parse($tokens);
		$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
		$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
			$parameterName = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);

		} else {
			$parameterName = '';
		}

		$isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
		return $this->enrichWithAttributes(
			$tokens,
			new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional),
			$startLine,
			$startIndex,
		);
	}


	/** @phpstan-impure */
	private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();
		if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
			return $this->parseNullable($tokens);

		} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
			$type = $this->subParse($tokens);
			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
			}

			return $type;
		} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
			$type = new Ast\Type\ThisTypeNode();
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
					$tokens,
					$type,
					$startLine,
					$startIndex,
				));
			}

			return $type;
		} else {
			$currentTokenValue = $tokens->currentTokenValue();
			$tokens->pushSavePoint(); // because of ConstFetchNode
			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
				$type = new Ast\Type\IdentifierTypeNode($currentTokenValue);

				if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
					if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
						$type = $this->parseGeneric(
							$tokens,
							$this->enrichWithAttributes(
								$tokens,
								$type,
								$startLine,
								$startIndex,
							),
						);
						if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
							$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
								$tokens,
								$type,
								$startLine,
								$startIndex,
							));
						}

					} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
						$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
							$tokens,
							$type,
							$startLine,
							$startIndex,
						));

					} elseif (in_array($type->name, [
						Ast\Type\ArrayShapeNode::KIND_ARRAY,
						Ast\Type\ArrayShapeNode::KIND_LIST,
						Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,
						Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_LIST,
						'object',
					], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
						if ($type->name === 'object') {
							$type = $this->parseObjectShape($tokens);
						} else {
							$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes(
								$tokens,
								$type,
								$startLine,
								$startIndex,
							), $type->name);
						}

						if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
							$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
								$tokens,
								$type,
								$startLine,
								$startIndex,
							));
						}
					}

					return $type;
				} else {
					$tokens->rollback(); // because of ConstFetchNode
				}
			} else {
				$tokens->dropSavePoint(); // because of ConstFetchNode
			}
		}

		$currentTokenValue = $tokens->currentTokenValue();
		$currentTokenType = $tokens->currentTokenType();
		$currentTokenOffset = $tokens->currentTokenOffset();
		$currentTokenLine = $tokens->currentTokenLine();

		try {
			$constExpr = $this->constExprParser->parse($tokens);
			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
				throw new ParserException(
					$currentTokenValue,
					$currentTokenType,
					$currentTokenOffset,
					Lexer::TOKEN_IDENTIFIER,
					null,
					$currentTokenLine,
				);
			}

			$type = $this->enrichWithAttributes(
				$tokens,
				new Ast\Type\ConstTypeNode($constExpr),
				$startLine,
				$startIndex,
			);
			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
			}

			return $type;
		} catch (LogicException $e) {
			throw new ParserException(
				$currentTokenValue,
				$currentTokenType,
				$currentTokenOffset,
				Lexer::TOKEN_IDENTIFIER,
				null,
				$currentTokenLine,
			);
		}
	}


	/** @phpstan-impure */
	private function tryParseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier, bool $hasTemplate): Ast\Type\TypeNode
	{
		try {
			$tokens->pushSavePoint();
			$type = $this->parseCallable($tokens, $identifier, $hasTemplate);
			$tokens->dropSavePoint();

		} catch (ParserException $e) {
			$tokens->rollback();
			$type = $identifier;
		}

		return $type;
	}


	/** @phpstan-impure */
	private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
	{
		$startLine = $type->getAttribute(Ast\Attribute::START_LINE);
		$startIndex = $type->getAttribute(Ast\Attribute::START_INDEX);
		try {
			while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
				$tokens->pushSavePoint();

				$canBeOffsetAccessType = !$tokens->isPrecededByHorizontalWhitespace();
				$tokens->consumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET);

				if ($canBeOffsetAccessType && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET)) {
					$offset = $this->parse($tokens);
					$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
					$tokens->dropSavePoint();
					$type = new Ast\Type\OffsetAccessTypeNode($type, $offset);

					if ($startLine !== null && $startIndex !== null) {
						$type = $this->enrichWithAttributes(
							$tokens,
							$type,
							$startLine,
							$startIndex,
						);
					}
				} else {
					$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
					$tokens->dropSavePoint();
					$type = new Ast\Type\ArrayTypeNode($type);

					if ($startLine !== null && $startIndex !== null) {
						$type = $this->enrichWithAttributes(
							$tokens,
							$type,
							$startLine,
							$startIndex,
						);
					}
				}
			}

		} catch (ParserException $e) {
			$tokens->rollback();
		}

		return $type;
	}


	/**
	 * @phpstan-impure
	 * @param Ast\Type\ArrayShapeNode::KIND_* $kind
	 */
	private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type, string $kind): Ast\Type\ArrayShapeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);

		$items = [];
		$sealed = true;
		$unsealedType = null;

		$done = false;

		do {
			$tokens->skipNewLineTokensAndConsumeComments();

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
				return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
			}

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
				$sealed = false;

				$tokens->skipNewLineTokensAndConsumeComments();
				if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
					if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) {
						$unsealedType = $this->parseArrayShapeUnsealedType($tokens);
					} else {
						$unsealedType = $this->parseListShapeUnsealedType($tokens);
					}
					$tokens->skipNewLineTokensAndConsumeComments();
				}

				$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
				break;
			}

			$items[] = $this->parseArrayShapeItem($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
			if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
				$done = true;
			}
			if ($tokens->currentTokenType() !== Lexer::TOKEN_COMMENT) {
				continue;
			}

			$tokens->next();

		} while (!$done);

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);

		if ($sealed) {
			return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
		}

		return Ast\Type\ArrayShapeNode::createUnsealed($items, $unsealedType, $kind);
	}


	/** @phpstan-impure */
	private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShapeItemNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		// parse any comments above the item
		$tokens->skipNewLineTokensAndConsumeComments();

		try {
			$tokens->pushSavePoint();
			$key = $this->parseArrayShapeKey($tokens);
			$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
			$tokens->consumeTokenType(Lexer::TOKEN_COLON);
			$value = $this->parse($tokens);

			$tokens->dropSavePoint();

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\Type\ArrayShapeItemNode($key, $optional, $value),
				$startLine,
				$startIndex,
			);
		} catch (ParserException $e) {
			$tokens->rollback();
			$value = $this->parse($tokens);

			return $this->enrichWithAttributes(
				$tokens,
				new Ast\Type\ArrayShapeItemNode(null, false, $value),
				$startLine,
				$startIndex,
			);
		}
	}

	/**
	 * @phpstan-impure
	 * @return Ast\ConstExpr\ConstExprIntegerNode|Ast\ConstExpr\ConstExprStringNode|Ast\ConstExpr\ConstFetchNode|Ast\Type\IdentifierTypeNode
	 */
	private function parseArrayShapeKey(TokenIterator $tokens)
	{
		$startIndex = $tokens->currentTokenIndex();
		$startLine = $tokens->currentTokenLine();

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
			$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED);

			$tokens->next();

		} else {
			$identifier = $tokens->currentTokenValue();
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
				$classConstantName = $tokens->currentTokenValue();
				$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);

				$key = new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName);
			} else {
				$key = new Ast\Type\IdentifierTypeNode($identifier);
			}
		}

		return $this->enrichWithAttributes(
			$tokens,
			$key,
			$startLine,
			$startIndex,
		);
	}

	/**
	 * @phpstan-impure
	 */
	private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
		$tokens->skipNewLineTokensAndConsumeComments();

		$valueType = $this->parse($tokens);
		$tokens->skipNewLineTokensAndConsumeComments();

		$keyType = null;
		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
			$tokens->skipNewLineTokensAndConsumeComments();

			$keyType = $valueType;
			$valueType = $this->parse($tokens);
			$tokens->skipNewLineTokensAndConsumeComments();
		}

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, $keyType),
			$startLine,
			$startIndex,
		);
	}

	/**
	 * @phpstan-impure
	 */
	private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
		$tokens->skipNewLineTokensAndConsumeComments();

		$valueType = $this->parse($tokens);
		$tokens->skipNewLineTokensAndConsumeComments();

		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, null),
			$startLine,
			$startIndex,
		);
	}

	/**
	 * @phpstan-impure
	 */
	private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNode
	{
		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);

		$items = [];

		do {
			$tokens->skipNewLineTokensAndConsumeComments();

			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
				return new Ast\Type\ObjectShapeNode($items);
			}

			$items[] = $this->parseObjectShapeItem($tokens);

			$tokens->skipNewLineTokensAndConsumeComments();
		} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));

		$tokens->skipNewLineTokensAndConsumeComments();
		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);

		return new Ast\Type\ObjectShapeNode($items);
	}

	/** @phpstan-impure */
	private function parseObjectShapeItem(TokenIterator $tokens): Ast\Type\ObjectShapeItemNode
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		$tokens->skipNewLineTokensAndConsumeComments();

		$key = $this->parseObjectShapeKey($tokens);
		$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
		$value = $this->parse($tokens);

		return $this->enrichWithAttributes(
			$tokens,
			new Ast\Type\ObjectShapeItemNode($key, $optional, $value),
			$startLine,
			$startIndex,
		);
	}

	/**
	 * @phpstan-impure
	 * @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode
	 */
	private function parseObjectShapeKey(TokenIterator $tokens)
	{
		$startLine = $tokens->currentTokenLine();
		$startIndex = $tokens->currentTokenIndex();

		if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
			$tokens->next();

		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED);
			$tokens->next();

		} else {
			$key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue());
			$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
		}

		return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser;

class ParserConfig
{

	public bool $useLinesAttributes;

	public bool $useIndexAttributes;

	public bool $useCommentsAttributes;

	/**
	 * @param array{lines?: bool, indexes?: bool, comments?: bool} $usedAttributes
	 */
	public function __construct(array $usedAttributes)
	{
		$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
		$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
		$this->useCommentsAttributes = $usedAttributes['comments'] ?? false;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Printer;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 *
 * Implements the Myers diff algorithm.
 *
 * @internal
 */
class DiffElem
{

	public const TYPE_KEEP = 0;
	public const TYPE_REMOVE = 1;
	public const TYPE_ADD = 2;
	public const TYPE_REPLACE = 3;

	/** @var self::TYPE_* */
	public $type;

	/** @var mixed Is null for add operations */
	public $old;

	/** @var mixed Is null for remove operations */
	public $new;

	/**
	 * @param self::TYPE_* $type
	 * @param mixed $old Is null for add operations
	 * @param mixed $new Is null for remove operations
	 */
	public function __construct(int $type, $old, $new)
	{
		$this->type = $type;
		$this->old = $old;
		$this->new = $new;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Printer;

use Exception;
use function array_reverse;
use function count;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 *
 * Implements the Myers diff algorithm.
 *
 * Myers, Eugene W. "An O (ND) difference algorithm and its variations."
 * Algorithmica 1.1 (1986): 251-266.
 *
 * @template T
 * @internal
 */
class Differ
{

	/** @var callable(T, T): bool */
	private $isEqual;

	/**
	 * Create differ over the given equality relation.
	 *
	 * @param callable(T, T): bool $isEqual Equality relation
	 */
	public function __construct(callable $isEqual)
	{
		$this->isEqual = $isEqual;
	}

	/**
	 * Calculate diff (edit script) from $old to $new.
	 *
	 * @param T[] $old Original array
	 * @param T[] $new New array
	 *
	 * @return DiffElem[] Diff (edit script)
	 */
	public function diff(array $old, array $new): array
	{
		[$trace, $x, $y] = $this->calculateTrace($old, $new);
		return $this->extractDiff($trace, $x, $y, $old, $new);
	}

	/**
	 * Calculate diff, including "replace" operations.
	 *
	 * If a sequence of remove operations is followed by the same number of add operations, these
	 * will be coalesced into replace operations.
	 *
	 * @param T[] $old Original array
	 * @param T[] $new New array
	 *
	 * @return DiffElem[] Diff (edit script), including replace operations
	 */
	public function diffWithReplacements(array $old, array $new): array
	{
		return $this->coalesceReplacements($this->diff($old, $new));
	}

	/**
	 * @param T[] $old
	 * @param T[] $new
	 * @return array{array<int, array<int, int>>, int, int}
	 */
	private function calculateTrace(array $old, array $new): array
	{
		$n = count($old);
		$m = count($new);
		$max = $n + $m;
		$v = [1 => 0];
		$trace = [];
		for ($d = 0; $d <= $max; $d++) {
			$trace[] = $v;
			for ($k = -$d; $k <= $d; $k += 2) {
				if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {
					$x = $v[$k + 1];
				} else {
					$x = $v[$k - 1] + 1;
				}

				$y = $x - $k;
				while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) {
					$x++;
					$y++;
				}

				$v[$k] = $x;
				if ($x >= $n && $y >= $m) {
					return [$trace, $x, $y];
				}
			}
		}
		throw new Exception('Should not happen');
	}

	/**
	 * @param array<int, array<int, int>> $trace
	 * @param T[] $old
	 * @param T[] $new
	 * @return DiffElem[]
	 */
	private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array
	{
		$result = [];
		for ($d = count($trace) - 1; $d >= 0; $d--) {
			$v = $trace[$d];
			$k = $x - $y;

			if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {
				$prevK = $k + 1;
			} else {
				$prevK = $k - 1;
			}

			$prevX = $v[$prevK];
			$prevY = $prevX - $prevK;

			while ($x > $prevX && $y > $prevY) {
				$result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]);
				$x--;
				$y--;
			}

			if ($d === 0) {
				break;
			}

			while ($x > $prevX) {
				$result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null);
				$x--;
			}

			while ($y > $prevY) {
				$result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]);
				$y--;
			}
		}
		return array_reverse($result);
	}

	/**
	 * Coalesce equal-length sequences of remove+add into a replace operation.
	 *
	 * @param DiffElem[] $diff
	 * @return DiffElem[]
	 */
	private function coalesceReplacements(array $diff): array
	{
		$newDiff = [];
		$c = count($diff);
		for ($i = 0; $i < $c; $i++) {
			$diffType = $diff[$i]->type;
			if ($diffType !== DiffElem::TYPE_REMOVE) {
				$newDiff[] = $diff[$i];
				continue;
			}

			$j = $i;
			while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) {
				$j++;
			}

			$k = $j;
			while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) {
				$k++;
			}

			if ($j - $i === $k - $j) {
				$len = $j - $i;
				for ($n = 0; $n < $len; $n++) {
					$newDiff[] = new DiffElem(
						DiffElem::TYPE_REPLACE,
						$diff[$i + $n]->old,
						$diff[$j + $n]->new,
					);
				}
			} else {
				for (; $i < $k; $i++) {
					$newDiff[] = $diff[$i];
				}
			}
			$i = $k - 1;
		}
		return $newDiff;
	}

}
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Printer;

use LogicException;
use PHPStan\PhpDocParser\Ast\Attribute;
use PHPStan\PhpDocParser\Ast\Comment;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagMethodValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagPropertyValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineAnnotation;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArgument;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArray;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArrayItem;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamClosureThisTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamOutTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\SealedTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeUnsealedTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use function array_keys;
use function array_map;
use function assert;
use function count;
use function get_class;
use function get_object_vars;
use function implode;
use function in_array;
use function is_array;
use function preg_match_all;
use function sprintf;
use function str_replace;
use function strlen;
use function strpos;
use function trim;
use const PREG_SET_ORDER;

/**
 * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
 *
 * Copyright (c) 2011, Nikita Popov
 * All rights reserved.
 */
final class Printer
{

	/** @var Differ<Node> */
	private Differ $differ;

	/**
	 * Map From "{$class}->{$subNode}" to string that should be inserted
	 * between elements of this list subnode
	 *
	 * @var array<string, string>
	 */
	private array $listInsertionMap = [
		PhpDocNode::class . '->children' => "\n * ",
		UnionTypeNode::class . '->types' => '|',
		IntersectionTypeNode::class . '->types' => '&',
		ArrayShapeNode::class . '->items' => ', ',
		ObjectShapeNode::class . '->items' => ', ',
		CallableTypeNode::class . '->parameters' => ', ',
		CallableTypeNode::class . '->templateTypes' => ', ',
		GenericTypeNode::class . '->genericTypes' => ', ',
		ConstExprArrayNode::class . '->items' => ', ',
		MethodTagValueNode::class . '->parameters' => ', ',
		DoctrineArray::class . '->items' => ', ',
		DoctrineAnnotation::class . '->arguments' => ', ',
	];

	/**
	 * [$find, $extraLeft, $extraRight]
	 *
	 * @var array<string, array{string|null, string, string}>
	 */
	private array $emptyListInsertionMap = [
		CallableTypeNode::class . '->parameters' => ['(', '', ''],
		ArrayShapeNode::class . '->items' => ['{', '', ''],
		ObjectShapeNode::class . '->items' => ['{', '', ''],
		DoctrineArray::class . '->items' => ['{', '', ''],
		DoctrineAnnotation::class . '->arguments' => ['(', '', ''],
	];

	/** @var array<string, list<class-string<TypeNode>>> */
	private array $parenthesesMap = [
		CallableTypeNode::class . '->returnType' => [
			CallableTypeNode::class,
			UnionTypeNode::class,
			IntersectionTypeNode::class,
		],
		ArrayTypeNode::class . '->type' => [
			CallableTypeNode::class,
			UnionTypeNode::class,
			IntersectionTypeNode::class,
			ConstTypeNode::class,
			NullableTypeNode::class,
		],
		OffsetAccessTypeNode::class . '->type' => [
			CallableTypeNode::class,
			UnionTypeNode::class,
			IntersectionTypeNode::class,
			NullableTypeNode::class,
		],
	];

	/** @var array<string, list<class-string<TypeNode>>> */
	private array $parenthesesListMap = [
		IntersectionTypeNode::class . '->types' => [
			IntersectionTypeNode::class,
			UnionTypeNode::class,
			NullableTypeNode::class,
		],
		UnionTypeNode::class . '->types' => [
			IntersectionTypeNode::class,
			UnionTypeNode::class,
			NullableTypeNode::class,
		],
	];

	public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens): string
	{
		$this->differ = new Differ(static function ($a, $b) {
			if ($a instanceof Node && $b instanceof Node) {
				return $a === $b->getAttribute(Attribute::ORIGINAL_NODE);
			}

			return false;
		});

		$tokenIndex = 0;
		$result = $this->printArrayFormatPreserving(
			$node->children,
			$originalNode->children,
			$originalTokens,
			$tokenIndex,
			PhpDocNode::class,
			'children',
		);
		if ($result !== null) {
			return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount());
		}

		return $this->print($node);
	}

	public function print(Node $node): string
	{
		if ($node instanceof PhpDocNode) {
			return "/**\n *" . implode("\n *", array_map(
				function (PhpDocChildNode $child): string {
					$s = $this->print($child);
					return $s === '' ? '' : ' ' . $s;
				},
				$node->children,
			)) . "\n */";
		}
		if ($node instanceof PhpDocTextNode) {
			return $node->text;
		}
		if ($node instanceof PhpDocTagNode) {
			if ($node->value instanceof DoctrineTagValueNode) {
				return $this->print($node->value);
			}

			return trim(sprintf('%s %s', $node->name, $this->print($node->value)));
		}
		if ($node instanceof PhpDocTagValueNode) {
			return $this->printTagValue($node);
		}
		if ($node instanceof TypeNode) {
			return $this->printType($node);
		}
		if ($node instanceof ConstExprNode) {
			return $this->printConstExpr($node);
		}
		if ($node instanceof MethodTagValueParameterNode) {
			$type = $node->type !== null ? $this->print($node->type) . ' ' : '';
			$isReference = $node->isReference ? '&' : '';
			$isVariadic = $node->isVariadic ? '...' : '';
			$default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : '';
			return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}";
		}
		if ($node instanceof CallableTypeParameterNode) {
			$type = $this->print($node->type) . ' ';
			$isReference = $node->isReference ? '&' : '';
			$isVariadic = $node->isVariadic ? '...' : '';
			$isOptional = $node->isOptional ? '=' : '';
			return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
		}
		if ($node instanceof ArrayShapeUnsealedTypeNode) {
			if ($node->keyType !== null) {
				return sprintf('<%s, %s>', $this->printType($node->keyType), $this->printType($node->valueType));
			}
			return sprintf('<%s>', $this->printType($node->valueType));
		}
		if ($node instanceof DoctrineAnnotation) {
			return (string) $node;
		}
		if ($node instanceof DoctrineArgument) {
			return (string) $node;
		}
		if ($node instanceof DoctrineArray) {
			return (string) $node;
		}
		if ($node instanceof DoctrineArrayItem) {
			return (string) $node;
		}
		if ($node instanceof ArrayShapeItemNode) {
			if ($node->keyName !== null) {
				return sprintf(
					'%s%s: %s',
					$this->print($node->keyName),
					$node->optional ? '?' : '',
					$this->printType($node->valueType),
				);
			}

			return $this->printType($node->valueType);
		}
		if ($node instanceof ObjectShapeItemNode) {
			if ($node->keyName !== null) {
				return sprintf(
					'%s%s: %s',
					$this->print($node->keyName),
					$node->optional ? '?' : '',
					$this->printType($node->valueType),
				);
			}

			return $this->printType($node->valueType);
		}

		throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
	}

	private function printTagValue(PhpDocTagValueNode $node): string
	{
		// only nodes that contain another node are handled here
		// the rest falls back on (string) $node

		if ($node instanceof AssertTagMethodValueNode) {
			$isNegated = $node->isNegated ? '!' : '';
			$isEquality = $node->isEquality ? '=' : '';
			$type = $this->printType($node->type);
			return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}");
		}
		if ($node instanceof AssertTagPropertyValueNode) {
			$isNegated = $node->isNegated ? '!' : '';
			$isEquality = $node->isEquality ? '=' : '';
			$type = $this->printType($node->type);
			return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}");
		}
		if ($node instanceof AssertTagValueNode) {
			$isNegated = $node->isNegated ? '!' : '';
			$isEquality = $node->isEquality ? '=' : '';
			$type = $this->printType($node->type);
			return trim("{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}");
		}
		if ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof MethodTagValueNode) {
			$static = $node->isStatic ? 'static ' : '';
			$returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : '';
			$parameters = implode(', ', array_map(fn (MethodTagValueParameterNode $parameter): string => $this->print($parameter), $node->parameters));
			$description = $node->description !== '' ? " {$node->description}" : '';
			$templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateTag): string => $this->print($templateTag), $node->templateTypes)) . '>' : '';
			return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}";
		}
		if ($node instanceof MixinTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof RequireExtendsTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof RequireImplementsTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof SealedTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof ParamOutTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->parameterName} {$node->description}");
		}
		if ($node instanceof ParamTagValueNode) {
			$reference = $node->isReference ? '&' : '';
			$variadic = $node->isVariadic ? '...' : '';
			$type = $this->printType($node->type);
			return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}");
		}
		if ($node instanceof ParamImmediatelyInvokedCallableTagValueNode) {
			return trim("{$node->parameterName} {$node->description}");
		}
		if ($node instanceof ParamLaterInvokedCallableTagValueNode) {
			return trim("{$node->parameterName} {$node->description}");
		}
		if ($node instanceof ParamClosureThisTagValueNode) {
			return trim("{$node->type} {$node->parameterName} {$node->description}");
		}
		if ($node instanceof PureUnlessCallableIsImpureTagValueNode) {
			return trim("{$node->parameterName} {$node->description}");
		}
		if ($node instanceof PropertyTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->propertyName} {$node->description}");
		}
		if ($node instanceof ReturnTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof SelfOutTagValueNode) {
			$type = $this->printType($node->type);
			return trim($type . ' ' . $node->description);
		}
		if ($node instanceof TemplateTagValueNode) {
			$upperBound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';
			$lowerBound = $node->lowerBound !== null ? ' super ' . $this->printType($node->lowerBound) : '';
			$default = $node->default !== null ? ' = ' . $this->printType($node->default) : '';
			return trim("{$node->name}{$upperBound}{$lowerBound}{$default} {$node->description}");
		}
		if ($node instanceof ThrowsTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof TypeAliasImportTagValueNode) {
			return trim(
				"{$node->importedAlias} from " . $this->printType($node->importedFrom)
				. ($node->importedAs !== null ? " as {$node->importedAs}" : ''),
			);
		}
		if ($node instanceof TypeAliasTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$node->alias} {$type}");
		}
		if ($node instanceof UsesTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} {$node->description}");
		}
		if ($node instanceof VarTagValueNode) {
			$type = $this->printType($node->type);
			return trim("{$type} " . trim("{$node->variableName} {$node->description}"));
		}

		return (string) $node;
	}

	private function printType(TypeNode $node): string
	{
		if ($node instanceof ArrayShapeNode) {
			$items = array_map(fn (ArrayShapeItemNode $item): string => $this->print($item), $node->items);

			if (! $node->sealed) {
				$items[] = '...' . ($node->unsealedType === null ? '' : $this->print($node->unsealedType));
			}

			return $node->kind . '{' . implode(', ', $items) . '}';
		}
		if ($node instanceof ArrayTypeNode) {
			return $this->printOffsetAccessType($node->type) . '[]';
		}
		if ($node instanceof CallableTypeNode) {
			if ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) {
				$returnType = $this->wrapInParentheses($node->returnType);
			} else {
				$returnType = $this->printType($node->returnType);
			}
			$template = $node->templateTypes !== []
				? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateNode): string => $this->print($templateNode), $node->templateTypes)) . '>'
				: '';
			$parameters = implode(', ', array_map(fn (CallableTypeParameterNode $parameterNode): string => $this->print($parameterNode), $node->parameters));
			return "{$node->identifier}{$template}({$parameters}): {$returnType}";
		}
		if ($node instanceof ConditionalTypeForParameterNode) {
			return sprintf(
				'(%s %s %s ? %s : %s)',
				$node->parameterName,
				$node->negated ? 'is not' : 'is',
				$this->printType($node->targetType),
				$this->printType($node->if),
				$this->printType($node->else),
			);
		}
		if ($node instanceof ConditionalTypeNode) {
			return sprintf(
				'(%s %s %s ? %s : %s)',
				$this->printType($node->subjectType),
				$node->negated ? 'is not' : 'is',
				$this->printType($node->targetType),
				$this->printType($node->if),
				$this->printType($node->else),
			);
		}
		if ($node instanceof ConstTypeNode) {
			return $this->printConstExpr($node->constExpr);
		}
		if ($node instanceof GenericTypeNode) {
			$genericTypes = [];

			foreach ($node->genericTypes as $index => $type) {
				$variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT;
				if ($variance === GenericTypeNode::VARIANCE_INVARIANT) {
					$genericTypes[] = $this->printType($type);
				} elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) {
					$genericTypes[] = '*';
				} else {
					$genericTypes[] = sprintf('%s %s', $variance, $this->print($type));
				}
			}

			return $node->type . '<' . implode(', ', $genericTypes) . '>';
		}
		if ($node instanceof IdentifierTypeNode) {
			return $node->name;
		}
		if ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) {
			$items = [];
			foreach ($node->types as $type) {
				if (
					$type instanceof IntersectionTypeNode
					|| $type instanceof UnionTypeNode
					|| $type instanceof NullableTypeNode
				) {
					$items[] = $this->wrapInParentheses($type);
					continue;
				}

				$items[] = $this->printType($type);
			}

			return implode($node instanceof IntersectionTypeNode ? '&' : '|', $items);
		}
		if ($node instanceof InvalidTypeNode) {
			return (string) $node;
		}
		if ($node instanceof NullableTypeNode) {
			if ($node->type instanceof IntersectionTypeNode || $node->type instanceof UnionTypeNode) {
				return '?(' . $this->printType($node->type) . ')';
			}

			return '?' . $this->printType($node->type);
		}
		if ($node instanceof ObjectShapeNode) {
			$items = array_map(fn (ObjectShapeItemNode $item): string => $this->print($item), $node->items);

			return 'object{' . implode(', ', $items) . '}';
		}
		if ($node instanceof OffsetAccessTypeNode) {
			return $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']';
		}
		if ($node instanceof ThisTypeNode) {
			return (string) $node;
		}

		throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
	}

	private function wrapInParentheses(TypeNode $node): string
	{
		return '(' . $this->printType($node) . ')';
	}

	private function printOffsetAccessType(TypeNode $type): string
	{
		if (
			$type instanceof CallableTypeNode
			|| $type instanceof UnionTypeNode
			|| $type instanceof IntersectionTypeNode
			|| $type instanceof NullableTypeNode
		) {
			return $this->wrapInParentheses($type);
		}

		return $this->printType($type);
	}

	private function printConstExpr(ConstExprNode $node): string
	{
		// this is fine - ConstExprNode classes do not contain nodes that need smart printer logic
		return (string) $node;
	}

	/**
	 * @param Node[] $nodes
	 * @param Node[] $originalNodes
	 */
	private function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName): ?string
	{
		$diff = $this->differ->diffWithReplacements($originalNodes, $nodes);
		$mapKey = $parentNodeClass . '->' . $subNodeName;
		$insertStr = $this->listInsertionMap[$mapKey] ?? null;
		$result = '';
		$beforeFirstKeepOrReplace = true;
		$delayedAdd = [];

		$insertNewline = false;
		[$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens);

		if ($insertStr === "\n * ") {
			$insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
		}

		foreach ($diff as $i => $diffElem) {
			$diffType = $diffElem->type;
			$arrItem = $diffElem->new;
			$origArrayItem = $diffElem->old;
			if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
				$beforeFirstKeepOrReplace = false;
				if (!$arrItem instanceof Node || !$origArrayItem instanceof Node) {
					return null;
				}

				/** @var int $itemStartPos */
				$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);

				/** @var int $itemEndPos */
				$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);

				if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) {
					throw new LogicException();
				}

				$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
				$origComments = $origArrayItem->getAttribute(Attribute::COMMENTS) ?? [];

				$commentStartPos = count($origComments) > 0 ? $origComments[0]->startIndex : $itemStartPos;
				assert($commentStartPos >= 0);

				$result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos);

				if (count($delayedAdd) > 0) {
					foreach ($delayedAdd as $delayedAddNode) {
						$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])
							&& in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], true);
						if ($parenthesesNeeded) {
							$result .= '(';
						}

						if ($insertNewline) {
							$delayedAddComments = $delayedAddNode->getAttribute(Attribute::COMMENTS) ?? [];
							if (count($delayedAddComments) > 0) {
								$result .= $this->printComments($delayedAddComments, $beforeAsteriskIndent, $afterAsteriskIndent);
								$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
							}
						}

						$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
						if ($parenthesesNeeded) {
							$result .= ')';
						}

						if ($insertNewline) {
							$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
						} else {
							$result .= $insertStr;
						}
					}

					$delayedAdd = [];
				}

				$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])
					&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true)
					&& !in_array(get_class($origArrayItem), $this->parenthesesListMap[$mapKey], true);
				$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos);
				if ($addParentheses) {
					$result .= '(';
				}

				if ($comments !== $origComments) {
					if (count($comments) > 0) {
						$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
						$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
					}
				}

				$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
				if ($addParentheses) {
					$result .= ')';
				}
				$tokenIndex = $itemEndPos + 1;

			} elseif ($diffType === DiffElem::TYPE_ADD) {
				if ($insertStr === null) {
					return null;
				}
				if (!$arrItem instanceof Node) {
					return null;
				}

				if ($insertStr === ', ' && $isMultiline || count($arrItem->getAttribute(Attribute::COMMENTS) ?? []) > 0) {
					$insertStr = ',';
					$insertNewline = true;
				}

				if ($beforeFirstKeepOrReplace) {
					// Will be inserted at the next "replace" or "keep" element
					$delayedAdd[] = $arrItem;
					continue;
				}

				/** @var int $itemEndPos */
				$itemEndPos = $tokenIndex - 1;
				if ($insertNewline) {
					$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
					$result .= $insertStr;
					if (count($comments) > 0) {
						$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
						$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
					}
					$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
				} else {
					$result .= $insertStr;
				}

				$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])
					&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true);
				if ($parenthesesNeeded) {
					$result .= '(';
				}

				$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
				if ($parenthesesNeeded) {
					$result .= ')';
				}

				$tokenIndex = $itemEndPos + 1;

			} elseif ($diffType === DiffElem::TYPE_REMOVE) {
				if (!$origArrayItem instanceof Node) {
					return null;
				}

				/** @var int $itemStartPos */
				$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);

				/** @var int $itemEndPos */
				$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);
				if ($itemStartPos < 0 || $itemEndPos < 0) {
					throw new LogicException();
				}

				if ($i === 0) {
					// If we're removing from the start, keep the tokens before the node and drop those after it,
					// instead of the other way around.
					$originalTokensArray = $originalTokens->getTokens();
					for ($j = $tokenIndex; $j < $itemStartPos; $j++) {
						if ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) {
							break;
						}
						$result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET];
					}
				}

				$tokenIndex = $itemEndPos + 1;
			}
		}

		if (count($delayedAdd) > 0) {
			if (!isset($this->emptyListInsertionMap[$mapKey])) {
				return null;
			}

			[$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey];
			if ($findToken !== null) {
				$originalTokensArray = $originalTokens->getTokens();
				for (; $tokenIndex < count($originalTokensArray); $tokenIndex++) {
					$result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET];
					if ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) {
						continue;
					}

					$tokenIndex++;
					break;
				}
			}
			$first = true;
			$result .= $extraLeft;
			foreach ($delayedAdd as $delayedAddNode) {
				if (!$first) {
					$result .= $insertStr;
					if ($insertNewline) {
						$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
					}
				}

				$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
				$first = false;
			}
			$result .= $extraRight;
		}

		return $result;
	}

	/**
	 * @param list<Comment> $comments
	 */
	private function printComments(array $comments, string $beforeAsteriskIndent, string $afterAsteriskIndent): string
	{
		$formattedComments = [];

		foreach ($comments as $comment) {
			$formattedComments[] = str_replace("\n", "\n" . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, $comment->getReformattedText());
		}

		return implode("\n$beforeAsteriskIndent*$afterAsteriskIndent", $formattedComments);
	}

	/**
	 * @param array<Node|null> $nodes
	 * @return array{bool, string, string}
	 */
	private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens): array
	{
		$isMultiline = count($nodes) > 1;
		$pos = $initialIndex;
		$allText = '';
		/** @var Node|null $node */
		foreach ($nodes as $node) {
			if (!$node instanceof Node) {
				continue;
			}

			$endPos = $node->getAttribute(Attribute::END_INDEX) + 1;
			$text = $originalTokens->getContentBetween($pos, $endPos);
			$allText .= $text;
			if (strpos($text, "\n") === false) {
				// We require that a newline is present between *every* item. If the formatting
				// is inconsistent, with only some items having newlines, we don't consider it
				// as multiline
				$isMultiline = false;
			}
			$pos = $endPos;
		}

		$c = preg_match_all('~\n(?<before>[\\x09\\x20]*)\*(?<after>\\x20*)~', $allText, $matches, PREG_SET_ORDER);
		if ($c === 0) {
			return [$isMultiline, ' ', '  '];
		}

		$before = '';
		$after = '';
		foreach ($matches as $match) {
			if (strlen($match['before']) > strlen($before)) {
				$before = $match['before'];
			}
			if (strlen($match['after']) <= strlen($after)) {
				continue;
			}

			$after = $match['after'];
		}

		$before = strlen($before) === 0 ? ' ' : $before;
		$after = strlen($after) === 0 ? '  ' : $after;

		return [$isMultiline, $before, $after];
	}

	private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens): string
	{
		/** @var Node|null $originalNode */
		$originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE);
		if ($originalNode === null) {
			return $this->print($node);
		}

		$class = get_class($node);
		if ($class !== get_class($originalNode)) {
			throw new LogicException();
		}

		$startPos = $originalNode->getAttribute(Attribute::START_INDEX);
		$endPos = $originalNode->getAttribute(Attribute::END_INDEX);
		if ($startPos < 0 || $endPos < 0) {
			throw new LogicException();
		}

		$result = '';
		$pos = $startPos;
		$subNodeNames = array_keys(get_object_vars($node));
		foreach ($subNodeNames as $subNodeName) {
			$subNode = $node->$subNodeName;
			$origSubNode = $originalNode->$subNodeName;

			if (
				(!$subNode instanceof Node && $subNode !== null)
				|| (!$origSubNode instanceof Node && $origSubNode !== null)
			) {
				if ($subNode === $origSubNode) {
					// Unchanged, can reuse old code
					continue;
				}

				if (is_array($subNode) && is_array($origSubNode)) {
					// Array subnode changed, we might be able to reconstruct it
					$listResult = $this->printArrayFormatPreserving(
						$subNode,
						$origSubNode,
						$originalTokens,
						$pos,
						$class,
						$subNodeName,
					);

					if ($listResult === null) {
						return $this->print($node);
					}

					$result .= $listResult;
					continue;
				}

				return $this->print($node);
			}

			if ($origSubNode === null) {
				if ($subNode === null) {
					// Both null, nothing to do
					continue;
				}

				return $this->print($node);
			}

			$subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX);
			$subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX);
			if ($subStartPos < 0 || $subEndPos < 0) {
				throw new LogicException();
			}

			if ($subEndPos < $subStartPos) {
				return $this->print($node);
			}

			if ($subNode === null) {
				return $this->print($node);
			}

			$result .= $originalTokens->getContentBetween($pos, $subStartPos);
			$mapKey = get_class($node) . '->' . $subNodeName;
			$parenthesesNeeded = isset($this->parenthesesMap[$mapKey])
				&& in_array(get_class($subNode), $this->parenthesesMap[$mapKey], true);

			if ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) {
				$parenthesesNeeded = $parenthesesNeeded
					&& !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], true);
			}

			$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos);
			if ($addParentheses) {
				$result .= '(';
			}

			$result .= $this->printNodeFormatPreserving($subNode, $originalTokens);
			if ($addParentheses) {
				$result .= ')';
			}

			$pos = $subEndPos + 1;
		}

		return $result . $originalTokens->getContentBetween($pos, $endPos + 1);
	}

}
<?php

namespace Psr\Container;

use Throwable;

/**
 * Base interface representing a generic exception in a container.
 */
interface ContainerExceptionInterface extends Throwable
{
}
<?php

declare(strict_types=1);

namespace Psr\Container;

/**
 * Describes the interface of a container that exposes methods to read its entries.
 */
interface ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
     * @throws ContainerExceptionInterface Error while retrieving the entry.
     *
     * @return mixed Entry.
     */
    public function get(string $id);

    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return bool
     */
    public function has(string $id): bool;
}
<?php

namespace Psr\Container;

/**
 * No entry was found in the container.
 */
interface NotFoundExceptionInterface extends ContainerExceptionInterface
{
}
<?php
declare(strict_types=1);

namespace Psr\EventDispatcher;

/**
 * Defines a dispatcher for events.
 */
interface EventDispatcherInterface
{
    /**
     * Provide all relevant listeners with an event to process.
     *
     * @param object $event
     *   The object to process.
     *
     * @return object
     *   The Event that was passed, now modified by listeners.
     */
    public function dispatch(object $event);
}
<?php
declare(strict_types=1);

namespace Psr\EventDispatcher;

/**
 * Mapper from an event to the listeners that are applicable to that event.
 */
interface ListenerProviderInterface
{
    /**
     * @param object $event
     *   An event for which to return the relevant listeners.
     * @return iterable[callable]
     *   An iterable (array, iterator, or generator) of callables.  Each
     *   callable MUST be type-compatible with $event.
     */
    public function getListenersForEvent(object $event) : iterable;
}
<?php
declare(strict_types=1);

namespace Psr\EventDispatcher;

/**
 * An Event whose processing may be interrupted when the event has been handled.
 *
 * A Dispatcher implementation MUST check to determine if an Event
 * is marked as stopped after each listener is called.  If it is then it should
 * return immediately without calling any further Listeners.
 */
interface StoppableEventInterface
{
    /**
     * Is propagation stopped?
     *
     * This will typically only be used by the Dispatcher to determine if the
     * previous listener halted propagation.
     *
     * @return bool
     *   True if the Event is complete and no further listeners should be called.
     *   False to continue calling listeners.
     */
    public function isPropagationStopped() : bool;
}
<?php

namespace Psr\Http\Client;

/**
 * Every HTTP client related exception MUST implement this interface.
 */
interface ClientExceptionInterface extends \Throwable
{
}
<?php

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface ClientInterface
{
    /**
     * Sends a PSR-7 request and returns a PSR-7 response.
     *
     * @param RequestInterface $request
     *
     * @return ResponseInterface
     *
     * @throws \Psr\Http\Client\ClientExceptionInterface If an error happens while processing the request.
     */
    public function sendRequest(RequestInterface $request): ResponseInterface;
}
<?php

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;

/**
 * Thrown when the request cannot be completed because of network issues.
 *
 * There is no response object as this exception is thrown when no response has been received.
 *
 * Example: the target host name can not be resolved or the connection failed.
 */
interface NetworkExceptionInterface extends ClientExceptionInterface
{
    /**
     * Returns the request.
     *
     * The request object MAY be a different object from the one passed to ClientInterface::sendRequest()
     *
     * @return RequestInterface
     */
    public function getRequest(): RequestInterface;
}
<?php

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;

/**
 * Exception for when a request failed.
 *
 * Examples:
 *      - Request is invalid (e.g. method is missing)
 *      - Runtime request errors (e.g. the body stream is not seekable)
 */
interface RequestExceptionInterface extends ClientExceptionInterface
{
    /**
     * Returns the request.
     *
     * The request object MAY be a different object from the one passed to ClientInterface::sendRequest()
     *
     * @return RequestInterface
     */
    public function getRequest(): RequestInterface;
}
<?php

namespace Psr\Http\Message;

interface RequestFactoryInterface
{
    /**
     * Create a new request.
     *
     * @param string $method The HTTP method associated with the request.
     * @param UriInterface|string $uri The URI associated with the request. If
     *     the value is a string, the factory MUST create a UriInterface
     *     instance based on it.
     *
     * @return RequestInterface
     */
    public function createRequest(string $method, $uri): RequestInterface;
}
<?php

namespace Psr\Http\Message;

interface ResponseFactoryInterface
{
    /**
     * Create a new response.
     *
     * @param int $code HTTP status code; defaults to 200
     * @param string $reasonPhrase Reason phrase to associate with status code
     *     in generated response; if none is provided implementations MAY use
     *     the defaults as suggested in the HTTP specification.
     *
     * @return ResponseInterface
     */
    public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface;
}
<?php

namespace Psr\Http\Message;

interface ServerRequestFactoryInterface
{
    /**
     * Create a new server request.
     *
     * Note that server-params are taken precisely as given - no parsing/processing
     * of the given values is performed, and, in particular, no attempt is made to
     * determine the HTTP method or URI, which must be provided explicitly.
     *
     * @param string $method The HTTP method associated with the request.
     * @param UriInterface|string $uri The URI associated with the request. If
     *     the value is a string, the factory MUST create a UriInterface
     *     instance based on it.
     * @param array $serverParams Array of SAPI parameters with which to seed
     *     the generated request instance.
     *
     * @return ServerRequestInterface
     */
    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface;
}
<?php

namespace Psr\Http\Message;

interface StreamFactoryInterface
{
    /**
     * Create a new stream from a string.
     *
     * The stream SHOULD be created with a temporary resource.
     *
     * @param string $content String content with which to populate the stream.
     *
     * @return StreamInterface
     */
    public function createStream(string $content = ''): StreamInterface;

    /**
     * Create a stream from an existing file.
     *
     * The file MUST be opened using the given mode, which may be any mode
     * supported by the `fopen` function.
     *
     * The `$filename` MAY be any string supported by `fopen()`.
     *
     * @param string $filename Filename or stream URI to use as basis of stream.
     * @param string $mode Mode with which to open the underlying filename/stream.
     *
     * @return StreamInterface
     * @throws \RuntimeException If the file cannot be opened.
     * @throws \InvalidArgumentException If the mode is invalid.
     */
    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface;

    /**
     * Create a new stream from an existing resource.
     *
     * The stream MUST be readable and may be writable.
     *
     * @param resource $resource PHP resource to use as basis of stream.
     *
     * @return StreamInterface
     */
    public function createStreamFromResource($resource): StreamInterface;
}
<?php

namespace Psr\Http\Message;

interface UploadedFileFactoryInterface
{
    /**
     * Create a new uploaded file.
     *
     * If a size is not provided it will be determined by checking the size of
     * the file.
     *
     * @see http://php.net/manual/features.file-upload.post-method.php
     * @see http://php.net/manual/features.file-upload.errors.php
     *
     * @param StreamInterface $stream Underlying stream representing the
     *     uploaded file content.
     * @param int|null $size in bytes
     * @param int $error PHP file upload error
     * @param string|null $clientFilename Filename as provided by the client, if any.
     * @param string|null $clientMediaType Media type as provided by the client, if any.
     *
     * @return UploadedFileInterface
     *
     * @throws \InvalidArgumentException If the file resource is not readable.
     */
    public function createUploadedFile(
        StreamInterface $stream,
        ?int $size = null,
        int $error = \UPLOAD_ERR_OK,
        ?string $clientFilename = null,
        ?string $clientMediaType = null
    ): UploadedFileInterface;
}
<?php

namespace Psr\Http\Message;

interface UriFactoryInterface
{
    /**
     * Create a new URI.
     *
     * @param string $uri
     *
     * @return UriInterface
     *
     * @throws \InvalidArgumentException If the given URI cannot be parsed.
     */
    public function createUri(string $uri = ''): UriInterface;
}
<?php

namespace Psr\Http\Message;

/**
 * HTTP messages consist of requests from a client to a server and responses
 * from a server to a client. This interface defines the methods common to
 * each.
 *
 * Messages are considered immutable; all methods that might change state MUST
 * be implemented such that they retain the internal state of the current
 * message and return an instance that contains the changed state.
 *
 * @link http://www.ietf.org/rfc/rfc7230.txt
 * @link http://www.ietf.org/rfc/rfc7231.txt
 */
interface MessageInterface
{
    /**
     * Retrieves the HTTP protocol version as a string.
     *
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
     *
     * @return string HTTP protocol version.
     */
    public function getProtocolVersion(): string;

    /**
     * Return an instance with the specified HTTP protocol version.
     *
     * The version string MUST contain only the HTTP version number (e.g.,
     * "1.1", "1.0").
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new protocol version.
     *
     * @param string $version HTTP protocol version
     * @return static
     */
    public function withProtocolVersion(string $version): MessageInterface;

    /**
     * Retrieves all message header values.
     *
     * The keys represent the header name as it will be sent over the wire, and
     * each value is an array of strings associated with the header.
     *
     *     // Represent the headers as a string
     *     foreach ($message->getHeaders() as $name => $values) {
     *         echo $name . ": " . implode(", ", $values);
     *     }
     *
     *     // Emit headers iteratively:
     *     foreach ($message->getHeaders() as $name => $values) {
     *         foreach ($values as $value) {
     *             header(sprintf('%s: %s', $name, $value), false);
     *         }
     *     }
     *
     * While header names are not case-sensitive, getHeaders() will preserve the
     * exact case in which headers were originally specified.
     *
     * @return string[][] Returns an associative array of the message's headers. Each
     *     key MUST be a header name, and each value MUST be an array of strings
     *     for that header.
     */
    public function getHeaders(): array;

    /**
     * Checks if a header exists by the given case-insensitive name.
     *
     * @param string $name Case-insensitive header field name.
     * @return bool Returns true if any header names match the given header
     *     name using a case-insensitive string comparison. Returns false if
     *     no matching header name is found in the message.
     */
    public function hasHeader(string $name): bool;

    /**
     * Retrieves a message header value by the given case-insensitive name.
     *
     * This method returns an array of all the header values of the given
     * case-insensitive header name.
     *
     * If the header does not appear in the message, this method MUST return an
     * empty array.
     *
     * @param string $name Case-insensitive header field name.
     * @return string[] An array of string values as provided for the given
     *    header. If the header does not appear in the message, this method MUST
     *    return an empty array.
     */
    public function getHeader(string $name): array;

    /**
     * Retrieves a comma-separated string of the values for a single header.
     *
     * This method returns all of the header values of the given
     * case-insensitive header name as a string concatenated together using
     * a comma.
     *
     * NOTE: Not all header values may be appropriately represented using
     * comma concatenation. For such headers, use getHeader() instead
     * and supply your own delimiter when concatenating.
     *
     * If the header does not appear in the message, this method MUST return
     * an empty string.
     *
     * @param string $name Case-insensitive header field name.
     * @return string A string of values as provided for the given header
     *    concatenated together using a comma. If the header does not appear in
     *    the message, this method MUST return an empty string.
     */
    public function getHeaderLine(string $name): string;

    /**
     * Return an instance with the provided value replacing the specified header.
     *
     * While header names are case-insensitive, the casing of the header will
     * be preserved by this function, and returned from getHeaders().
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new and/or updated header and value.
     *
     * @param string $name Case-insensitive header field name.
     * @param string|string[] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withHeader(string $name, $value): MessageInterface;

    /**
     * Return an instance with the specified header appended with the given value.
     *
     * Existing values for the specified header will be maintained. The new
     * value(s) will be appended to the existing list. If the header did not
     * exist previously, it will be added.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new header and/or value.
     *
     * @param string $name Case-insensitive header field name to add.
     * @param string|string[] $value Header value(s).
     * @return static
     * @throws \InvalidArgumentException for invalid header names or values.
     */
    public function withAddedHeader(string $name, $value): MessageInterface;

    /**
     * Return an instance without the specified header.
     *
     * Header resolution MUST be done without case-sensitivity.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that removes
     * the named header.
     *
     * @param string $name Case-insensitive header field name to remove.
     * @return static
     */
    public function withoutHeader(string $name): MessageInterface;

    /**
     * Gets the body of the message.
     *
     * @return StreamInterface Returns the body as a stream.
     */
    public function getBody(): StreamInterface;

    /**
     * Return an instance with the specified message body.
     *
     * The body MUST be a StreamInterface object.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return a new instance that has the
     * new body stream.
     *
     * @param StreamInterface $body Body.
     * @return static
     * @throws \InvalidArgumentException When the body is not valid.
     */
    public function withBody(StreamInterface $body): MessageInterface;
}
<?php

namespace Psr\Http\Message;

/**
 * Representation of an outgoing, client-side request.
 *
 * Per the HTTP specification, this interface includes properties for
 * each of the following:
 *
 * - Protocol version
 * - HTTP method
 * - URI
 * - Headers
 * - Message body
 *
 * During construction, implementations MUST attempt to set the Host header from
 * a provided URI if no Host header is provided.
 *
 * Requests are considered immutable; all methods that might change state MUST
 * be implemented such that they retain the internal state of the current
 * message and return an instance that contains the changed state.
 */
interface RequestInterface extends MessageInterface
{
    /**
     * Retrieves the message's request target.
     *
     * Retrieves the message's request-target either as it will appear (for
     * clients), as it appeared at request (for servers), or as it was
     * specified for the instance (see withRequestTarget()).
     *
     * In most cases, this will be the origin-form of the composed URI,
     * unless a value was provided to the concrete implementation (see
     * withRequestTarget() below).
     *
     * If no URI is available, and no request-target has been specifically
     * provided, this method MUST return the string "/".
     *
     * @return string
     */
    public function getRequestTarget(): string;

    /**
     * Return an instance with the specific request-target.
     *
     * If the request needs a non-origin-form request-target — e.g., for
     * specifying an absolute-form, authority-form, or asterisk-form —
     * this method may be used to create an instance with the specified
     * request-target, verbatim.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * changed request target.
     *
     * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
     *     request-target forms allowed in request messages)
     * @param string $requestTarget
     * @return static
     */
    public function withRequestTarget(string $requestTarget): RequestInterface;


    /**
     * Retrieves the HTTP method of the request.
     *
     * @return string Returns the request method.
     */
    public function getMethod(): string;

    /**
     * Return an instance with the provided HTTP method.
     *
     * While HTTP method names are typically all uppercase characters, HTTP
     * method names are case-sensitive and thus implementations SHOULD NOT
     * modify the given string.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * changed request method.
     *
     * @param string $method Case-sensitive method.
     * @return static
     * @throws \InvalidArgumentException for invalid HTTP methods.
     */
    public function withMethod(string $method): RequestInterface;

    /**
     * Retrieves the URI instance.
     *
     * This method MUST return a UriInterface instance.
     *
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
     * @return UriInterface Returns a UriInterface instance
     *     representing the URI of the request.
     */
    public function getUri(): UriInterface;

    /**
     * Returns an instance with the provided URI.
     *
     * This method MUST update the Host header of the returned request by
     * default if the URI contains a host component. If the URI does not
     * contain a host component, any pre-existing Host header MUST be carried
     * over to the returned request.
     *
     * You can opt-in to preserving the original state of the Host header by
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
     * `true`, this method interacts with the Host header in the following ways:
     *
     * - If the Host header is missing or empty, and the new URI contains
     *   a host component, this method MUST update the Host header in the returned
     *   request.
     * - If the Host header is missing or empty, and the new URI does not contain a
     *   host component, this method MUST NOT update the Host header in the returned
     *   request.
     * - If a Host header is present and non-empty, this method MUST NOT update
     *   the Host header in the returned request.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new UriInterface instance.
     *
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
     * @param UriInterface $uri New request URI to use.
     * @param bool $preserveHost Preserve the original state of the Host header.
     * @return static
     */
    public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface;
}
<?php

namespace Psr\Http\Message;

/**
 * Representation of an outgoing, server-side response.
 *
 * Per the HTTP specification, this interface includes properties for
 * each of the following:
 *
 * - Protocol version
 * - Status code and reason phrase
 * - Headers
 * - Message body
 *
 * Responses are considered immutable; all methods that might change state MUST
 * be implemented such that they retain the internal state of the current
 * message and return an instance that contains the changed state.
 */
interface ResponseInterface extends MessageInterface
{
    /**
     * Gets the response status code.
     *
     * The status code is a 3-digit integer result code of the server's attempt
     * to understand and satisfy the request.
     *
     * @return int Status code.
     */
    public function getStatusCode(): int;

    /**
     * Return an instance with the specified status code and, optionally, reason phrase.
     *
     * If no reason phrase is specified, implementations MAY choose to default
     * to the RFC 7231 or IANA recommended reason phrase for the response's
     * status code.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated status and reason phrase.
     *
     * @link http://tools.ietf.org/html/rfc7231#section-6
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
     * @param int $code The 3-digit integer result code to set.
     * @param string $reasonPhrase The reason phrase to use with the
     *     provided status code; if none is provided, implementations MAY
     *     use the defaults as suggested in the HTTP specification.
     * @return static
     * @throws \InvalidArgumentException For invalid status code arguments.
     */
    public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface;

    /**
     * Gets the response reason phrase associated with the status code.
     *
     * Because a reason phrase is not a required element in a response
     * status line, the reason phrase value MAY be null. Implementations MAY
     * choose to return the default RFC 7231 recommended reason phrase (or those
     * listed in the IANA HTTP Status Code Registry) for the response's
     * status code.
     *
     * @link http://tools.ietf.org/html/rfc7231#section-6
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
     * @return string Reason phrase; must return an empty string if none present.
     */
    public function getReasonPhrase(): string;
}
<?php

namespace Psr\Http\Message;

/**
 * Representation of an incoming, server-side HTTP request.
 *
 * Per the HTTP specification, this interface includes properties for
 * each of the following:
 *
 * - Protocol version
 * - HTTP method
 * - URI
 * - Headers
 * - Message body
 *
 * Additionally, it encapsulates all data as it has arrived to the
 * application from the CGI and/or PHP environment, including:
 *
 * - The values represented in $_SERVER.
 * - Any cookies provided (generally via $_COOKIE)
 * - Query string arguments (generally via $_GET, or as parsed via parse_str())
 * - Upload files, if any (as represented by $_FILES)
 * - Deserialized body parameters (generally from $_POST)
 *
 * $_SERVER values MUST be treated as immutable, as they represent application
 * state at the time of request; as such, no methods are provided to allow
 * modification of those values. The other values provide such methods, as they
 * can be restored from $_SERVER or the request body, and may need treatment
 * during the application (e.g., body parameters may be deserialized based on
 * content type).
 *
 * Additionally, this interface recognizes the utility of introspecting a
 * request to derive and match additional parameters (e.g., via URI path
 * matching, decrypting cookie values, deserializing non-form-encoded body
 * content, matching authorization headers to users, etc). These parameters
 * are stored in an "attributes" property.
 *
 * Requests are considered immutable; all methods that might change state MUST
 * be implemented such that they retain the internal state of the current
 * message and return an instance that contains the changed state.
 */
interface ServerRequestInterface extends RequestInterface
{
    /**
     * Retrieve server parameters.
     *
     * Retrieves data related to the incoming request environment,
     * typically derived from PHP's $_SERVER superglobal. The data IS NOT
     * REQUIRED to originate from $_SERVER.
     *
     * @return array
     */
    public function getServerParams(): array;

    /**
     * Retrieve cookies.
     *
     * Retrieves cookies sent by the client to the server.
     *
     * The data MUST be compatible with the structure of the $_COOKIE
     * superglobal.
     *
     * @return array
     */
    public function getCookieParams(): array;

    /**
     * Return an instance with the specified cookies.
     *
     * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
     * be compatible with the structure of $_COOKIE. Typically, this data will
     * be injected at instantiation.
     *
     * This method MUST NOT update the related Cookie header of the request
     * instance, nor related values in the server params.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated cookie values.
     *
     * @param array $cookies Array of key/value pairs representing cookies.
     * @return static
     */
    public function withCookieParams(array $cookies): ServerRequestInterface;

    /**
     * Retrieve query string arguments.
     *
     * Retrieves the deserialized query string arguments, if any.
     *
     * Note: the query params might not be in sync with the URI or server
     * params. If you need to ensure you are only getting the original
     * values, you may need to parse the query string from `getUri()->getQuery()`
     * or from the `QUERY_STRING` server param.
     *
     * @return array
     */
    public function getQueryParams(): array;

    /**
     * Return an instance with the specified query string arguments.
     *
     * These values SHOULD remain immutable over the course of the incoming
     * request. They MAY be injected during instantiation, such as from PHP's
     * $_GET superglobal, or MAY be derived from some other value such as the
     * URI. In cases where the arguments are parsed from the URI, the data
     * MUST be compatible with what PHP's parse_str() would return for
     * purposes of how duplicate query parameters are handled, and how nested
     * sets are handled.
     *
     * Setting query string arguments MUST NOT change the URI stored by the
     * request, nor the values in the server params.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated query string arguments.
     *
     * @param array $query Array of query string arguments, typically from
     *     $_GET.
     * @return static
     */
    public function withQueryParams(array $query): ServerRequestInterface;

    /**
     * Retrieve normalized file upload data.
     *
     * This method returns upload metadata in a normalized tree, with each leaf
     * an instance of Psr\Http\Message\UploadedFileInterface.
     *
     * These values MAY be prepared from $_FILES or the message body during
     * instantiation, or MAY be injected via withUploadedFiles().
     *
     * @return array An array tree of UploadedFileInterface instances; an empty
     *     array MUST be returned if no data is present.
     */
    public function getUploadedFiles(): array;

    /**
     * Create a new instance with the specified uploaded files.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated body parameters.
     *
     * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
     * @return static
     * @throws \InvalidArgumentException if an invalid structure is provided.
     */
    public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface;

    /**
     * Retrieve any parameters provided in the request body.
     *
     * If the request Content-Type is either application/x-www-form-urlencoded
     * or multipart/form-data, and the request method is POST, this method MUST
     * return the contents of $_POST.
     *
     * Otherwise, this method may return any results of deserializing
     * the request body content; as parsing returns structured content, the
     * potential types MUST be arrays or objects only. A null value indicates
     * the absence of body content.
     *
     * @return null|array|object The deserialized body parameters, if any.
     *     These will typically be an array or object.
     */
    public function getParsedBody();

    /**
     * Return an instance with the specified body parameters.
     *
     * These MAY be injected during instantiation.
     *
     * If the request Content-Type is either application/x-www-form-urlencoded
     * or multipart/form-data, and the request method is POST, use this method
     * ONLY to inject the contents of $_POST.
     *
     * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
     * deserializing the request body content. Deserialization/parsing returns
     * structured data, and, as such, this method ONLY accepts arrays or objects,
     * or a null value if nothing was available to parse.
     *
     * As an example, if content negotiation determines that the request data
     * is a JSON payload, this method could be used to create a request
     * instance with the deserialized parameters.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated body parameters.
     *
     * @param null|array|object $data The deserialized body data. This will
     *     typically be in an array or object.
     * @return static
     * @throws \InvalidArgumentException if an unsupported argument type is
     *     provided.
     */
    public function withParsedBody($data): ServerRequestInterface;

    /**
     * Retrieve attributes derived from the request.
     *
     * The request "attributes" may be used to allow injection of any
     * parameters derived from the request: e.g., the results of path
     * match operations; the results of decrypting cookies; the results of
     * deserializing non-form-encoded message bodies; etc. Attributes
     * will be application and request specific, and CAN be mutable.
     *
     * @return array Attributes derived from the request.
     */
    public function getAttributes(): array;

    /**
     * Retrieve a single derived request attribute.
     *
     * Retrieves a single derived request attribute as described in
     * getAttributes(). If the attribute has not been previously set, returns
     * the default value as provided.
     *
     * This method obviates the need for a hasAttribute() method, as it allows
     * specifying a default value to return if the attribute is not found.
     *
     * @see getAttributes()
     * @param string $name The attribute name.
     * @param mixed $default Default value to return if the attribute does not exist.
     * @return mixed
     */
    public function getAttribute(string $name, $default = null);

    /**
     * Return an instance with the specified derived request attribute.
     *
     * This method allows setting a single derived request attribute as
     * described in getAttributes().
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * updated attribute.
     *
     * @see getAttributes()
     * @param string $name The attribute name.
     * @param mixed $value The value of the attribute.
     * @return static
     */
    public function withAttribute(string $name, $value): ServerRequestInterface;

    /**
     * Return an instance that removes the specified derived request attribute.
     *
     * This method allows removing a single derived request attribute as
     * described in getAttributes().
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that removes
     * the attribute.
     *
     * @see getAttributes()
     * @param string $name The attribute name.
     * @return static
     */
    public function withoutAttribute(string $name): ServerRequestInterface;
}
<?php

namespace Psr\Http\Message;

/**
 * Describes a data stream.
 *
 * Typically, an instance will wrap a PHP stream; this interface provides
 * a wrapper around the most common operations, including serialization of
 * the entire stream to a string.
 */
interface StreamInterface
{
    /**
     * Reads all data from the stream into a string, from the beginning to end.
     *
     * This method MUST attempt to seek to the beginning of the stream before
     * reading data and read the stream until the end is reached.
     *
     * Warning: This could attempt to load a large amount of data into memory.
     *
     * This method MUST NOT raise an exception in order to conform with PHP's
     * string casting operations.
     *
     * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
     * @return string
     */
    public function __toString(): string;

    /**
     * Closes the stream and any underlying resources.
     *
     * @return void
     */
    public function close(): void;

    /**
     * Separates any underlying resources from the stream.
     *
     * After the stream has been detached, the stream is in an unusable state.
     *
     * @return resource|null Underlying PHP stream, if any
     */
    public function detach();

    /**
     * Get the size of the stream if known.
     *
     * @return int|null Returns the size in bytes if known, or null if unknown.
     */
    public function getSize(): ?int;

    /**
     * Returns the current position of the file read/write pointer
     *
     * @return int Position of the file pointer
     * @throws \RuntimeException on error.
     */
    public function tell(): int;

    /**
     * Returns true if the stream is at the end of the stream.
     *
     * @return bool
     */
    public function eof(): bool;

    /**
     * Returns whether or not the stream is seekable.
     *
     * @return bool
     */
    public function isSeekable(): bool;

    /**
     * Seek to a position in the stream.
     *
     * @link http://www.php.net/manual/en/function.fseek.php
     * @param int $offset Stream offset
     * @param int $whence Specifies how the cursor position will be calculated
     *     based on the seek offset. Valid values are identical to the built-in
     *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
     *     offset bytes SEEK_CUR: Set position to current location plus offset
     *     SEEK_END: Set position to end-of-stream plus offset.
     * @throws \RuntimeException on failure.
     */
    public function seek(int $offset, int $whence = SEEK_SET): void;

    /**
     * Seek to the beginning of the stream.
     *
     * If the stream is not seekable, this method will raise an exception;
     * otherwise, it will perform a seek(0).
     *
     * @see seek()
     * @link http://www.php.net/manual/en/function.fseek.php
     * @throws \RuntimeException on failure.
     */
    public function rewind(): void;

    /**
     * Returns whether or not the stream is writable.
     *
     * @return bool
     */
    public function isWritable(): bool;

    /**
     * Write data to the stream.
     *
     * @param string $string The string that is to be written.
     * @return int Returns the number of bytes written to the stream.
     * @throws \RuntimeException on failure.
     */
    public function write(string $string): int;

    /**
     * Returns whether or not the stream is readable.
     *
     * @return bool
     */
    public function isReadable(): bool;

    /**
     * Read data from the stream.
     *
     * @param int $length Read up to $length bytes from the object and return
     *     them. Fewer than $length bytes may be returned if underlying stream
     *     call returns fewer bytes.
     * @return string Returns the data read from the stream, or an empty string
     *     if no bytes are available.
     * @throws \RuntimeException if an error occurs.
     */
    public function read(int $length): string;

    /**
     * Returns the remaining contents in a string
     *
     * @return string
     * @throws \RuntimeException if unable to read or an error occurs while
     *     reading.
     */
    public function getContents(): string;

    /**
     * Get stream metadata as an associative array or retrieve a specific key.
     *
     * The keys returned are identical to the keys returned from PHP's
     * stream_get_meta_data() function.
     *
     * @link http://php.net/manual/en/function.stream-get-meta-data.php
     * @param string|null $key Specific metadata to retrieve.
     * @return array|mixed|null Returns an associative array if no key is
     *     provided. Returns a specific key value if a key is provided and the
     *     value is found, or null if the key is not found.
     */
    public function getMetadata(?string $key = null);
}
<?php

namespace Psr\Http\Message;

/**
 * Value object representing a file uploaded through an HTTP request.
 *
 * Instances of this interface are considered immutable; all methods that
 * might change state MUST be implemented such that they retain the internal
 * state of the current instance and return an instance that contains the
 * changed state.
 */
interface UploadedFileInterface
{
    /**
     * Retrieve a stream representing the uploaded file.
     *
     * This method MUST return a StreamInterface instance, representing the
     * uploaded file. The purpose of this method is to allow utilizing native PHP
     * stream functionality to manipulate the file upload, such as
     * stream_copy_to_stream() (though the result will need to be decorated in a
     * native PHP stream wrapper to work with such functions).
     *
     * If the moveTo() method has been called previously, this method MUST raise
     * an exception.
     *
     * @return StreamInterface Stream representation of the uploaded file.
     * @throws \RuntimeException in cases when no stream is available or can be
     *     created.
     */
    public function getStream(): StreamInterface;

    /**
     * Move the uploaded file to a new location.
     *
     * Use this method as an alternative to move_uploaded_file(). This method is
     * guaranteed to work in both SAPI and non-SAPI environments.
     * Implementations must determine which environment they are in, and use the
     * appropriate method (move_uploaded_file(), rename(), or a stream
     * operation) to perform the operation.
     *
     * $targetPath may be an absolute path, or a relative path. If it is a
     * relative path, resolution should be the same as used by PHP's rename()
     * function.
     *
     * The original file or stream MUST be removed on completion.
     *
     * If this method is called more than once, any subsequent calls MUST raise
     * an exception.
     *
     * When used in an SAPI environment where $_FILES is populated, when writing
     * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
     * used to ensure permissions and upload status are verified correctly.
     *
     * If you wish to move to a stream, use getStream(), as SAPI operations
     * cannot guarantee writing to stream destinations.
     *
     * @see http://php.net/is_uploaded_file
     * @see http://php.net/move_uploaded_file
     * @param string $targetPath Path to which to move the uploaded file.
     * @throws \InvalidArgumentException if the $targetPath specified is invalid.
     * @throws \RuntimeException on any error during the move operation, or on
     *     the second or subsequent call to the method.
     */
    public function moveTo(string $targetPath): void;
    
    /**
     * Retrieve the file size.
     *
     * Implementations SHOULD return the value stored in the "size" key of
     * the file in the $_FILES array if available, as PHP calculates this based
     * on the actual size transmitted.
     *
     * @return int|null The file size in bytes or null if unknown.
     */
    public function getSize(): ?int;
    
    /**
     * Retrieve the error associated with the uploaded file.
     *
     * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.
     *
     * If the file was uploaded successfully, this method MUST return
     * UPLOAD_ERR_OK.
     *
     * Implementations SHOULD return the value stored in the "error" key of
     * the file in the $_FILES array.
     *
     * @see http://php.net/manual/en/features.file-upload.errors.php
     * @return int One of PHP's UPLOAD_ERR_XXX constants.
     */
    public function getError(): int;
    
    /**
     * Retrieve the filename sent by the client.
     *
     * Do not trust the value returned by this method. A client could send
     * a malicious filename with the intention to corrupt or hack your
     * application.
     *
     * Implementations SHOULD return the value stored in the "name" key of
     * the file in the $_FILES array.
     *
     * @return string|null The filename sent by the client or null if none
     *     was provided.
     */
    public function getClientFilename(): ?string;
    
    /**
     * Retrieve the media type sent by the client.
     *
     * Do not trust the value returned by this method. A client could send
     * a malicious media type with the intention to corrupt or hack your
     * application.
     *
     * Implementations SHOULD return the value stored in the "type" key of
     * the file in the $_FILES array.
     *
     * @return string|null The media type sent by the client or null if none
     *     was provided.
     */
    public function getClientMediaType(): ?string;
}
<?php

namespace Psr\Http\Message;

/**
 * Value object representing a URI.
 *
 * This interface is meant to represent URIs according to RFC 3986 and to
 * provide methods for most common operations. Additional functionality for
 * working with URIs can be provided on top of the interface or externally.
 * Its primary use is for HTTP requests, but may also be used in other
 * contexts.
 *
 * Instances of this interface are considered immutable; all methods that
 * might change state MUST be implemented such that they retain the internal
 * state of the current instance and return an instance that contains the
 * changed state.
 *
 * Typically the Host header will be also be present in the request message.
 * For server-side requests, the scheme will typically be discoverable in the
 * server parameters.
 *
 * @link http://tools.ietf.org/html/rfc3986 (the URI specification)
 */
interface UriInterface
{
    /**
     * Retrieve the scheme component of the URI.
     *
     * If no scheme is present, this method MUST return an empty string.
     *
     * The value returned MUST be normalized to lowercase, per RFC 3986
     * Section 3.1.
     *
     * The trailing ":" character is not part of the scheme and MUST NOT be
     * added.
     *
     * @see https://tools.ietf.org/html/rfc3986#section-3.1
     * @return string The URI scheme.
     */
    public function getScheme(): string;

    /**
     * Retrieve the authority component of the URI.
     *
     * If no authority information is present, this method MUST return an empty
     * string.
     *
     * The authority syntax of the URI is:
     *
     * <pre>
     * [user-info@]host[:port]
     * </pre>
     *
     * If the port component is not set or is the standard port for the current
     * scheme, it SHOULD NOT be included.
     *
     * @see https://tools.ietf.org/html/rfc3986#section-3.2
     * @return string The URI authority, in "[user-info@]host[:port]" format.
     */
    public function getAuthority(): string;

    /**
     * Retrieve the user information component of the URI.
     *
     * If no user information is present, this method MUST return an empty
     * string.
     *
     * If a user is present in the URI, this will return that value;
     * additionally, if the password is also present, it will be appended to the
     * user value, with a colon (":") separating the values.
     *
     * The trailing "@" character is not part of the user information and MUST
     * NOT be added.
     *
     * @return string The URI user information, in "username[:password]" format.
     */
    public function getUserInfo(): string;

    /**
     * Retrieve the host component of the URI.
     *
     * If no host is present, this method MUST return an empty string.
     *
     * The value returned MUST be normalized to lowercase, per RFC 3986
     * Section 3.2.2.
     *
     * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
     * @return string The URI host.
     */
    public function getHost(): string;

    /**
     * Retrieve the port component of the URI.
     *
     * If a port is present, and it is non-standard for the current scheme,
     * this method MUST return it as an integer. If the port is the standard port
     * used with the current scheme, this method SHOULD return null.
     *
     * If no port is present, and no scheme is present, this method MUST return
     * a null value.
     *
     * If no port is present, but a scheme is present, this method MAY return
     * the standard port for that scheme, but SHOULD return null.
     *
     * @return null|int The URI port.
     */
    public function getPort(): ?int;

    /**
     * Retrieve the path component of the URI.
     *
     * The path can either be empty or absolute (starting with a slash) or
     * rootless (not starting with a slash). Implementations MUST support all
     * three syntaxes.
     *
     * Normally, the empty path "" and absolute path "/" are considered equal as
     * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
     * do this normalization because in contexts with a trimmed base path, e.g.
     * the front controller, this difference becomes significant. It's the task
     * of the user to handle both "" and "/".
     *
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
     * any characters. To determine what characters to encode, please refer to
     * RFC 3986, Sections 2 and 3.3.
     *
     * As an example, if the value should include a slash ("/") not intended as
     * delimiter between path segments, that value MUST be passed in encoded
     * form (e.g., "%2F") to the instance.
     *
     * @see https://tools.ietf.org/html/rfc3986#section-2
     * @see https://tools.ietf.org/html/rfc3986#section-3.3
     * @return string The URI path.
     */
    public function getPath(): string;

    /**
     * Retrieve the query string of the URI.
     *
     * If no query string is present, this method MUST return an empty string.
     *
     * The leading "?" character is not part of the query and MUST NOT be
     * added.
     *
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
     * any characters. To determine what characters to encode, please refer to
     * RFC 3986, Sections 2 and 3.4.
     *
     * As an example, if a value in a key/value pair of the query string should
     * include an ampersand ("&") not intended as a delimiter between values,
     * that value MUST be passed in encoded form (e.g., "%26") to the instance.
     *
     * @see https://tools.ietf.org/html/rfc3986#section-2
     * @see https://tools.ietf.org/html/rfc3986#section-3.4
     * @return string The URI query string.
     */
    public function getQuery(): string;

    /**
     * Retrieve the fragment component of the URI.
     *
     * If no fragment is present, this method MUST return an empty string.
     *
     * The leading "#" character is not part of the fragment and MUST NOT be
     * added.
     *
     * The value returned MUST be percent-encoded, but MUST NOT double-encode
     * any characters. To determine what characters to encode, please refer to
     * RFC 3986, Sections 2 and 3.5.
     *
     * @see https://tools.ietf.org/html/rfc3986#section-2
     * @see https://tools.ietf.org/html/rfc3986#section-3.5
     * @return string The URI fragment.
     */
    public function getFragment(): string;

    /**
     * Return an instance with the specified scheme.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified scheme.
     *
     * Implementations MUST support the schemes "http" and "https" case
     * insensitively, and MAY accommodate other schemes if required.
     *
     * An empty scheme is equivalent to removing the scheme.
     *
     * @param string $scheme The scheme to use with the new instance.
     * @return static A new instance with the specified scheme.
     * @throws \InvalidArgumentException for invalid or unsupported schemes.
     */
    public function withScheme(string $scheme): UriInterface;

    /**
     * Return an instance with the specified user information.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified user information.
     *
     * Password is optional, but the user information MUST include the
     * user; an empty string for the user is equivalent to removing user
     * information.
     *
     * @param string $user The user name to use for authority.
     * @param null|string $password The password associated with $user.
     * @return static A new instance with the specified user information.
     */
    public function withUserInfo(string $user, ?string $password = null): UriInterface;

    /**
     * Return an instance with the specified host.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified host.
     *
     * An empty host value is equivalent to removing the host.
     *
     * @param string $host The hostname to use with the new instance.
     * @return static A new instance with the specified host.
     * @throws \InvalidArgumentException for invalid hostnames.
     */
    public function withHost(string $host): UriInterface;

    /**
     * Return an instance with the specified port.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified port.
     *
     * Implementations MUST raise an exception for ports outside the
     * established TCP and UDP port ranges.
     *
     * A null value provided for the port is equivalent to removing the port
     * information.
     *
     * @param null|int $port The port to use with the new instance; a null value
     *     removes the port information.
     * @return static A new instance with the specified port.
     * @throws \InvalidArgumentException for invalid ports.
     */
    public function withPort(?int $port): UriInterface;

    /**
     * Return an instance with the specified path.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified path.
     *
     * The path can either be empty or absolute (starting with a slash) or
     * rootless (not starting with a slash). Implementations MUST support all
     * three syntaxes.
     *
     * If the path is intended to be domain-relative rather than path relative then
     * it must begin with a slash ("/"). Paths not starting with a slash ("/")
     * are assumed to be relative to some base path known to the application or
     * consumer.
     *
     * Users can provide both encoded and decoded path characters.
     * Implementations ensure the correct encoding as outlined in getPath().
     *
     * @param string $path The path to use with the new instance.
     * @return static A new instance with the specified path.
     * @throws \InvalidArgumentException for invalid paths.
     */
    public function withPath(string $path): UriInterface;

    /**
     * Return an instance with the specified query string.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified query string.
     *
     * Users can provide both encoded and decoded query characters.
     * Implementations ensure the correct encoding as outlined in getQuery().
     *
     * An empty query string value is equivalent to removing the query string.
     *
     * @param string $query The query string to use with the new instance.
     * @return static A new instance with the specified query string.
     * @throws \InvalidArgumentException for invalid query strings.
     */
    public function withQuery(string $query): UriInterface;

    /**
     * Return an instance with the specified URI fragment.
     *
     * This method MUST retain the state of the current instance, and return
     * an instance that contains the specified URI fragment.
     *
     * Users can provide both encoded and decoded fragment characters.
     * Implementations ensure the correct encoding as outlined in getFragment().
     *
     * An empty fragment value is equivalent to removing the fragment.
     *
     * @param string $fragment The fragment to use with the new instance.
     * @return static A new instance with the specified fragment.
     */
    public function withFragment(string $fragment): UriInterface;

    /**
     * Return the string representation as a URI reference.
     *
     * Depending on which components of the URI are present, the resulting
     * string is either a full URI or relative reference according to RFC 3986,
     * Section 4.1. The method concatenates the various components of the URI,
     * using the appropriate delimiters:
     *
     * - If a scheme is present, it MUST be suffixed by ":".
     * - If an authority is present, it MUST be prefixed by "//".
     * - The path can be concatenated without delimiters. But there are two
     *   cases where the path has to be adjusted to make the URI reference
     *   valid as PHP does not allow to throw an exception in __toString():
     *     - If the path is rootless and an authority is present, the path MUST
     *       be prefixed by "/".
     *     - If the path is starting with more than one "/" and no authority is
     *       present, the starting slashes MUST be reduced to one.
     * - If a query is present, it MUST be prefixed by "?".
     * - If a fragment is present, it MUST be prefixed by "#".
     *
     * @see http://tools.ietf.org/html/rfc3986#section-4.1
     * @return string
     */
    public function __toString(): string;
}
<?php

namespace Psr\Log;

/**
 * This is a simple Logger implementation that other Loggers can inherit from.
 *
 * It simply delegates all log-level-specific methods to the `log` method to
 * reduce boilerplate code that a simple Logger that does the same thing with
 * messages regardless of the error level has to implement.
 */
abstract class AbstractLogger implements LoggerInterface
{
    use LoggerTrait;
}
<?php

namespace Psr\Log;

class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php

namespace Psr\Log;

/**
 * Describes a logger-aware instance.
 */
interface LoggerAwareInterface
{
    /**
     * Sets a logger instance on the object.
     */
    public function setLogger(LoggerInterface $logger): void;
}
<?php

namespace Psr\Log;

/**
 * Basic Implementation of LoggerAwareInterface.
 */
trait LoggerAwareTrait
{
    /**
     * The logger instance.
     */
    protected ?LoggerInterface $logger = null;

    /**
     * Sets a logger.
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }
}
<?php

namespace Psr\Log;

/**
 * Describes a logger instance.
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data. The only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param mixed[] $context
     */
    public function emergency(string|\Stringable $message, array $context = []): void;

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param mixed[] $context
     */
    public function alert(string|\Stringable $message, array $context = []): void;

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param mixed[] $context
     */
    public function critical(string|\Stringable $message, array $context = []): void;

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param mixed[] $context
     */
    public function error(string|\Stringable $message, array $context = []): void;

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param mixed[] $context
     */
    public function warning(string|\Stringable $message, array $context = []): void;

    /**
     * Normal but significant events.
     *
     * @param mixed[] $context
     */
    public function notice(string|\Stringable $message, array $context = []): void;

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param mixed[] $context
     */
    public function info(string|\Stringable $message, array $context = []): void;

    /**
     * Detailed debug information.
     *
     * @param mixed[] $context
     */
    public function debug(string|\Stringable $message, array $context = []): void;

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param mixed[] $context
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, string|\Stringable $message, array $context = []): void;
}
<?php

namespace Psr\Log;

/**
 * This is a simple Logger trait that classes unable to extend AbstractLogger
 * (because they extend another class, etc) can include.
 *
 * It simply delegates all log-level-specific methods to the `log` method to
 * reduce boilerplate code that a simple Logger that does the same thing with
 * messages regardless of the error level has to implement.
 */
trait LoggerTrait
{
    /**
     * System is unusable.
     */
    public function emergency(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::EMERGENCY, $message, $context);
    }

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     */
    public function alert(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::ALERT, $message, $context);
    }

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     */
    public function critical(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::CRITICAL, $message, $context);
    }

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     */
    public function error(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::ERROR, $message, $context);
    }

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     */
    public function warning(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::WARNING, $message, $context);
    }

    /**
     * Normal but significant events.
     */
    public function notice(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::NOTICE, $message, $context);
    }

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     */
    public function info(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::INFO, $message, $context);
    }

    /**
     * Detailed debug information.
     */
    public function debug(string|\Stringable $message, array $context = []): void
    {
        $this->log(LogLevel::DEBUG, $message, $context);
    }

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    abstract public function log($level, string|\Stringable $message, array $context = []): void;
}
<?php

namespace Psr\Log;

/**
 * Describes log levels.
 */
class LogLevel
{
    const EMERGENCY = 'emergency';
    const ALERT     = 'alert';
    const CRITICAL  = 'critical';
    const ERROR     = 'error';
    const WARNING   = 'warning';
    const NOTICE    = 'notice';
    const INFO      = 'info';
    const DEBUG     = 'debug';
}
<?php

namespace Psr\Log;

/**
 * This Logger can be used to avoid conditional log calls.
 *
 * Logging should always be optional, and if no logger is provided to your
 * library creating a NullLogger instance to have something to throw logs at
 * is a good way to avoid littering your code with `if ($this->logger) { }`
 * blocks.
 */
class NullLogger extends AbstractLogger
{
    /**
     * Logs with an arbitrary level.
     *
     * @param mixed[] $context
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, string|\Stringable $message, array $context = []): void
    {
        // noop
    }
}
<?php

if (!function_exists('getallheaders')) {

    /**
     * Get all HTTP header key/values as an associative array for the current request.
     *
     * @return string[string] The HTTP header key/value pairs.
     */
    function getallheaders()
    {
        $headers = array();

        $copy_server = array(
            'CONTENT_TYPE'   => 'Content-Type',
            'CONTENT_LENGTH' => 'Content-Length',
            'CONTENT_MD5'    => 'Content-Md5',
        );

        foreach ($_SERVER as $key => $value) {
            if (substr($key, 0, 5) === 'HTTP_') {
                $key = substr($key, 5);
                if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
                    $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
                    $headers[$key] = $value;
                }
            } elseif (isset($copy_server[$key])) {
                $headers[$copy_server[$key]] = $value;
            }
        }

        if (!isset($headers['Authorization'])) {
            if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
                $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
            } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
                $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
                $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
            } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
                $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
            }
        }

        return $headers;
    }

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\CompleteCommand;
use Symfony\Component\Console\Command\DumpCompletionCommand;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\LazyCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\Command\SignalableCommandInterface;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleSignalEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputAwareInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SignalRegistry\SignalRegistry;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\ErrorHandler\ErrorHandler;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
 * An Application is the container for a collection of commands.
 *
 * It is the main entry point of a Console application.
 *
 * This class is optimized for a standard CLI environment.
 *
 * Usage:
 *
 *     $app = new Application('myapp', '1.0 (stable)');
 *     $app->add(new SimpleCommand());
 *     $app->run();
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Application implements ResetInterface
{
    private array $commands = [];
    private bool $wantHelps = false;
    private ?Command $runningCommand = null;
    private string $name;
    private string $version;
    private ?CommandLoaderInterface $commandLoader = null;
    private bool $catchExceptions = true;
    private bool $catchErrors = false;
    private bool $autoExit = true;
    private InputDefinition $definition;
    private HelperSet $helperSet;
    private ?EventDispatcherInterface $dispatcher = null;
    private Terminal $terminal;
    private string $defaultCommand;
    private bool $singleCommand = false;
    private bool $initialized = false;
    private ?SignalRegistry $signalRegistry = null;
    private array $signalsToDispatchEvent = [];

    public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
    {
        $this->name = $name;
        $this->version = $version;
        $this->terminal = new Terminal();
        $this->defaultCommand = 'list';
        if (\defined('SIGINT') && SignalRegistry::isSupported()) {
            $this->signalRegistry = new SignalRegistry();
            $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2];
        }
    }

    /**
     * @final
     */
    public function setDispatcher(EventDispatcherInterface $dispatcher): void
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * @return void
     */
    public function setCommandLoader(CommandLoaderInterface $commandLoader)
    {
        $this->commandLoader = $commandLoader;
    }

    public function getSignalRegistry(): SignalRegistry
    {
        if (!$this->signalRegistry) {
            throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
        }

        return $this->signalRegistry;
    }

    /**
     * @return void
     */
    public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
    {
        $this->signalsToDispatchEvent = $signalsToDispatchEvent;
    }

    /**
     * Runs the current application.
     *
     * @return int 0 if everything went fine, or an error code
     *
     * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
     */
    public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
    {
        if (\function_exists('putenv')) {
            @putenv('LINES='.$this->terminal->getHeight());
            @putenv('COLUMNS='.$this->terminal->getWidth());
        }

        $input ??= new ArgvInput();
        $output ??= new ConsoleOutput();

        $renderException = function (\Throwable $e) use ($output) {
            if ($output instanceof ConsoleOutputInterface) {
                $this->renderThrowable($e, $output->getErrorOutput());
            } else {
                $this->renderThrowable($e, $output);
            }
        };
        if ($phpHandler = set_exception_handler($renderException)) {
            restore_exception_handler();
            if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
                $errorHandler = true;
            } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
                $phpHandler[0]->setExceptionHandler($errorHandler);
            }
        }

        try {
            $this->configureIO($input, $output);

            $exitCode = $this->doRun($input, $output);
        } catch (\Throwable $e) {
            if ($e instanceof \Exception && !$this->catchExceptions) {
                throw $e;
            }
            if (!$e instanceof \Exception && !$this->catchErrors) {
                throw $e;
            }

            $renderException($e);

            $exitCode = $e->getCode();
            if (is_numeric($exitCode)) {
                $exitCode = (int) $exitCode;
                if ($exitCode <= 0) {
                    $exitCode = 1;
                }
            } else {
                $exitCode = 1;
            }
        } finally {
            // if the exception handler changed, keep it
            // otherwise, unregister $renderException
            if (!$phpHandler) {
                if (set_exception_handler($renderException) === $renderException) {
                    restore_exception_handler();
                }
                restore_exception_handler();
            } elseif (!$errorHandler) {
                $finalHandler = $phpHandler[0]->setExceptionHandler(null);
                if ($finalHandler !== $renderException) {
                    $phpHandler[0]->setExceptionHandler($finalHandler);
                }
            }
        }

        if ($this->autoExit) {
            if ($exitCode > 255) {
                $exitCode = 255;
            }

            exit($exitCode);
        }

        return $exitCode;
    }

    /**
     * Runs the current application.
     *
     * @return int 0 if everything went fine, or an error code
     */
    public function doRun(InputInterface $input, OutputInterface $output)
    {
        if (true === $input->hasParameterOption(['--version', '-V'], true)) {
            $output->writeln($this->getLongVersion());

            return 0;
        }

        try {
            // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
            $input->bind($this->getDefinition());
        } catch (ExceptionInterface) {
            // Errors must be ignored, full binding/validation happens later when the command is known.
        }

        $name = $this->getCommandName($input);
        if (true === $input->hasParameterOption(['--help', '-h'], true)) {
            if (!$name) {
                $name = 'help';
                $input = new ArrayInput(['command_name' => $this->defaultCommand]);
            } else {
                $this->wantHelps = true;
            }
        }

        if (!$name) {
            $name = $this->defaultCommand;
            $definition = $this->getDefinition();
            $definition->setArguments(array_merge(
                $definition->getArguments(),
                [
                    'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
                ]
            ));
        }

        try {
            $this->runningCommand = null;
            // the command name MUST be the first element of the input
            $command = $this->find($name);
        } catch (\Throwable $e) {
            if (($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) {
                $alternative = $alternatives[0];

                $style = new SymfonyStyle($input, $output);
                $output->writeln('');
                $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true);
                $output->writeln($formattedBlock);
                if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) {
                    if (null !== $this->dispatcher) {
                        $event = new ConsoleErrorEvent($input, $output, $e);
                        $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);

                        return $event->getExitCode();
                    }

                    return 1;
                }

                $command = $this->find($alternative);
            } else {
                if (null !== $this->dispatcher) {
                    $event = new ConsoleErrorEvent($input, $output, $e);
                    $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);

                    if (0 === $event->getExitCode()) {
                        return 0;
                    }

                    $e = $event->getError();
                }

                try {
                    if ($e instanceof CommandNotFoundException && $namespace = $this->findNamespace($name)) {
                        $helper = new DescriptorHelper();
                        $helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, [
                            'format' => 'txt',
                            'raw_text' => false,
                            'namespace' => $namespace,
                            'short' => false,
                        ]);

                        return isset($event) ? $event->getExitCode() : 1;
                    }

                    throw $e;
                } catch (NamespaceNotFoundException) {
                    throw $e;
                }
            }
        }

        if ($command instanceof LazyCommand) {
            $command = $command->getCommand();
        }

        $this->runningCommand = $command;
        $exitCode = $this->doRunCommand($command, $input, $output);
        $this->runningCommand = null;

        return $exitCode;
    }

    /**
     * @return void
     */
    public function reset()
    {
    }

    /**
     * @return void
     */
    public function setHelperSet(HelperSet $helperSet)
    {
        $this->helperSet = $helperSet;
    }

    /**
     * Get the helper set associated with the command.
     */
    public function getHelperSet(): HelperSet
    {
        return $this->helperSet ??= $this->getDefaultHelperSet();
    }

    /**
     * @return void
     */
    public function setDefinition(InputDefinition $definition)
    {
        $this->definition = $definition;
    }

    /**
     * Gets the InputDefinition related to this Application.
     */
    public function getDefinition(): InputDefinition
    {
        $this->definition ??= $this->getDefaultInputDefinition();

        if ($this->singleCommand) {
            $inputDefinition = $this->definition;
            $inputDefinition->setArguments();

            return $inputDefinition;
        }

        return $this->definition;
    }

    /**
     * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
     */
    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        if (
            CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType()
            && 'command' === $input->getCompletionName()
        ) {
            foreach ($this->all() as $name => $command) {
                // skip hidden commands and aliased commands as they already get added below
                if ($command->isHidden() || $command->getName() !== $name) {
                    continue;
                }
                $suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription()));
                foreach ($command->getAliases() as $name) {
                    $suggestions->suggestValue(new Suggestion($name, $command->getDescription()));
                }
            }

            return;
        }

        if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) {
            $suggestions->suggestOptions($this->getDefinition()->getOptions());

            return;
        }
    }

    /**
     * Gets the help message.
     */
    public function getHelp(): string
    {
        return $this->getLongVersion();
    }

    /**
     * Gets whether to catch exceptions or not during commands execution.
     */
    public function areExceptionsCaught(): bool
    {
        return $this->catchExceptions;
    }

    /**
     * Sets whether to catch exceptions or not during commands execution.
     *
     * @return void
     */
    public function setCatchExceptions(bool $boolean)
    {
        $this->catchExceptions = $boolean;
    }

    /**
     * Sets whether to catch errors or not during commands execution.
     */
    public function setCatchErrors(bool $catchErrors = true): void
    {
        $this->catchErrors = $catchErrors;
    }

    /**
     * Gets whether to automatically exit after a command execution or not.
     */
    public function isAutoExitEnabled(): bool
    {
        return $this->autoExit;
    }

    /**
     * Sets whether to automatically exit after a command execution or not.
     *
     * @return void
     */
    public function setAutoExit(bool $boolean)
    {
        $this->autoExit = $boolean;
    }

    /**
     * Gets the name of the application.
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * Sets the application name.
     *
     * @return void
     */
    public function setName(string $name)
    {
        $this->name = $name;
    }

    /**
     * Gets the application version.
     */
    public function getVersion(): string
    {
        return $this->version;
    }

    /**
     * Sets the application version.
     *
     * @return void
     */
    public function setVersion(string $version)
    {
        $this->version = $version;
    }

    /**
     * Returns the long version of the application.
     *
     * @return string
     */
    public function getLongVersion()
    {
        if ('UNKNOWN' !== $this->getName()) {
            if ('UNKNOWN' !== $this->getVersion()) {
                return \sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());
            }

            return $this->getName();
        }

        return 'Console Tool';
    }

    /**
     * Registers a new command.
     */
    public function register(string $name): Command
    {
        return $this->add(new Command($name));
    }

    /**
     * Adds an array of command objects.
     *
     * If a Command is not enabled it will not be added.
     *
     * @param Command[] $commands An array of commands
     *
     * @return void
     */
    public function addCommands(array $commands)
    {
        foreach ($commands as $command) {
            $this->add($command);
        }
    }

    /**
     * Adds a command object.
     *
     * If a command with the same name already exists, it will be overridden.
     * If the command is not enabled it will not be added.
     *
     * @return Command|null
     */
    public function add(Command $command)
    {
        $this->init();

        $command->setApplication($this);

        if (!$command->isEnabled()) {
            $command->setApplication(null);

            return null;
        }

        if (!$command instanceof LazyCommand) {
            // Will throw if the command is not correctly initialized.
            $command->getDefinition();
        }

        if (!$command->getName()) {
            throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command)));
        }

        $this->commands[$command->getName()] = $command;

        foreach ($command->getAliases() as $alias) {
            $this->commands[$alias] = $command;
        }

        return $command;
    }

    /**
     * Returns a registered command by name or alias.
     *
     * @return Command
     *
     * @throws CommandNotFoundException When given command name does not exist
     */
    public function get(string $name)
    {
        $this->init();

        if (!$this->has($name)) {
            throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name));
        }

        // When the command has a different name than the one used at the command loader level
        if (!isset($this->commands[$name])) {
            throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
        }

        $command = $this->commands[$name];

        if ($this->wantHelps) {
            $this->wantHelps = false;

            $helpCommand = $this->get('help');
            $helpCommand->setCommand($command);

            return $helpCommand;
        }

        return $command;
    }

    /**
     * Returns true if the command exists, false otherwise.
     */
    public function has(string $name): bool
    {
        $this->init();

        return isset($this->commands[$name]) || ($this->commandLoader?->has($name) && $this->add($this->commandLoader->get($name)));
    }

    /**
     * Returns an array of all unique namespaces used by currently registered commands.
     *
     * It does not return the global namespace which always exists.
     *
     * @return string[]
     */
    public function getNamespaces(): array
    {
        $namespaces = [];
        foreach ($this->all() as $command) {
            if ($command->isHidden()) {
                continue;
            }

            $namespaces[] = $this->extractAllNamespaces($command->getName());

            foreach ($command->getAliases() as $alias) {
                $namespaces[] = $this->extractAllNamespaces($alias);
            }
        }

        return array_values(array_unique(array_filter(array_merge([], ...$namespaces))));
    }

    /**
     * Finds a registered namespace by a name or an abbreviation.
     *
     * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
     */
    public function findNamespace(string $namespace): string
    {
        $allNamespaces = $this->getNamespaces();
        $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*';
        $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);

        if (empty($namespaces)) {
            $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace);

            if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
                if (1 == \count($alternatives)) {
                    $message .= "\n\nDid you mean this?\n    ";
                } else {
                    $message .= "\n\nDid you mean one of these?\n    ";
                }

                $message .= implode("\n    ", $alternatives);
            }

            throw new NamespaceNotFoundException($message, $alternatives);
        }

        $exact = \in_array($namespace, $namespaces, true);
        if (\count($namespaces) > 1 && !$exact) {
            throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
        }

        return $exact ? $namespace : reset($namespaces);
    }

    /**
     * Finds a command by name or alias.
     *
     * Contrary to get, this command tries to find the best
     * match if you give it an abbreviation of a name or alias.
     *
     * @return Command
     *
     * @throws CommandNotFoundException When command name is incorrect or ambiguous
     */
    public function find(string $name)
    {
        $this->init();

        $aliases = [];

        foreach ($this->commands as $command) {
            foreach ($command->getAliases() as $alias) {
                if (!$this->has($alias)) {
                    $this->commands[$alias] = $command;
                }
            }
        }

        if ($this->has($name)) {
            return $this->get($name);
        }

        $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
        $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*';
        $commands = preg_grep('{^'.$expr.'}', $allCommands);

        if (empty($commands)) {
            $commands = preg_grep('{^'.$expr.'}i', $allCommands);
        }

        // if no commands matched or we just matched namespaces
        if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
            if (false !== $pos = strrpos($name, ':')) {
                // check if a namespace exists and contains commands
                $this->findNamespace(substr($name, 0, $pos));
            }

            $message = \sprintf('Command "%s" is not defined.', $name);

            if ($alternatives = $this->findAlternatives($name, $allCommands)) {
                // remove hidden commands
                $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden());

                if (1 == \count($alternatives)) {
                    $message .= "\n\nDid you mean this?\n    ";
                } else {
                    $message .= "\n\nDid you mean one of these?\n    ";
                }
                $message .= implode("\n    ", $alternatives);
            }

            throw new CommandNotFoundException($message, array_values($alternatives));
        }

        // filter out aliases for commands which are already on the list
        if (\count($commands) > 1) {
            $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
            $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
                if (!$commandList[$nameOrAlias] instanceof Command) {
                    $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
                }

                $commandName = $commandList[$nameOrAlias]->getName();

                $aliases[$nameOrAlias] = $commandName;

                return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
            }));
        }

        if (\count($commands) > 1) {
            $usableWidth = $this->terminal->getWidth() - 10;
            $abbrevs = array_values($commands);
            $maxLen = 0;
            foreach ($abbrevs as $abbrev) {
                $maxLen = max(Helper::width($abbrev), $maxLen);
            }
            $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) {
                if ($commandList[$cmd]->isHidden()) {
                    unset($commands[array_search($cmd, $commands)]);

                    return false;
                }

                $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();

                return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
            }, array_values($commands));

            if (\count($commands) > 1) {
                $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));

                throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands));
            }
        }

        $command = $this->get(reset($commands));

        if ($command->isHidden()) {
            throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name));
        }

        return $command;
    }

    /**
     * Gets the commands (registered in the given namespace if provided).
     *
     * The array keys are the full names and the values the command instances.
     *
     * @return Command[]
     */
    public function all(?string $namespace = null)
    {
        $this->init();

        if (null === $namespace) {
            if (!$this->commandLoader) {
                return $this->commands;
            }

            $commands = $this->commands;
            foreach ($this->commandLoader->getNames() as $name) {
                if (!isset($commands[$name]) && $this->has($name)) {
                    $commands[$name] = $this->get($name);
                }
            }

            return $commands;
        }

        $commands = [];
        foreach ($this->commands as $name => $command) {
            if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
                $commands[$name] = $command;
            }
        }

        if ($this->commandLoader) {
            foreach ($this->commandLoader->getNames() as $name) {
                if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) {
                    $commands[$name] = $this->get($name);
                }
            }
        }

        return $commands;
    }

    /**
     * Returns an array of possible abbreviations given a set of names.
     *
     * @return string[][]
     */
    public static function getAbbreviations(array $names): array
    {
        $abbrevs = [];
        foreach ($names as $name) {
            for ($len = \strlen($name); $len > 0; --$len) {
                $abbrev = substr($name, 0, $len);
                $abbrevs[$abbrev][] = $name;
            }
        }

        return $abbrevs;
    }

    public function renderThrowable(\Throwable $e, OutputInterface $output): void
    {
        $output->writeln('', OutputInterface::VERBOSITY_QUIET);

        $this->doRenderThrowable($e, $output);

        if (null !== $this->runningCommand) {
            $output->writeln(\sprintf('<info>%s</info>', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
            $output->writeln('', OutputInterface::VERBOSITY_QUIET);
        }
    }

    protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void
    {
        do {
            $message = trim($e->getMessage());
            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $class = get_debug_type($e);
                $title = \sprintf('  [%s%s]  ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
                $len = Helper::width($title);
            } else {
                $len = 0;
            }

            if (str_contains($message, "@anonymous\0")) {
                $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message);
            }

            $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
            $lines = [];
            foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) {
                foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
                    // pre-format lines to get the right string length
                    $lineLength = Helper::width($line) + 4;
                    $lines[] = [$line, $lineLength];

                    $len = max($lineLength, $len);
                }
            }

            $messages = [];
            if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $messages[] = \sprintf('<comment>%s</comment>', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
            }
            $messages[] = $emptyLine = \sprintf('<error>%s</error>', str_repeat(' ', $len));
            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $messages[] = \sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::width($title))));
            }
            foreach ($lines as $line) {
                $messages[] = \sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));
            }
            $messages[] = $emptyLine;
            $messages[] = '';

            $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);

            if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);

                // exception related properties
                $trace = $e->getTrace();

                array_unshift($trace, [
                    'function' => '',
                    'file' => $e->getFile() ?: 'n/a',
                    'line' => $e->getLine() ?: 'n/a',
                    'args' => [],
                ]);

                for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
                    $class = $trace[$i]['class'] ?? '';
                    $type = $trace[$i]['type'] ?? '';
                    $function = $trace[$i]['function'] ?? '';
                    $file = $trace[$i]['file'] ?? 'n/a';
                    $line = $trace[$i]['line'] ?? 'n/a';

                    $output->writeln(\sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
                }

                $output->writeln('', OutputInterface::VERBOSITY_QUIET);
            }
        } while ($e = $e->getPrevious());
    }

    /**
     * Configures the input and output instances based on the user arguments and options.
     *
     * @return void
     */
    protected function configureIO(InputInterface $input, OutputInterface $output)
    {
        if (true === $input->hasParameterOption(['--ansi'], true)) {
            $output->setDecorated(true);
        } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {
            $output->setDecorated(false);
        }

        if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {
            $input->setInteractive(false);
        }

        switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
            case -1:
                $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
                break;
            case 1:
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
                break;
            case 2:
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
                break;
            case 3:
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
                break;
            default:
                $shellVerbosity = 0;
                break;
        }

        if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
            $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
            $shellVerbosity = -1;
        } else {
            if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
                $shellVerbosity = 3;
            } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
                $shellVerbosity = 2;
            } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
                $shellVerbosity = 1;
            }
        }

        if (-1 === $shellVerbosity) {
            $input->setInteractive(false);
        }

        if (\function_exists('putenv')) {
            @putenv('SHELL_VERBOSITY='.$shellVerbosity);
        }
        $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
        $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
    }

    /**
     * Runs the current command.
     *
     * If an event dispatcher has been attached to the application,
     * events are also dispatched during the life-cycle of the command.
     *
     * @return int 0 if everything went fine, or an error code
     */
    protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
    {
        foreach ($command->getHelperSet() as $helper) {
            if ($helper instanceof InputAwareInterface) {
                $helper->setInput($input);
            }
        }

        $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
        if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) {
            if (!$this->signalRegistry) {
                throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
            }

            if (Terminal::hasSttyAvailable()) {
                $sttyMode = shell_exec('stty -g');

                foreach ([\SIGINT, \SIGTERM] as $signal) {
                    $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode));
                }
            }

            if ($this->dispatcher) {
                // We register application signals, so that we can dispatch the event
                foreach ($this->signalsToDispatchEvent as $signal) {
                    $event = new ConsoleSignalEvent($command, $input, $output, $signal);

                    $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) {
                        $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
                        $exitCode = $event->getExitCode();

                        // If the command is signalable, we call the handleSignal() method
                        if (\in_array($signal, $commandSignals, true)) {
                            $exitCode = $command->handleSignal($signal, $exitCode);
                            // BC layer for Symfony <= 5
                            if (null === $exitCode) {
                                trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
                                $exitCode = 0;
                            }
                        }

                        if (false !== $exitCode) {
                            $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal);
                            $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);

                            exit($event->getExitCode());
                        }
                    });
                }

                // then we register command signals, but not if already handled after the dispatcher
                $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent);
            }

            foreach ($commandSignals as $signal) {
                $this->signalRegistry->register($signal, function (int $signal) use ($command): void {
                    $exitCode = $command->handleSignal($signal);
                    // BC layer for Symfony <= 5
                    if (null === $exitCode) {
                        trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
                        $exitCode = 0;
                    }

                    if (false !== $exitCode) {
                        exit($exitCode);
                    }
                });
            }
        }

        if (null === $this->dispatcher) {
            return $command->run($input, $output);
        }

        // bind before the console.command event, so the listeners have access to input options/arguments
        try {
            $command->mergeApplicationDefinition();
            $input->bind($command->getDefinition());
        } catch (ExceptionInterface) {
            // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
        }

        $event = new ConsoleCommandEvent($command, $input, $output);
        $e = null;

        try {
            $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);

            if ($event->commandShouldRun()) {
                $exitCode = $command->run($input, $output);
            } else {
                $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
            }
        } catch (\Throwable $e) {
            $event = new ConsoleErrorEvent($input, $output, $e, $command);
            $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
            $e = $event->getError();

            if (0 === $exitCode = $event->getExitCode()) {
                $e = null;
            }
        }

        $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
        $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);

        if (null !== $e) {
            throw $e;
        }

        return $event->getExitCode();
    }

    /**
     * Gets the name of the command based on input.
     */
    protected function getCommandName(InputInterface $input): ?string
    {
        return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
    }

    /**
     * Gets the default input definition.
     */
    protected function getDefaultInputDefinition(): InputDefinition
    {
        return new InputDefinition([
            new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
            new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the <info>'.$this->defaultCommand.'</info> command'),
            new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
            new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
            new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
            new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null),
            new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
        ]);
    }

    /**
     * Gets the default commands that should always be available.
     *
     * @return Command[]
     */
    protected function getDefaultCommands(): array
    {
        return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()];
    }

    /**
     * Gets the default helper set with the helpers that should always be available.
     */
    protected function getDefaultHelperSet(): HelperSet
    {
        return new HelperSet([
            new FormatterHelper(),
            new DebugFormatterHelper(),
            new ProcessHelper(),
            new QuestionHelper(),
        ]);
    }

    /**
     * Returns abbreviated suggestions in string format.
     */
    private function getAbbreviationSuggestions(array $abbrevs): string
    {
        return '    '.implode("\n    ", $abbrevs);
    }

    /**
     * Returns the namespace part of the command name.
     *
     * This method is not part of public API and should not be used directly.
     */
    public function extractNamespace(string $name, ?int $limit = null): string
    {
        $parts = explode(':', $name, -1);

        return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
    }

    /**
     * Finds alternative of $name among $collection,
     * if nothing is found in $collection, try in $abbrevs.
     *
     * @return string[]
     */
    private function findAlternatives(string $name, iterable $collection): array
    {
        $threshold = 1e3;
        $alternatives = [];

        $collectionParts = [];
        foreach ($collection as $item) {
            $collectionParts[$item] = explode(':', $item);
        }

        foreach (explode(':', $name) as $i => $subname) {
            foreach ($collectionParts as $collectionName => $parts) {
                $exists = isset($alternatives[$collectionName]);
                if (!isset($parts[$i]) && $exists) {
                    $alternatives[$collectionName] += $threshold;
                    continue;
                } elseif (!isset($parts[$i])) {
                    continue;
                }

                $lev = levenshtein($subname, $parts[$i]);
                if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {
                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
                } elseif ($exists) {
                    $alternatives[$collectionName] += $threshold;
                }
            }
        }

        foreach ($collection as $item) {
            $lev = levenshtein($name, $item);
            if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
            }
        }

        $alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold);
        ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);

        return array_keys($alternatives);
    }

    /**
     * Sets the default Command name.
     *
     * @return $this
     */
    public function setDefaultCommand(string $commandName, bool $isSingleCommand = false): static
    {
        $this->defaultCommand = explode('|', ltrim($commandName, '|'))[0];

        if ($isSingleCommand) {
            // Ensure the command exist
            $this->find($commandName);

            $this->singleCommand = true;
        }

        return $this;
    }

    /**
     * @internal
     */
    public function isSingleCommand(): bool
    {
        return $this->singleCommand;
    }

    private function splitStringByWidth(string $string, int $width): array
    {
        // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
        // additionally, array_slice() is not enough as some character has doubled width.
        // we need a function to split string not by character count but by string width
        if (false === $encoding = mb_detect_encoding($string, null, true)) {
            return str_split($string, $width);
        }

        $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
        $lines = [];
        $line = '';

        $offset = 0;
        while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
            $offset += \strlen($m[0]);

            foreach (preg_split('//u', $m[0]) as $char) {
                // test if $char could be appended to current line
                if (Helper::width($line.$char) <= $width) {
                    $line .= $char;
                    continue;
                }
                // if not, push current line to array and make new line
                $lines[] = str_pad($line, $width);
                $line = $char;
            }
        }

        $lines[] = \count($lines) ? str_pad($line, $width) : $line;

        mb_convert_variables($encoding, 'utf8', $lines);

        return $lines;
    }

    /**
     * Returns all namespaces of the command name.
     *
     * @return string[]
     */
    private function extractAllNamespaces(string $name): array
    {
        // -1 as third argument is needed to skip the command short name when exploding
        $parts = explode(':', $name, -1);
        $namespaces = [];

        foreach ($parts as $part) {
            if (\count($namespaces)) {
                $namespaces[] = end($namespaces).':'.$part;
            } else {
                $namespaces[] = $part;
            }
        }

        return $namespaces;
    }

    private function init(): void
    {
        if ($this->initialized) {
            return;
        }
        $this->initialized = true;

        foreach ($this->getDefaultCommands() as $command) {
            $this->add($command);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Attribute;

/**
 * Service tag to autoconfigure commands.
 */
#[\Attribute(\Attribute::TARGET_CLASS)]
class AsCommand
{
    public function __construct(
        public string $name,
        public ?string $description = null,
        array $aliases = [],
        bool $hidden = false,
    ) {
        if (!$hidden && !$aliases) {
            return;
        }

        $name = explode('|', $name);
        $name = array_merge($name, $aliases);

        if ($hidden && '' !== $name[0]) {
            array_unshift($name, '');
        }

        $this->name = implode('|', $name);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\CI;

use Symfony\Component\Console\Output\OutputInterface;

/**
 * Utility class for Github actions.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
class GithubActionReporter
{
    private OutputInterface $output;

    /**
     * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85
     */
    private const ESCAPED_DATA = [
        '%' => '%25',
        "\r" => '%0D',
        "\n" => '%0A',
    ];

    /**
     * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94
     */
    private const ESCAPED_PROPERTIES = [
        '%' => '%25',
        "\r" => '%0D',
        "\n" => '%0A',
        ':' => '%3A',
        ',' => '%2C',
    ];

    public function __construct(OutputInterface $output)
    {
        $this->output = $output;
    }

    public static function isGithubActionEnvironment(): bool
    {
        return false !== getenv('GITHUB_ACTIONS');
    }

    /**
     * Output an error using the Github annotations format.
     *
     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
     */
    public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
    {
        $this->log('error', $message, $file, $line, $col);
    }

    /**
     * Output a warning using the Github annotations format.
     *
     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
     */
    public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
    {
        $this->log('warning', $message, $file, $line, $col);
    }

    /**
     * Output a debug log using the Github annotations format.
     *
     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message
     */
    public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
    {
        $this->log('debug', $message, $file, $line, $col);
    }

    private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void
    {
        // Some values must be encoded.
        $message = strtr($message, self::ESCAPED_DATA);

        if (!$file) {
            // No file provided, output the message solely:
            $this->output->writeln(\sprintf('::%s::%s', $type, $message));

            return;
        }

        $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 */
final class Color
{
    private const COLORS = [
        'black' => 0,
        'red' => 1,
        'green' => 2,
        'yellow' => 3,
        'blue' => 4,
        'magenta' => 5,
        'cyan' => 6,
        'white' => 7,
        'default' => 9,
    ];

    private const BRIGHT_COLORS = [
        'gray' => 0,
        'bright-red' => 1,
        'bright-green' => 2,
        'bright-yellow' => 3,
        'bright-blue' => 4,
        'bright-magenta' => 5,
        'bright-cyan' => 6,
        'bright-white' => 7,
    ];

    private const AVAILABLE_OPTIONS = [
        '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 string $foreground;
    private string $background;
    private array $options = [];

    public function __construct(string $foreground = '', string $background = '', array $options = [])
    {
        $this->foreground = $this->parseColor($foreground);
        $this->background = $this->parseColor($background, true);

        foreach ($options as $option) {
            if (!isset(self::AVAILABLE_OPTIONS[$option])) {
                throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS))));
            }

            $this->options[$option] = self::AVAILABLE_OPTIONS[$option];
        }
    }

    public function apply(string $text): string
    {
        return $this->set().$text.$this->unset();
    }

    public function set(): string
    {
        $setCodes = [];
        if ('' !== $this->foreground) {
            $setCodes[] = $this->foreground;
        }
        if ('' !== $this->background) {
            $setCodes[] = $this->background;
        }
        foreach ($this->options as $option) {
            $setCodes[] = $option['set'];
        }
        if (0 === \count($setCodes)) {
            return '';
        }

        return \sprintf("\033[%sm", implode(';', $setCodes));
    }

    public function unset(): string
    {
        $unsetCodes = [];
        if ('' !== $this->foreground) {
            $unsetCodes[] = 39;
        }
        if ('' !== $this->background) {
            $unsetCodes[] = 49;
        }
        foreach ($this->options as $option) {
            $unsetCodes[] = $option['unset'];
        }
        if (0 === \count($unsetCodes)) {
            return '';
        }

        return \sprintf("\033[%sm", implode(';', $unsetCodes));
    }

    private function parseColor(string $color, bool $background = false): string
    {
        if ('' === $color) {
            return '';
        }

        if ('#' === $color[0]) {
            return ($background ? '4' : '3').Terminal::getColorMode()->convertFromHexToAnsiColorCode($color);
        }

        if (isset(self::COLORS[$color])) {
            return ($background ? '4' : '3').self::COLORS[$color];
        }

        if (isset(self::BRIGHT_COLORS[$color])) {
            return ($background ? '10' : '9').self::BRIGHT_COLORS[$color];
        }

        throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS)))));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Helper\HelperInterface;
use Symfony\Component\Console\Helper\HelperSet;
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;

/**
 * Base class for all commands.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Command
{
    // see https://tldp.org/LDP/abs/html/exitcodes.html
    public const SUCCESS = 0;
    public const FAILURE = 1;
    public const INVALID = 2;

    /**
     * @var string|null The default command name
     *
     * @deprecated since Symfony 6.1, use the AsCommand attribute instead
     */
    protected static $defaultName;

    /**
     * @var string|null The default command description
     *
     * @deprecated since Symfony 6.1, use the AsCommand attribute instead
     */
    protected static $defaultDescription;

    private ?Application $application = null;
    private ?string $name = null;
    private ?string $processTitle = null;
    private array $aliases = [];
    private InputDefinition $definition;
    private bool $hidden = false;
    private string $help = '';
    private string $description = '';
    private ?InputDefinition $fullDefinition = null;
    private bool $ignoreValidationErrors = false;
    private ?\Closure $code = null;
    private array $synopsis = [];
    private array $usages = [];
    private ?HelperSet $helperSet = null;

    public static function getDefaultName(): ?string
    {
        $class = static::class;

        if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
            return $attribute[0]->newInstance()->name;
        }

        $r = new \ReflectionProperty($class, 'defaultName');

        if ($class !== $r->class || null === static::$defaultName) {
            return null;
        }

        trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);

        return static::$defaultName;
    }

    public static function getDefaultDescription(): ?string
    {
        $class = static::class;

        if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
            return $attribute[0]->newInstance()->description;
        }

        $r = new \ReflectionProperty($class, 'defaultDescription');

        if ($class !== $r->class || null === static::$defaultDescription) {
            return null;
        }

        trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);

        return static::$defaultDescription;
    }

    /**
     * @param string|null $name The name of the command; passing null means it must be set in configure()
     *
     * @throws LogicException When the command name is empty
     */
    public function __construct(?string $name = null)
    {
        $this->definition = new InputDefinition();

        if (null === $name && null !== $name = static::getDefaultName()) {
            $aliases = explode('|', $name);

            if ('' === $name = array_shift($aliases)) {
                $this->setHidden(true);
                $name = array_shift($aliases);
            }

            $this->setAliases($aliases);
        }

        if (null !== $name) {
            $this->setName($name);
        }

        if ('' === $this->description) {
            $this->setDescription(static::getDefaultDescription() ?? '');
        }

        $this->configure();
    }

    /**
     * Ignores validation errors.
     *
     * This is mainly useful for the help command.
     *
     * @return void
     */
    public function ignoreValidationErrors()
    {
        $this->ignoreValidationErrors = true;
    }

    /**
     * @return void
     */
    public function setApplication(?Application $application = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        $this->application = $application;
        if ($application) {
            $this->setHelperSet($application->getHelperSet());
        } else {
            $this->helperSet = null;
        }

        $this->fullDefinition = null;
    }

    /**
     * @return void
     */
    public function setHelperSet(HelperSet $helperSet)
    {
        $this->helperSet = $helperSet;
    }

    /**
     * Gets the helper set.
     */
    public function getHelperSet(): ?HelperSet
    {
        return $this->helperSet;
    }

    /**
     * Gets the application instance for this command.
     */
    public function getApplication(): ?Application
    {
        return $this->application;
    }

    /**
     * Checks whether the command is enabled or not in the current environment.
     *
     * Override this to check for x or y and return false if the command cannot
     * run properly under the current conditions.
     *
     * @return bool
     */
    public function isEnabled()
    {
        return true;
    }

    /**
     * Configures the current command.
     *
     * @return void
     */
    protected function configure()
    {
    }

    /**
     * Executes the current command.
     *
     * This method is not abstract because you can use this class
     * as a concrete class. In this case, instead of defining the
     * execute() method, you set the code to execute by passing
     * a Closure to the setCode() method.
     *
     * @return int 0 if everything went fine, or an exit code
     *
     * @throws LogicException When this abstract method is not implemented
     *
     * @see setCode()
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        throw new LogicException('You must override the execute() method in the concrete command class.');
    }

    /**
     * Interacts with the user.
     *
     * This method is executed before the InputDefinition is validated.
     * This means that this is the only place where the command can
     * interactively ask for values of missing required arguments.
     *
     * @return void
     */
    protected function interact(InputInterface $input, OutputInterface $output)
    {
    }

    /**
     * Initializes the command after the input has been bound and before the input
     * is validated.
     *
     * This is mainly useful when a lot of commands extends one main command
     * where some things need to be initialized based on the input arguments and options.
     *
     * @see InputInterface::bind()
     * @see InputInterface::validate()
     *
     * @return void
     */
    protected function initialize(InputInterface $input, OutputInterface $output)
    {
    }

    /**
     * Runs the command.
     *
     * The code to execute is either defined directly with the
     * setCode() method or by overriding the execute() method
     * in a sub-class.
     *
     * @return int The command exit code
     *
     * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}.
     *
     * @see setCode()
     * @see execute()
     */
    public function run(InputInterface $input, OutputInterface $output): int
    {
        // add the application arguments and options
        $this->mergeApplicationDefinition();

        // bind the input against the command specific arguments/options
        try {
            $input->bind($this->getDefinition());
        } catch (ExceptionInterface $e) {
            if (!$this->ignoreValidationErrors) {
                throw $e;
            }
        }

        $this->initialize($input, $output);

        if (null !== $this->processTitle) {
            if (\function_exists('cli_set_process_title')) {
                if (!@cli_set_process_title($this->processTitle)) {
                    if ('Darwin' === \PHP_OS) {
                        $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
                    } else {
                        cli_set_process_title($this->processTitle);
                    }
                }
            } elseif (\function_exists('setproctitle')) {
                setproctitle($this->processTitle);
            } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
                $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
            }
        }

        if ($input->isInteractive()) {
            $this->interact($input, $output);
        }

        // The command name argument is often omitted when a command is executed directly with its run() method.
        // It would fail the validation if we didn't make sure the command argument is present,
        // since it's required by the application.
        if ($input->hasArgument('command') && null === $input->getArgument('command')) {
            $input->setArgument('command', $this->getName());
        }

        $input->validate();

        if ($this->code) {
            $statusCode = ($this->code)($input, $output);
        } else {
            $statusCode = $this->execute($input, $output);

            if (!\is_int($statusCode)) {
                throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode)));
            }
        }

        return is_numeric($statusCode) ? (int) $statusCode : 0;
    }

    /**
     * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
     */
    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        $definition = $this->getDefinition();
        if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) {
            $definition->getOption($input->getCompletionName())->complete($input, $suggestions);
        } elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) {
            $definition->getArgument($input->getCompletionName())->complete($input, $suggestions);
        }
    }

    /**
     * Sets the code to execute when running this command.
     *
     * If this method is used, it overrides the code defined
     * in the execute() method.
     *
     * @param callable $code A callable(InputInterface $input, OutputInterface $output)
     *
     * @return $this
     *
     * @throws InvalidArgumentException
     *
     * @see execute()
     */
    public function setCode(callable $code): static
    {
        if ($code instanceof \Closure) {
            $r = new \ReflectionFunction($code);
            if (null === $r->getClosureThis()) {
                set_error_handler(static function () {});
                try {
                    if ($c = \Closure::bind($code, $this)) {
                        $code = $c;
                    }
                } finally {
                    restore_error_handler();
                }
            }
        } else {
            $code = $code(...);
        }

        $this->code = $code;

        return $this;
    }

    /**
     * Merges the application definition with the command definition.
     *
     * This method is not part of public API and should not be used directly.
     *
     * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments
     *
     * @internal
     */
    public function mergeApplicationDefinition(bool $mergeArgs = true): void
    {
        if (null === $this->application) {
            return;
        }

        $this->fullDefinition = new InputDefinition();
        $this->fullDefinition->setOptions($this->definition->getOptions());
        $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions());

        if ($mergeArgs) {
            $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments());
            $this->fullDefinition->addArguments($this->definition->getArguments());
        } else {
            $this->fullDefinition->setArguments($this->definition->getArguments());
        }
    }

    /**
     * Sets an array of argument and option instances.
     *
     * @return $this
     */
    public function setDefinition(array|InputDefinition $definition): static
    {
        if ($definition instanceof InputDefinition) {
            $this->definition = $definition;
        } else {
            $this->definition->setDefinition($definition);
        }

        $this->fullDefinition = null;

        return $this;
    }

    /**
     * Gets the InputDefinition attached to this Command.
     */
    public function getDefinition(): InputDefinition
    {
        return $this->fullDefinition ?? $this->getNativeDefinition();
    }

    /**
     * Gets the InputDefinition to be used to create representations of this Command.
     *
     * Can be overridden to provide the original command representation when it would otherwise
     * be changed by merging with the application InputDefinition.
     *
     * This method is not part of public API and should not be used directly.
     */
    public function getNativeDefinition(): InputDefinition
    {
        return $this->definition ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
    }

    /**
     * Adds an argument.
     *
     * @param $mode    The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
     * @param $default The default value (for InputArgument::OPTIONAL mode only)
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     *
     * @return $this
     *
     * @throws InvalidArgumentException When argument mode is not valid
     */
    public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static
    {
        $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : [];
        if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
            throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues)));
        }
        $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
        $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));

        return $this;
    }

    /**
     * Adds an option.
     *
     * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
     * @param $mode     The option mode: One of the InputOption::VALUE_* constants
     * @param $default  The default value (must be null for InputOption::VALUE_NONE)
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     *
     * @return $this
     *
     * @throws InvalidArgumentException If option mode is invalid or incompatible
     */
    public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
    {
        $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : [];
        if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
            throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues)));
        }
        $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
        $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));

        return $this;
    }

    /**
     * Sets the name of the command.
     *
     * This method can set both the namespace and the name if
     * you separate them by a colon (:)
     *
     *     $command->setName('foo:bar');
     *
     * @return $this
     *
     * @throws InvalidArgumentException When the name is invalid
     */
    public function setName(string $name): static
    {
        $this->validateName($name);

        $this->name = $name;

        return $this;
    }

    /**
     * Sets the process title of the command.
     *
     * This feature should be used only when creating a long process command,
     * like a daemon.
     *
     * @return $this
     */
    public function setProcessTitle(string $title): static
    {
        $this->processTitle = $title;

        return $this;
    }

    /**
     * Returns the command name.
     */
    public function getName(): ?string
    {
        return $this->name;
    }

    /**
     * @param bool $hidden Whether or not the command should be hidden from the list of commands
     *
     * @return $this
     */
    public function setHidden(bool $hidden = true): static
    {
        $this->hidden = $hidden;

        return $this;
    }

    /**
     * @return bool whether the command should be publicly shown or not
     */
    public function isHidden(): bool
    {
        return $this->hidden;
    }

    /**
     * Sets the description for the command.
     *
     * @return $this
     */
    public function setDescription(string $description): static
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Returns the description for the command.
     */
    public function getDescription(): string
    {
        return $this->description;
    }

    /**
     * Sets the help for the command.
     *
     * @return $this
     */
    public function setHelp(string $help): static
    {
        $this->help = $help;

        return $this;
    }

    /**
     * Returns the help for the command.
     */
    public function getHelp(): string
    {
        return $this->help;
    }

    /**
     * Returns the processed help for the command replacing the %command.name% and
     * %command.full_name% patterns with the real values dynamically.
     */
    public function getProcessedHelp(): string
    {
        $name = $this->name;
        $isSingleCommand = $this->application?->isSingleCommand();

        $placeholders = [
            '%command.name%',
            '%command.full_name%',
        ];
        $replacements = [
            $name,
            $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
        ];

        return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
    }

    /**
     * Sets the aliases for the command.
     *
     * @param string[] $aliases An array of aliases for the command
     *
     * @return $this
     *
     * @throws InvalidArgumentException When an alias is invalid
     */
    public function setAliases(iterable $aliases): static
    {
        $list = [];

        foreach ($aliases as $alias) {
            $this->validateName($alias);
            $list[] = $alias;
        }

        $this->aliases = \is_array($aliases) ? $aliases : $list;

        return $this;
    }

    /**
     * Returns the aliases for the command.
     */
    public function getAliases(): array
    {
        return $this->aliases;
    }

    /**
     * Returns the synopsis for the command.
     *
     * @param bool $short Whether to show the short version of the synopsis (with options folded) or not
     */
    public function getSynopsis(bool $short = false): string
    {
        $key = $short ? 'short' : 'long';

        if (!isset($this->synopsis[$key])) {
            $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
        }

        return $this->synopsis[$key];
    }

    /**
     * Add a command usage example, it'll be prefixed with the command name.
     *
     * @return $this
     */
    public function addUsage(string $usage): static
    {
        if (!str_starts_with($usage, $this->name)) {
            $usage = \sprintf('%s %s', $this->name, $usage);
        }

        $this->usages[] = $usage;

        return $this;
    }

    /**
     * Returns alternative usages of the command.
     */
    public function getUsages(): array
    {
        return $this->usages;
    }

    /**
     * Gets a helper instance by name.
     *
     * @return HelperInterface
     *
     * @throws LogicException           if no HelperSet is defined
     * @throws InvalidArgumentException if the helper is not defined
     */
    public function getHelper(string $name): mixed
    {
        if (null === $this->helperSet) {
            throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
        }

        return $this->helperSet->get($name);
    }

    /**
     * Validates a command name.
     *
     * It must be non-empty and parts can optionally be separated by ":".
     *
     * @throws InvalidArgumentException When the name is invalid
     */
    private function validateName(string $name): void
    {
        if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
            throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name));
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Output\BashCompletionOutput;
use Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
use Symfony\Component\Console\Completion\Output\FishCompletionOutput;
use Symfony\Component\Console\Completion\Output\ZshCompletionOutput;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Responsible for providing the values to the shell completion.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
#[AsCommand(name: '|_complete', description: 'Internal command to provide shell completion suggestions')]
final class CompleteCommand extends Command
{
    public const COMPLETION_API_VERSION = '1';

    /**
     * @deprecated since Symfony 6.1
     */
    protected static $defaultName = '|_complete';

    /**
     * @deprecated since Symfony 6.1
     */
    protected static $defaultDescription = 'Internal command to provide shell completion suggestions';

    private array $completionOutputs;

    private bool $isDebug = false;

    /**
     * @param array<string, class-string<CompletionOutputInterface>> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value
     */
    public function __construct(array $completionOutputs = [])
    {
        // must be set before the parent constructor, as the property value is used in configure()
        $this->completionOutputs = $completionOutputs + [
            'bash' => BashCompletionOutput::class,
            'fish' => FishCompletionOutput::class,
            'zsh' => ZshCompletionOutput::class,
        ];

        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")')
            ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')
            ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')
            ->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script')
            ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated')
        ;
    }

    protected function initialize(InputInterface $input, OutputInterface $output): void
    {
        $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1
            $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version');
            if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) {
                $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION);
                $this->log($message);

                $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.');

                return 126;
            }

            $shell = $input->getOption('shell');
            if (!$shell) {
                throw new \RuntimeException('The "--shell" option must be set.');
            }

            if (!$completionOutput = $this->completionOutputs[$shell] ?? false) {
                throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs))));
            }

            $completionInput = $this->createCompletionInput($input);
            $suggestions = new CompletionSuggestions();

            $this->log([
                '',
                '<comment>'.date('Y-m-d H:i:s').'</>',
                '<info>Input:</> <comment>("|" indicates the cursor position)</>',
                '  '.(string) $completionInput,
                '<info>Command:</>',
                '  '.(string) implode(' ', $_SERVER['argv']),
                '<info>Messages:</>',
            ]);

            $command = $this->findCommand($completionInput, $output);
            if (null === $command) {
                $this->log('  No command found, completing using the Application class.');

                $this->getApplication()->complete($completionInput, $suggestions);
            } elseif (
                $completionInput->mustSuggestArgumentValuesFor('command')
                && $command->getName() !== $completionInput->getCompletionValue()
                && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)
            ) {
                $this->log('  No command found, completing using the Application class.');

                // expand shortcut names ("cache:cl<TAB>") into their full name ("cache:clear")
                $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));
            } else {
                $command->mergeApplicationDefinition();
                $completionInput->bind($command->getDefinition());

                if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
                    $this->log('  Completing option names for the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> command.');

                    $suggestions->suggestOptions($command->getDefinition()->getOptions());
                } else {
                    $this->log([
                        '  Completing using the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> class.',
                        '  Completing <comment>'.$completionInput->getCompletionType().'</> for <comment>'.$completionInput->getCompletionName().'</>',
                    ]);
                    if (null !== $compval = $completionInput->getCompletionValue()) {
                        $this->log('  Current value: <comment>'.$compval.'</>');
                    }

                    $command->complete($completionInput, $suggestions);
                }
            }

            /** @var CompletionOutputInterface $completionOutput */
            $completionOutput = new $completionOutput();

            $this->log('<info>Suggestions:</>');
            if ($options = $suggestions->getOptionSuggestions()) {
                $this->log('  --'.implode(' --', array_map(fn ($o) => $o->getName(), $options)));
            } elseif ($values = $suggestions->getValueSuggestions()) {
                $this->log('  '.implode(' ', $values));
            } else {
                $this->log('  <comment>No suggestions were provided</>');
            }

            $completionOutput->write($suggestions, $output);
        } catch (\Throwable $e) {
            $this->log([
                '<error>Error!</error>',
                (string) $e,
            ]);

            if ($output->isDebug()) {
                throw $e;
            }

            return 2;
        }

        return 0;
    }

    private function createCompletionInput(InputInterface $input): CompletionInput
    {
        $currentIndex = $input->getOption('current');
        if (!$currentIndex || !ctype_digit($currentIndex)) {
            throw new \RuntimeException('The "--current" option must be set and it must be an integer.');
        }

        $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex);

        try {
            $completionInput->bind($this->getApplication()->getDefinition());
        } catch (ExceptionInterface) {
        }

        return $completionInput;
    }

    private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command
    {
        try {
            $inputName = $completionInput->getFirstArgument();
            if (null === $inputName) {
                return null;
            }

            return $this->getApplication()->find($inputName);
        } catch (CommandNotFoundException) {
        }

        return null;
    }

    private function log($messages): void
    {
        if (!$this->isDebug) {
            return;
        }

        $commandName = basename($_SERVER['argv'][0]);
        file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\PHP_EOL, (array) $messages).\PHP_EOL, \FILE_APPEND);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;

/**
 * Dumps the completion script for the current shell.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
#[AsCommand(name: 'completion', description: 'Dump the shell completion script')]
final class DumpCompletionCommand extends Command
{
    /**
     * @deprecated since Symfony 6.1
     */
    protected static $defaultName = 'completion';

    /**
     * @deprecated since Symfony 6.1
     */
    protected static $defaultDescription = 'Dump the shell completion script';

    private array $supportedShells;

    protected function configure(): void
    {
        $fullCommand = $_SERVER['PHP_SELF'];
        $commandName = basename($fullCommand);
        $fullCommand = @realpath($fullCommand) ?: $fullCommand;

        $shell = $this->guessShell();
        [$rcFile, $completionFile] = match ($shell) {
            'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"],
            'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName],
            default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"],
        };

        $supportedShells = implode(', ', $this->getSupportedShells());

        $this
            ->setHelp(<<<EOH
The <info>%command.name%</> command dumps the shell completion script required
to use shell autocompletion (currently, {$supportedShells} completion are supported).

<comment>Static installation
-------------------</>

Dump the script to a global completion file and restart your shell:

    <info>%command.full_name% {$shell} | sudo tee {$completionFile}</>

Or dump the script to a local file and source it:

    <info>%command.full_name% {$shell} > completion.sh</>

    <comment># source the file whenever you use the project</>
    <info>source completion.sh</>

    <comment># or add this line at the end of your "{$rcFile}" file:</>
    <info>source /path/to/completion.sh</>

<comment>Dynamic installation
--------------------</>

Add this to the end of your shell configuration file (e.g. <info>"{$rcFile}"</>):

    <info>eval "$({$fullCommand} completion {$shell})"</>
EOH
            )
            ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, $this->getSupportedShells(...))
            ->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $commandName = basename($_SERVER['argv'][0]);

        if ($input->getOption('debug')) {
            $this->tailDebugLog($commandName, $output);

            return 0;
        }

        $shell = $input->getArgument('shell') ?? self::guessShell();
        $completionFile = __DIR__.'/../Resources/completion.'.$shell;
        if (!file_exists($completionFile)) {
            $supportedShells = $this->getSupportedShells();

            if ($output instanceof ConsoleOutputInterface) {
                $output = $output->getErrorOutput();
            }
            if ($shell) {
                $output->writeln(\sprintf('<error>Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").</>', $shell, implode('", "', $supportedShells)));
            } else {
                $output->writeln(\sprintf('<error>Shell not detected, Symfony shell completion only supports "%s").</>', implode('", "', $supportedShells)));
            }

            return 2;
        }

        $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], 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
    {
        if (isset($this->supportedShells)) {
            return $this->supportedShells;
        }

        $shells = [];

        foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) {
            if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) {
                $shells[] = $file->getExtension();
            }
        }
        sort($shells);

        return $this->supportedShells = $shells;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * HelpCommand displays the help for a given command.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class HelpCommand extends Command
{
    private Command $command;

    /**
     * @return void
     */
    protected function configure()
    {
        $this->ignoreValidationErrors();

        $this
            ->setName('help')
            ->setDefinition([
                new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())),
                new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()),
                new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
            ])
            ->setDescription('Display help for a command')
            ->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays help for a given command:

  <info>%command.full_name% list</info>

You can also output the help in other formats by using the <comment>--format</comment> option:

  <info>%command.full_name% --format=xml list</info>

To display the list of available commands, please use the <info>list</info> command.
EOF
            )
        ;
    }

    /**
     * @return void
     */
    public function setCommand(Command $command)
    {
        $this->command = $command;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->command ??= $this->getApplication()->find($input->getArgument('command_name'));

        $helper = new DescriptorHelper();
        $helper->describe($output, $this->command, [
            'format' => $input->getOption('format'),
            'raw_text' => $input->getOption('raw'),
        ]);

        unset($this->command);

        return 0;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Helper\HelperInterface;
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 <p@tchwork.com>
 */
final class LazyCommand extends Command
{
    private \Closure|Command $command;
    private ?bool $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 (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        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);
    }

    public function setCode(callable $code): static
    {
        $this->getCommand()->setCode($code);

        return $this;
    }

    /**
     * @internal
     */
    public function mergeApplicationDefinition(bool $mergeArgs = true): void
    {
        $this->getCommand()->mergeApplicationDefinition($mergeArgs);
    }

    public function setDefinition(array|InputDefinition $definition): static
    {
        $this->getCommand()->setDefinition($definition);

        return $this;
    }

    public function getDefinition(): InputDefinition
    {
        return $this->getCommand()->getDefinition();
    }

    public function getNativeDefinition(): InputDefinition
    {
        return $this->getCommand()->getNativeDefinition();
    }

    /**
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     */
    public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
    {
        $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : [];
        $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues);

        return $this;
    }

    /**
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     */
    public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
    {
        $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : [];
        $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);

        return $this;
    }

    public function setProcessTitle(string $title): static
    {
        $this->getCommand()->setProcessTitle($title);

        return $this;
    }

    public function setHelp(string $help): static
    {
        $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);
    }

    public function addUsage(string $usage): static
    {
        $this->getCommand()->addUsage($usage);

        return $this;
    }

    public function getUsages(): array
    {
        return $this->getCommand()->getUsages();
    }

    public function getHelper(string $name): HelperInterface
    {
        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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * ListCommand displays the list of all available commands for the application.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ListCommand extends Command
{
    /**
     * @return void
     */
    protected function configure()
    {
        $this
            ->setName('list')
            ->setDefinition([
                new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())),
                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', fn () => (new DescriptorHelper())->getFormats()),
                new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
            ])
            ->setDescription('List commands')
            ->setHelp(<<<'EOF'
The <info>%command.name%</info> command lists all commands:

  <info>%command.full_name%</info>

You can also display the commands for a specific namespace:

  <info>%command.full_name% test</info>

You can also output the information in other formats by using the <comment>--format</comment> option:

  <info>%command.full_name% --format=xml</info>

It's also possible to get raw list of commands (useful for embedding command runner):

  <info>%command.full_name% --raw</info>
EOF
            )
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $helper = new DescriptorHelper();
        $helper->describe($output, $this->getApplication(), [
            'format' => $input->getOption('format'),
            'raw_text' => $input->getOption('raw'),
            'namespace' => $input->getArgument('namespace'),
            'short' => $input->getOption('short'),
        ]);

        return 0;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\SemaphoreStore;

/**
 * Basic lock feature for commands.
 *
 * @author Geoffrey Brier <geoffrey.brier@gmail.com>
 */
trait LockableTrait
{
    private ?LockInterface $lock = null;

    /**
     * Locks a command.
     */
    private function lock(?string $name = null, bool $blocking = false): bool
    {
        if (!class_exists(SemaphoreStore::class)) {
            throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".');
        }

        if (null !== $this->lock) {
            throw new LogicException('A lock is already in place.');
        }

        if (SemaphoreStore::isSupported()) {
            $store = new SemaphoreStore();
        } else {
            $store = new FlockStore();
        }

        $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
        if (!$this->lock->acquire($blocking)) {
            $this->lock = null;

            return false;
        }

        return true;
    }

    /**
     * Releases the command lock if there is one.
     */
    private function release(): void
    {
        if ($this->lock) {
            $this->lock->release();
            $this->lock = null;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

/**
 * Interface for command reacting to signal.
 *
 * @author Grégoire Pineau <lyrixx@lyrix.info>
 */
interface SignalableCommandInterface
{
    /**
     * Returns the list of signals to subscribe.
     */
    public function getSubscribedSignals(): array;

    /**
     * The method will be called when the application is signaled.
     *
     * @param int|false $previousExitCode
     *
     * @return int|false The exit code to return or false to continue the normal execution
     */
    public function handleSignal(int $signal/* , int|false $previousExitCode = 0 */);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\HelperInterface;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Stopwatch\Stopwatch;

/**
 * @internal
 *
 * @author Jules Pietri <jules@heahprod.com>
 */
final class TraceableCommand extends Command implements SignalableCommandInterface
{
    public readonly Command $command;
    public int $exitCode;
    public ?int $interruptedBySignal = null;
    public bool $ignoreValidation;
    public bool $isInteractive = false;
    public string $duration = 'n/a';
    public string $maxMemoryUsage = 'n/a';
    public InputInterface $input;
    public OutputInterface $output;
    /** @var array<string, mixed> */
    public array $arguments;
    /** @var array<string, mixed> */
    public array $options;
    /** @var array<string, mixed> */
    public array $interactiveInputs = [];
    public array $handledSignals = [];

    public function __construct(
        Command $command,
        private readonly Stopwatch $stopwatch,
    ) {
        if ($command instanceof LazyCommand) {
            $command = $command->getCommand();
        }

        $this->command = $command;

        // prevent call to self::getDefaultDescription()
        $this->setDescription($command->getDescription());

        parent::__construct($command->getName());

        // init below enables calling {@see parent::run()}
        [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () {
            return [$this->code, $this->processTitle, $this->ignoreValidationErrors];
        }, $command, Command::class)();

        if (\is_callable($code)) {
            $this->setCode($code);
        }

        if ($processTitle) {
            parent::setProcessTitle($processTitle);
        }

        if ($ignoreValidationErrors) {
            parent::ignoreValidationErrors();
        }

        $this->ignoreValidation = $ignoreValidationErrors;
    }

    public function __call(string $name, array $arguments): mixed
    {
        return $this->command->{$name}(...$arguments);
    }

    public function getSubscribedSignals(): array
    {
        return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : [];
    }

    public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false
    {
        if (!$this->command instanceof SignalableCommandInterface) {
            return false;
        }

        $event = $this->stopwatch->start($this->getName().'.handle_signal');

        $exit = $this->command->handleSignal($signal, $previousExitCode);

        $event->stop();

        if (!isset($this->handledSignals[$signal])) {
            $this->handledSignals[$signal] = [
                'handled' => 0,
                'duration' => 0,
                'memory' => 0,
            ];
        }

        ++$this->handledSignals[$signal]['handled'];
        $this->handledSignals[$signal]['duration'] += $event->getDuration();
        $this->handledSignals[$signal]['memory'] = max(
            $this->handledSignals[$signal]['memory'],
            $event->getMemory() >> 20
        );

        return $exit;
    }

    /**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    public function ignoreValidationErrors(): void
    {
        $this->ignoreValidation = true;
        $this->command->ignoreValidationErrors();

        parent::ignoreValidationErrors();
    }

    public function setApplication(?Application $application = null): void
    {
        $this->command->setApplication($application);
    }

    public function getApplication(): ?Application
    {
        return $this->command->getApplication();
    }

    public function setHelperSet(HelperSet $helperSet): void
    {
        $this->command->setHelperSet($helperSet);
    }

    public function getHelperSet(): ?HelperSet
    {
        return $this->command->getHelperSet();
    }

    public function isEnabled(): bool
    {
        return $this->command->isEnabled();
    }

    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        $this->command->complete($input, $suggestions);
    }

    /**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    public function setCode(callable $code): static
    {
        $this->command->setCode($code);

        return parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int {
            $event = $this->stopwatch->start($this->getName().'.code');

            $this->exitCode = $code($input, $output);

            $event->stop();

            return $this->exitCode;
        });
    }

    /**
     * @internal
     */
    public function mergeApplicationDefinition(bool $mergeArgs = true): void
    {
        $this->command->mergeApplicationDefinition($mergeArgs);
    }

    public function setDefinition(array|InputDefinition $definition): static
    {
        $this->command->setDefinition($definition);

        return $this;
    }

    public function getDefinition(): InputDefinition
    {
        return $this->command->getDefinition();
    }

    public function getNativeDefinition(): InputDefinition
    {
        return $this->command->getNativeDefinition();
    }

    public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
    {
        $this->command->addArgument($name, $mode, $description, $default, $suggestedValues);

        return $this;
    }

    public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
    {
        $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);

        return $this;
    }

    /**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    public function setProcessTitle(string $title): static
    {
        $this->command->setProcessTitle($title);

        return parent::setProcessTitle($title);
    }

    public function setHelp(string $help): static
    {
        $this->command->setHelp($help);

        return $this;
    }

    public function getHelp(): string
    {
        return $this->command->getHelp();
    }

    public function getProcessedHelp(): string
    {
        return $this->command->getProcessedHelp();
    }

    public function getSynopsis(bool $short = false): string
    {
        return $this->command->getSynopsis($short);
    }

    public function addUsage(string $usage): static
    {
        $this->command->addUsage($usage);

        return $this;
    }

    public function getUsages(): array
    {
        return $this->command->getUsages();
    }

    public function getHelper(string $name): HelperInterface
    {
        return $this->command->getHelper($name);
    }

    public function run(InputInterface $input, OutputInterface $output): int
    {
        $this->input = $input;
        $this->output = $output;
        $this->arguments = $input->getArguments();
        $this->options = $input->getOptions();
        $event = $this->stopwatch->start($this->getName(), 'command');

        try {
            $this->exitCode = $this->command->run($input, $output);
        } finally {
            $event->stop();

            if ($output instanceof ConsoleOutputInterface && $output->isDebug()) {
                $output->getErrorOutput()->writeln((string) $event);
            }

            $this->duration = $event->getDuration().' ms';
            $this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB';

            if ($this->isInteractive) {
                $this->extractInteractiveInputs($input->getArguments(), $input->getOptions());
            }
        }

        return $this->exitCode;
    }

    protected function initialize(InputInterface $input, OutputInterface $output): void
    {
        $event = $this->stopwatch->start($this->getName().'.init', 'command');

        $this->command->initialize($input, $output);

        $event->stop();
    }

    protected function interact(InputInterface $input, OutputInterface $output): void
    {
        if (!$this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) {
            return;
        }

        $event = $this->stopwatch->start($this->getName().'.interact', 'command');

        $this->command->interact($input, $output);

        $event->stop();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $event = $this->stopwatch->start($this->getName().'.execute', 'command');

        $exitCode = $this->command->execute($input, $output);

        $event->stop();

        return $exitCode;
    }

    private function extractInteractiveInputs(array $arguments, array $options): void
    {
        foreach ($arguments as $argName => $argValue) {
            if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) {
                continue;
            }

            $this->interactiveInputs[$argName] = $argValue;
        }

        foreach ($options as $optName => $optValue) {
            if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) {
                continue;
            }

            $this->interactiveInputs['--'.$optName] = $optValue;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\CommandLoader;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
interface CommandLoaderInterface
{
    /**
     * Loads a command.
     *
     * @throws CommandNotFoundException
     */
    public function get(string $name): Command;

    /**
     * Checks if a command exists.
     */
    public function has(string $name): bool;

    /**
     * @return string[]
     */
    public function getNames(): array;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\CommandLoader;

use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
 * Loads commands from a PSR-11 container.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class ContainerCommandLoader implements CommandLoaderInterface
{
    private ContainerInterface $container;
    private array $commandMap;

    /**
     * @param array $commandMap An array with command names as keys and service ids as values
     */
    public function __construct(ContainerInterface $container, array $commandMap)
    {
        $this->container = $container;
        $this->commandMap = $commandMap;
    }

    public function get(string $name): Command
    {
        if (!$this->has($name)) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }

        return $this->container->get($this->commandMap[$name]);
    }

    public function has(string $name): bool
    {
        return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
    }

    public function getNames(): array
    {
        return array_keys($this->commandMap);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\CommandLoader;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
 * A simple command loader using factories to instantiate commands lazily.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
class FactoryCommandLoader implements CommandLoaderInterface
{
    private array $factories;

    /**
     * @param callable[] $factories Indexed by command names
     */
    public function __construct(array $factories)
    {
        $this->factories = $factories;
    }

    public function has(string $name): bool
    {
        return isset($this->factories[$name]);
    }

    public function get(string $name): Command
    {
        if (!isset($this->factories[$name])) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }

        $factory = $this->factories[$name];

        return $factory();
    }

    public function getNames(): array
    {
        return array_keys($this->factories);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <wouter@wouterj.nl>
 */
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 array $tokens;
    private int $currentIndex;
    private string $completionType;
    private ?string $completionName = null;
    private string $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)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $inputStr, $tokens);

        return self::fromTokens($tokens[0], $currentIndex);
    }

    /**
     * Create an input based on an COMP_WORDS token list.
     *
     * @param string[] $tokens       the set of split tokens (e.g. COMP_WORDS or argv)
     * @param int      $currentIndex the index of the cursor (e.g. COMP_CWORD)
     */
    public static function fromTokens(array $tokens, int $currentIndex): self
    {
        $input = new self($tokens);
        $input->tokens = $tokens;
        $input->currentIndex = $currentIndex;

        return $input;
    }

    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 ($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 ($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
     *
     * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component.
     *
     * @return self::TYPE_*
     */
    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) {
            // 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);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Completion;

use Symfony\Component\Console\Input\InputOption;

/**
 * Stores all completion suggestions for the current input.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
final class CompletionSuggestions
{
    private array $valueSuggestions = [];
    private array $optionSuggestions = [];

    /**
     * Add a suggested value for an input option or argument.
     *
     * @return $this
     */
    public function suggestValue(string|Suggestion $value): static
    {
        $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<string|Suggestion> $values
     *
     * @return $this
     */
    public function suggestValues(array $values): static
    {
        foreach ($values as $value) {
            $this->suggestValue($value);
        }

        return $this;
    }

    /**
     * Add a suggestion for an input option name.
     *
     * @return $this
     */
    public function suggestOption(InputOption $option): static
    {
        $this->optionSuggestions[] = $option;

        return $this;
    }

    /**
     * Add multiple suggestions for input option names at once.
     *
     * @param InputOption[] $options
     *
     * @return $this
     */
    public function suggestOptions(array $options): static
    {
        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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Completion\Output;

use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
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));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <wouter@wouterj.nl>
 */
interface CompletionOutputInterface
{
    public function write(CompletionSuggestions $suggestions, OutputInterface $output): void;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Completion\Output;

use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Guillaume Aveline <guillaume.aveline@pm.me>
 */
class FishCompletionOutput 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->write(implode("\n", $values));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Completion\Output;

use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Jitendra A <adhocore@gmail.com>
 */
class ZshCompletionOutput implements CompletionOutputInterface
{
    public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
    {
        $values = [];
        foreach ($suggestions->getValueSuggestions() as $value) {
            $values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : '');
        }
        foreach ($suggestions->getOptionSuggestions() as $option) {
            $values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
            if ($option->isNegatable()) {
                $values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
            }
        }
        $output->write(implode("\n", $values)."\n");
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Completion;

/**
 * Represents a single suggested value.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
class Suggestion implements \Stringable
{
    public function __construct(
        private readonly string $value,
        private readonly string $description = '',
    ) {
    }

    public function getValue(): string
    {
        return $this->value;
    }

    public function getDescription(): string
    {
        return $this->description;
    }

    public function __toString(): string
    {
        return $this->getValue();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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.
 *
 * @author Francesco Levorato <git@flevour.net>
 */
final class ConsoleEvents
{
    /**
     * The COMMAND event allows you to attach listeners before any command is
     * executed by the console. It also allows you to modify the command, input and output
     * before they are handed to the command.
     *
     * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
     */
    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.
     *
     * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
     */
    public const TERMINATE = 'console.terminate';

    /**
     * The ERROR event occurs when an uncaught exception or error appears.
     *
     * This event allows you to deal with the exception/error or
     * to modify the thrown exception.
     *
     * @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,
    ];
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console;

use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Pierre du Plessis <pdples@gmail.com>
 */
final class Cursor
{
    private OutputInterface $output;
    /** @var resource */
    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): static
    {
        $this->output->write(\sprintf("\x1b[%dA", $lines));

        return $this;
    }

    /**
     * @return $this
     */
    public function moveDown(int $lines = 1): static
    {
        $this->output->write(\sprintf("\x1b[%dB", $lines));

        return $this;
    }

    /**
     * @return $this
     */
    public function moveRight(int $columns = 1): static
    {
        $this->output->write(\sprintf("\x1b[%dC", $columns));

        return $this;
    }

    /**
     * @return $this
     */
    public function moveLeft(int $columns = 1): static
    {
        $this->output->write(\sprintf("\x1b[%dD", $columns));

        return $this;
    }

    /**
     * @return $this
     */
    public function moveToColumn(int $column): static
    {
        $this->output->write(\sprintf("\x1b[%dG", $column));

        return $this;
    }

    /**
     * @return $this
     */
    public function moveToPosition(int $column, int $row): static
    {
        $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column));

        return $this;
    }

    /**
     * @return $this
     */
    public function savePosition(): static
    {
        $this->output->write("\x1b7");

        return $this;
    }

    /**
     * @return $this
     */
    public function restorePosition(): static
    {
        $this->output->write("\x1b8");

        return $this;
    }

    /**
     * @return $this
     */
    public function hide(): static
    {
        $this->output->write("\x1b[?25l");

        return $this;
    }

    /**
     * @return $this
     */
    public function show(): static
    {
        $this->output->write("\x1b[?25h\x1b[?0c");

        return $this;
    }

    /**
     * Clears all the output from the current line.
     *
     * @return $this
     */
    public function clearLine(): static
    {
        $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(): static
    {
        $this->output->write("\x1b[0J");

        return $this;
    }

    /**
     * Clears the entire screen.
     *
     * @return $this
     */
    public function clearScreen(): static
    {
        $this->output->write("\x1b[2J");

        return $this;
    }

    /**
     * Returns the current cursor position as x,y coordinates.
     */
    public function getCurrentPosition(): array
    {
        static $isTtySupported;

        if (!$isTtySupported ??= '/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT)) {
            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];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\DataCollector;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Debug\CliRequest;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SignalRegistry\SignalMap;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\VarDumper\Cloner\Data;

/**
 * @internal
 *
 * @author Jules Pietri <jules@heahprod.com>
 */
final class CommandDataCollector extends DataCollector
{
    public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
    {
        if (!$request instanceof CliRequest) {
            return;
        }

        $command = $request->command;
        $application = $command->getApplication();

        $this->data = [
            'command' => $this->cloneVar($command->command),
            'exit_code' => $command->exitCode,
            'interrupted_by_signal' => $command->interruptedBySignal,
            'duration' => $command->duration,
            'max_memory_usage' => $command->maxMemoryUsage,
            'verbosity_level' => match ($command->output->getVerbosity()) {
                OutputInterface::VERBOSITY_QUIET => 'quiet',
                OutputInterface::VERBOSITY_NORMAL => 'normal',
                OutputInterface::VERBOSITY_VERBOSE => 'verbose',
                OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose',
                OutputInterface::VERBOSITY_DEBUG => 'debug',
            },
            'interactive' => $command->isInteractive,
            'validate_input' => !$command->ignoreValidation,
            'enabled' => $command->isEnabled(),
            'visible' => !$command->isHidden(),
            'input' => $this->cloneVar($command->input),
            'output' => $this->cloneVar($command->output),
            'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs),
            'signalable' => $command->getSubscribedSignals(),
            'handled_signals' => $command->handledSignals,
            'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())),
        ];

        $baseDefinition = $application->getDefinition();

        foreach ($command->arguments as $argName => $argValue) {
            if ($baseDefinition->hasArgument($argName)) {
                $this->data['application_inputs'][$argName] = $this->cloneVar($argValue);
            } else {
                $this->data['arguments'][$argName] = $this->cloneVar($argValue);
            }
        }

        foreach ($command->options as $optName => $optValue) {
            if ($baseDefinition->hasOption($optName)) {
                $this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue);
            } else {
                $this->data['options'][$optName] = $this->cloneVar($optValue);
            }
        }
    }

    public function getName(): string
    {
        return 'command';
    }

    /**
     * @return array{
     *     class?: class-string,
     *     executor?: string,
     *     file: string,
     *     line: int,
     * }
     */
    public function getCommand(): array
    {
        $class = $this->data['command']->getType();
        $r = new \ReflectionMethod($class, 'execute');

        if (Command::class !== $r->getDeclaringClass()) {
            return [
                'executor' => $class.'::'.$r->name,
                'file' => $r->getFileName(),
                'line' => $r->getStartLine(),
            ];
        }

        $r = new \ReflectionClass($class);

        return [
            'class' => $class,
            'file' => $r->getFileName(),
            'line' => $r->getStartLine(),
        ];
    }

    public function getInterruptedBySignal(): ?string
    {
        if (isset($this->data['interrupted_by_signal'])) {
            return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']);
        }

        return null;
    }

    public function getDuration(): string
    {
        return $this->data['duration'];
    }

    public function getMaxMemoryUsage(): string
    {
        return $this->data['max_memory_usage'];
    }

    public function getVerbosityLevel(): string
    {
        return $this->data['verbosity_level'];
    }

    public function getInteractive(): bool
    {
        return $this->data['interactive'];
    }

    public function getValidateInput(): bool
    {
        return $this->data['validate_input'];
    }

    public function getEnabled(): bool
    {
        return $this->data['enabled'];
    }

    public function getVisible(): bool
    {
        return $this->data['visible'];
    }

    public function getInput(): Data
    {
        return $this->data['input'];
    }

    public function getOutput(): Data
    {
        return $this->data['output'];
    }

    /**
     * @return Data[]
     */
    public function getArguments(): array
    {
        return $this->data['arguments'] ?? [];
    }

    /**
     * @return Data[]
     */
    public function getOptions(): array
    {
        return $this->data['options'] ?? [];
    }

    /**
     * @return Data[]
     */
    public function getApplicationInputs(): array
    {
        return $this->data['application_inputs'] ?? [];
    }

    /**
     * @return Data[]
     */
    public function getInteractiveInputs(): array
    {
        return $this->data['interactive_inputs'] ?? [];
    }

    public function getSignalable(): array
    {
        return array_map(
            static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
            $this->data['signalable']
        );
    }

    public function getHandledSignals(): array
    {
        $keys = array_map(
            static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
            array_keys($this->data['handled_signals'])
        );

        return array_combine($keys, array_values($this->data['handled_signals']));
    }

    /**
     * @return Data[]
     */
    public function getHelperSet(): array
    {
        return $this->data['helper_set'] ?? [];
    }

    public function reset(): void
    {
        $this->data = [];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Debug;

use Symfony\Component\Console\Command\TraceableCommand;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * @internal
 */
final class CliRequest extends Request
{
    public function __construct(
        public readonly TraceableCommand $command,
    ) {
        parent::__construct(
            attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'],
            server: $_SERVER,
        );
    }

    // Methods below allow to populate a profile, thus enable search and filtering
    public function getUri(): string
    {
        if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) {
            $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME').' console';
        } else {
            $binary = $this->server->get('argv')[0];
        }

        return $binary.' '.$this->command->input;
    }

    public function getMethod(): string
    {
        return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH';
    }

    public function getResponse(): Response
    {
        return new class($this->command->exitCode) extends Response {
            public function __construct(private readonly int $exitCode)
            {
                parent::__construct();
            }

            public function getStatusCode(): int
            {
                return $this->exitCode;
            }
        };
    }

    public function getClientIp(): string
    {
        $application = $this->command->getApplication();

        return $application->getName().' '.$application->getVersion();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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;

/**
 * Registers console commands.
 *
 * @author Grégoire Pineau <lyrixx@lyrixx.info>
 */
class AddConsoleCommandPass implements CompilerPassInterface
{
    /**
     * @return void
     */
    public function process(ContainerBuilder $container)
    {
        $commandServices = $container->findTaggedServiceIds('console.command', true);
        $lazyCommandMap = [];
        $lazyCommandRefs = [];
        $serviceIds = [];

        foreach ($commandServices as $id => $tags) {
            $definition = $container->getDefinition($id);
            $definition->addTag('container.no_preload');
            $class = $container->getParameterBag()->resolveValue($definition->getClass());

            if (isset($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));
                }
                if (!$r->isSubclassOf(Command::class)) {
                    throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class));
                }
                $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() || $definition->hasTag('container.private')) {
                    $commandId = 'console.command.public_alias.'.$id;
                    $container->setAlias($commandId, $id)->setPublic(true);
                    $id = $commandId;
                }
                $serviceIds[] = $id;

                continue;
            }

            $description = $tags[0]['description'] ?? null;

            unset($tags[0]);
            $lazyCommandMap[$commandName] = $id;
            $lazyCommandRefs[$id] = new TypedReference($id, $class);

            foreach ($aliases as $alias) {
                $lazyCommandMap[$alias] = $id;
            }

            foreach ($tags as $tag) {
                if (isset($tag['command'])) {
                    $aliases[] = $tag['command'];
                    $lazyCommandMap[$tag['command']] = $id;
                }

                $description ??= $tag['description'] ?? null;
            }

            $definition->addMethodCall('setName', [$commandName]);

            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, 'console.command', 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('console.command_loader', ContainerCommandLoader::class)
            ->setPublic(true)
            ->addTag('container.no_preload')
            ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);

        $container->setParameter('console.command.ids', $serviceIds);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;

/**
 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
 *
 * @internal
 */
class ApplicationDescription
{
    public const GLOBAL_NAMESPACE = '_global';

    private Application $application;
    private ?string $namespace;
    private bool $showHidden;
    private array $namespaces;

    /**
     * @var array<string, Command>
     */
    private array $commands;

    /**
     * @var array<string, Command>
     */
    private array $aliases = [];

    public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false)
    {
        $this->application = $application;
        $this->namespace = $namespace;
        $this->showHidden = $showHidden;
    }

    public function getNamespaces(): array
    {
        if (!isset($this->namespaces)) {
            $this->inspectApplication();
        }

        return $this->namespaces;
    }

    /**
     * @return Command[]
     */
    public function getCommands(): array
    {
        if (!isset($this->commands)) {
            $this->inspectApplication();
        }

        return $this->commands;
    }

    /**
     * @throws CommandNotFoundException
     */
    public function getCommand(string $name): Command
    {
        if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }

        return $this->commands[$name] ?? $this->aliases[$name];
    }

    private function inspectApplication(): void
    {
        $this->commands = [];
        $this->namespaces = [];

        $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
        foreach ($this->sortCommands($all) as $namespace => $commands) {
            $names = [];

            /** @var Command $command */
            foreach ($commands as $name => $command) {
                if (!$command->getName() || (!$this->showHidden && $command->isHidden())) {
                    continue;
                }

                if ($command->getName() === $name) {
                    $this->commands[$name] = $command;
                } else {
                    $this->aliases[$name] = $command;
                }

                $names[] = $name;
            }

            $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
        }
    }

    private function sortCommands(array $commands): array
    {
        $namespacedCommands = [];
        $globalCommands = [];
        $sortedCommands = [];
        foreach ($commands as $name => $command) {
            $key = $this->application->extractNamespace($name, 1);
            if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {
                $globalCommands[$name] = $command;
            } else {
                $namespacedCommands[$key][$name] = $command;
            }
        }

        if ($globalCommands) {
            ksort($globalCommands);
            $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
        }

        if ($namespacedCommands) {
            ksort($namespacedCommands, \SORT_STRING);
            foreach ($namespacedCommands as $key => $commandsSet) {
                ksort($commandsSet);
                $sortedCommands[$key] = $commandsSet;
            }
        }

        return $sortedCommands;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
 *
 * @internal
 */
abstract class Descriptor implements DescriptorInterface
{
    protected OutputInterface $output;

    public function describe(OutputInterface $output, object $object, array $options = []): void
    {
        $this->output = $output;

        match (true) {
            $object instanceof InputArgument => $this->describeInputArgument($object, $options),
            $object instanceof InputOption => $this->describeInputOption($object, $options),
            $object instanceof InputDefinition => $this->describeInputDefinition($object, $options),
            $object instanceof Command => $this->describeCommand($object, $options),
            $object instanceof Application => $this->describeApplication($object, $options),
            default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))),
        };
    }

    protected function write(string $content, bool $decorated = false): void
    {
        $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
    }

    /**
     * Describes an InputArgument instance.
     */
    abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void;

    /**
     * Describes an InputOption instance.
     */
    abstract protected function describeInputOption(InputOption $option, array $options = []): void;

    /**
     * Describes an InputDefinition instance.
     */
    abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void;

    /**
     * Describes a Command instance.
     */
    abstract protected function describeCommand(Command $command, array $options = []): void;

    /**
     * Describes an Application instance.
     */
    abstract protected function describeApplication(Application $application, array $options = []): void;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Output\OutputInterface;

/**
 * Descriptor interface.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
interface DescriptorInterface
{
    /**
     * @return void
     */
    public function describe(OutputInterface $output, object $object, array $options = []);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;

/**
 * JSON descriptor.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class JsonDescriptor extends Descriptor
{
    protected function describeInputArgument(InputArgument $argument, array $options = []): void
    {
        $this->writeData($this->getInputArgumentData($argument), $options);
    }

    protected function describeInputOption(InputOption $option, array $options = []): void
    {
        $this->writeData($this->getInputOptionData($option), $options);
        if ($option->isNegatable()) {
            $this->writeData($this->getInputOptionData($option, true), $options);
        }
    }

    protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
    {
        $this->writeData($this->getInputDefinitionData($definition), $options);
    }

    protected function describeCommand(Command $command, array $options = []): void
    {
        $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
    }

    protected function describeApplication(Application $application, array $options = []): void
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace, true);
        $commands = [];

        foreach ($description->getCommands() as $command) {
            $commands[] = $this->getCommandData($command, $options['short'] ?? false);
        }

        $data = [];
        if ('UNKNOWN' !== $application->getName()) {
            $data['application']['name'] = $application->getName();
            if ('UNKNOWN' !== $application->getVersion()) {
                $data['application']['version'] = $application->getVersion();
            }
        }

        $data['commands'] = $commands;

        if ($describedNamespace) {
            $data['namespace'] = $describedNamespace;
        } else {
            $data['namespaces'] = array_values($description->getNamespaces());
        }

        $this->writeData($data, $options);
    }

    /**
     * Writes data as json.
     */
    private function writeData(array $data, array $options): void
    {
        $flags = $options['json_encoding'] ?? 0;

        $this->write(json_encode($data, $flags));
    }

    private function getInputArgumentData(InputArgument $argument): array
    {
        return [
            'name' => $argument->getName(),
            'is_required' => $argument->isRequired(),
            'is_array' => $argument->isArray(),
            'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
            'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
        ];
    }

    private function getInputOptionData(InputOption $option, bool $negated = false): array
    {
        return $negated ? [
            'name' => '--no-'.$option->getName(),
            'shortcut' => '',
            'accept_value' => false,
            'is_value_required' => false,
            'is_multiple' => false,
            'description' => 'Negate the "--'.$option->getName().'" option',
            'default' => null === $option->getDefault() ? null : !$option->getDefault(),
        ] : [
            'name' => '--'.$option->getName(),
            'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
            'accept_value' => $option->acceptValue(),
            'is_value_required' => $option->isValueRequired(),
            'is_multiple' => $option->isArray(),
            'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
            'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(),
        ];
    }

    private function getInputDefinitionData(InputDefinition $definition): array
    {
        $inputArguments = [];
        foreach ($definition->getArguments() as $name => $argument) {
            $inputArguments[$name] = $this->getInputArgumentData($argument);
        }

        $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, bool $short = false): array
    {
        $data = [
            'name' => $command->getName(),
            'description' => $command->getDescription(),
        ];

        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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Markdown descriptor.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class MarkdownDescriptor extends Descriptor
{
    public function describe(OutputInterface $output, object $object, array $options = []): void
    {
        $decorated = $output->isDecorated();
        $output->setDecorated(false);

        parent::describe($output, $object, $options);

        $output->setDecorated($decorated);
    }

    protected function write(string $content, bool $decorated = true): void
    {
        parent::write($content, $decorated);
    }

    protected function describeInputArgument(InputArgument $argument, array $options = []): void
    {
        $this->write(
            '#### `'.($argument->getName() ?: '<none>')."`\n\n"
            .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
            .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
            .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
            .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
        );
    }

    protected function describeInputOption(InputOption $option, array $options = []): void
    {
        $name = '--'.$option->getName();
        if ($option->isNegatable()) {
            $name .= '|--no-'.$option->getName();
        }
        if ($option->getShortcut()) {
            $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
        }

        $this->write(
            '#### `'.$name.'`'."\n\n"
            .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '')
            .'* 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)).'`'
        );
    }

    protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
    {
        if ($showArguments = \count($definition->getArguments()) > 0) {
            $this->write('### Arguments');
            foreach ($definition->getArguments() as $argument) {
                $this->write("\n\n");
                $this->describeInputArgument($argument);
            }
        }

        if (\count($definition->getOptions()) > 0) {
            if ($showArguments) {
                $this->write("\n\n");
            }

            $this->write('### Options');
            foreach ($definition->getOptions() as $option) {
                $this->write("\n\n");
                $this->describeInputOption($option);
            }
        }
    }

    protected function describeCommand(Command $command, array $options = []): void
    {
        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(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n")
            );

            return;
        }

        $command->mergeApplicationDefinition(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(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n")
        );

        if ($help = $command->getProcessedHelp()) {
            $this->write("\n");
            $this->write($help);
        }

        $definition = $command->getDefinition();
        if ($definition->getOptions() || $definition->getArguments()) {
            $this->write("\n\n");
            $this->describeInputDefinition($definition);
        }
    }

    protected function describeApplication(Application $application, array $options = []): void
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace);
        $title = $this->getApplicationTitle($application);

        $this->write($title."\n".str_repeat('=', Helper::width($title)));

        foreach ($description->getNamespaces() as $namespace) {
            if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
                $this->write("\n\n");
                $this->write('**'.$namespace['id'].':**');
            }

            $this->write("\n\n");
            $this->write(implode("\n", array_map(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands'])));
        }

        foreach ($description->getCommands() as $command) {
            $this->write("\n\n");
            $this->describeCommand($command, $options);
        }
    }

    private function getApplicationTitle(Application $application): string
    {
        if ('UNKNOWN' !== $application->getName()) {
            if ('UNKNOWN' !== $application->getVersion()) {
                return \sprintf('%s %s', $application->getName(), $application->getVersion());
            }

            return $application->getName();
        }

        return 'Console Tool';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\String\UnicodeString;

class ReStructuredTextDescriptor extends Descriptor
{
    // <h1>
    private string $partChar = '=';
    // <h2>
    private string $chapterChar = '-';
    // <h3>
    private string $sectionChar = '~';
    // <h4>
    private string $subsectionChar = '.';
    // <h5>
    private string $subsubsectionChar = '^';
    // <h6>
    private string $paragraphsChar = '"';

    private array $visibleNamespaces = [];

    public function describe(OutputInterface $output, object $object, array $options = []): void
    {
        $decorated = $output->isDecorated();
        $output->setDecorated(false);

        parent::describe($output, $object, $options);

        $output->setDecorated($decorated);
    }

    /**
     * Override parent method to set $decorated = true.
     */
    protected function write(string $content, bool $decorated = true): void
    {
        parent::write($content, $decorated);
    }

    protected function describeInputArgument(InputArgument $argument, array $options = []): void
    {
        $this->write(
            $argument->getName() ?: '<none>'."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n"
                .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
                .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n"
                .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n"
                .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``'
        );
    }

    protected function describeInputOption(InputOption $option, array $options = []): void
    {
        $name = '\-\-'.$option->getName();
        if ($option->isNegatable()) {
            $name .= '|\-\-no-'.$option->getName();
        }
        if ($option->getShortcut()) {
            $name .= '|-'.str_replace('|', '|-', $option->getShortcut());
        }

        $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : '';
        $optionDescription = (new UnicodeString($optionDescription))->ascii();
        $this->write(
            $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n"
            .$optionDescription
            .'- **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)).'``'."\n"
        );
    }

    protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
    {
        if ($showArguments = ((bool) $definition->getArguments())) {
            $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n";
            foreach ($definition->getArguments() as $argument) {
                $this->write("\n\n");
                $this->describeInputArgument($argument);
            }
        }

        if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) {
            if ($showArguments) {
                $this->write("\n\n");
            }

            $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n");
            foreach ($nonDefaultOptions as $option) {
                $this->describeInputOption($option);
                $this->write("\n");
            }
        }
    }

    protected function describeCommand(Command $command, array $options = []): void
    {
        if ($options['short'] ?? false) {
            $this->write(
                '``'.$command->getName()."``\n"
                .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
                .($command->getDescription() ? $command->getDescription()."\n\n" : '')
                ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n"
                .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
            );

            return;
        }

        $command->mergeApplicationDefinition(false);

        foreach ($command->getAliases() as $alias) {
            $this->write('.. _'.$alias.":\n\n");
        }
        $this->write(
            $command->getName()."\n"
            .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
            .($command->getDescription() ? $command->getDescription()."\n\n" : '')
            ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n"
            .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
        );

        if ($help = $command->getProcessedHelp()) {
            $this->write("\n");
            $this->write($help);
        }

        $definition = $command->getDefinition();
        if ($definition->getOptions() || $definition->getArguments()) {
            $this->write("\n\n");
            $this->describeInputDefinition($definition);
        }
    }

    protected function describeApplication(Application $application, array $options = []): void
    {
        $description = new ApplicationDescription($application, $options['namespace'] ?? null);
        $title = $this->getApplicationTitle($application);

        $this->write($title."\n".str_repeat($this->partChar, Helper::width($title)));
        $this->createTableOfContents($description, $application);
        $this->describeCommands($application, $options);
    }

    private function getApplicationTitle(Application $application): string
    {
        if ('UNKNOWN' === $application->getName()) {
            return 'Console Tool';
        }
        if ('UNKNOWN' !== $application->getVersion()) {
            return \sprintf('%s %s', $application->getName(), $application->getVersion());
        }

        return $application->getName();
    }

    private function describeCommands($application, array $options): void
    {
        $title = 'Commands';
        $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n");
        foreach ($this->visibleNamespaces as $namespace) {
            if ('_global' === $namespace) {
                $commands = $application->all('');
                $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n");
            } else {
                $commands = $application->all($namespace);
                $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
            }

            foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) {
                $this->describeCommand($command, $options);
                $this->write("\n\n");
            }
        }
    }

    private function createTableOfContents(ApplicationDescription $description, Application $application): void
    {
        $this->setVisibleNamespaces($description);
        $chapterTitle = 'Table of Contents';
        $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n");
        foreach ($this->visibleNamespaces as $namespace) {
            if ('_global' === $namespace) {
                $commands = $application->all('');
            } else {
                $commands = $application->all($namespace);
                $this->write("\n\n");
                $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
            }
            $commands = $this->removeAliasesAndHiddenCommands($commands);

            $this->write("\n\n");
            $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands))));
        }
    }

    private function getNonDefaultOptions(InputDefinition $definition): array
    {
        $globalOptions = [
            'help',
            'quiet',
            'verbose',
            'version',
            'ansi',
            'no-interaction',
        ];
        $nonDefaultOptions = [];
        foreach ($definition->getOptions() as $option) {
            // Skip global options.
            if (!\in_array($option->getName(), $globalOptions)) {
                $nonDefaultOptions[] = $option;
            }
        }

        return $nonDefaultOptions;
    }

    private function setVisibleNamespaces(ApplicationDescription $description): void
    {
        $commands = $description->getCommands();
        foreach ($description->getNamespaces() as $namespace) {
            try {
                $namespaceCommands = $namespace['commands'];
                foreach ($namespaceCommands as $key => $commandName) {
                    if (!\array_key_exists($commandName, $commands)) {
                        // If the array key does not exist, then this is an alias.
                        unset($namespaceCommands[$key]);
                    } elseif ($commands[$commandName]->isHidden()) {
                        unset($namespaceCommands[$key]);
                    }
                }
                if (!$namespaceCommands) {
                    // If the namespace contained only aliases or hidden commands, skip the namespace.
                    continue;
                }
            } catch (\Exception) {
            }
            $this->visibleNamespaces[] = $namespace['id'];
        }
    }

    private function removeAliasesAndHiddenCommands(array $commands): array
    {
        foreach ($commands as $key => $command) {
            if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) {
                unset($commands[$key]);
            }
        }
        unset($commands['completion']);

        return $commands;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;

/**
 * Text descriptor.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class TextDescriptor extends Descriptor
{
    protected function describeInputArgument(InputArgument $argument, array $options = []): void
    {
        if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
            $default = \sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
        } else {
            $default = '';
        }

        $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());
        $spacingWidth = $totalWidth - \strlen($argument->getName());

        $this->writeText(\sprintf('  <info>%s</info>  %s%s%s',
            $argument->getName(),
            str_repeat(' ', $spacingWidth),
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
            preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
            $default
        ), $options);
    }

    protected function describeInputOption(InputOption $option, array $options = []): void
    {
        if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
            $default = \sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
        } else {
            $default = '';
        }

        $value = '';
        if ($option->acceptValue()) {
            $value = '='.strtoupper($option->getName());

            if ($option->isValueOptional()) {
                $value = '['.$value.']';
            }
        }

        $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
        $synopsis = \sprintf('%s%s',
            $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : '    ',
            \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)
        );

        $spacingWidth = $totalWidth - Helper::width($synopsis);

        $this->writeText(\sprintf('  <info>%s</info>  %s%s%s%s',
            $synopsis,
            str_repeat(' ', $spacingWidth),
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
            preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()),
            $default,
            $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
        ), $options);
    }

    protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
    {
        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
        foreach ($definition->getArguments() as $argument) {
            $totalWidth = max($totalWidth, Helper::width($argument->getName()));
        }

        if ($definition->getArguments()) {
            $this->writeText('<comment>Arguments:</comment>', $options);
            $this->writeText("\n");
            foreach ($definition->getArguments() as $argument) {
                $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
                $this->writeText("\n");
            }
        }

        if ($definition->getArguments() && $definition->getOptions()) {
            $this->writeText("\n");
        }

        if ($definition->getOptions()) {
            $laterOptions = [];

            $this->writeText('<comment>Options:</comment>', $options);
            foreach ($definition->getOptions() as $option) {
                if (\strlen($option->getShortcut() ?? '') > 1) {
                    $laterOptions[] = $option;
                    continue;
                }
                $this->writeText("\n");
                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
            }
            foreach ($laterOptions as $option) {
                $this->writeText("\n");
                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
            }
        }
    }

    protected function describeCommand(Command $command, array $options = []): void
    {
        $command->mergeApplicationDefinition(false);

        if ($description = $command->getDescription()) {
            $this->writeText('<comment>Description:</comment>', $options);
            $this->writeText("\n");
            $this->writeText('  '.$description);
            $this->writeText("\n\n");
        }

        $this->writeText('<comment>Usage:</comment>', $options);
        foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
            $this->writeText("\n");
            $this->writeText('  '.OutputFormatter::escape($usage), $options);
        }
        $this->writeText("\n");

        $definition = $command->getDefinition();
        if ($definition->getOptions() || $definition->getArguments()) {
            $this->writeText("\n");
            $this->describeInputDefinition($definition, $options);
            $this->writeText("\n");
        }

        $help = $command->getProcessedHelp();
        if ($help && $help !== $description) {
            $this->writeText("\n");
            $this->writeText('<comment>Help:</comment>', $options);
            $this->writeText("\n");
            $this->writeText('  '.str_replace("\n", "\n  ", $help), $options);
            $this->writeText("\n");
        }
    }

    protected function describeApplication(Application $application, array $options = []): void
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace);

        if (isset($options['raw_text']) && $options['raw_text']) {
            $width = $this->getColumnWidth($description->getCommands());

            foreach ($description->getCommands() as $command) {
                $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
                $this->writeText("\n");
            }
        } else {
            if ('' != $help = $application->getHelp()) {
                $this->writeText("$help\n\n", $options);
            }

            $this->writeText("<comment>Usage:</comment>\n", $options);
            $this->writeText("  command [options] [arguments]\n\n", $options);

            $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);

            $this->writeText("\n");
            $this->writeText("\n");

            $commands = $description->getCommands();
            $namespaces = $description->getNamespaces();
            if ($describedNamespace && $namespaces) {
                // make sure all alias commands are included when describing a specific namespace
                $describedNamespaceInfo = reset($namespaces);
                foreach ($describedNamespaceInfo['commands'] as $name) {
                    $commands[$name] = $description->getCommand($name);
                }
            }

            // calculate max. width based on available commands per namespace
            $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces)))));

            if ($describedNamespace) {
                $this->writeText(\sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
            } else {
                $this->writeText('<comment>Available commands:</comment>', $options);
            }

            foreach ($namespaces as $namespace) {
                $namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name]));

                if (!$namespace['commands']) {
                    continue;
                }

                if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
                    $this->writeText("\n");
                    $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);
                }

                foreach ($namespace['commands'] as $name) {
                    $this->writeText("\n");
                    $spacingWidth = $width - Helper::width($name);
                    $command = $commands[$name];
                    $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
                    $this->writeText(\sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
                }
            }

            $this->writeText("\n");
        }
    }

    private function writeText(string $content, array $options = []): void
    {
        $this->write(
            isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
            isset($options['raw_output']) ? !$options['raw_output'] : true
        );
    }

    /**
     * Formats command aliases to show them in the command description.
     */
    private function getCommandAliasesText(Command $command): string
    {
        $text = '';
        $aliases = $command->getAliases();

        if ($aliases) {
            $text = '['.implode('|', $aliases).'] ';
        }

        return $text;
    }

    /**
     * Formats input option/argument default value.
     */
    private function formatDefaultValue(mixed $default): string
    {
        if (\INF === $default) {
            return 'INF';
        }

        if (\is_string($default)) {
            $default = OutputFormatter::escape($default);
        } elseif (\is_array($default)) {
            foreach ($default as $key => $value) {
                if (\is_string($value)) {
                    $default[$key] = OutputFormatter::escape($value);
                }
            }
        }

        return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
    }

    /**
     * @param array<Command|string> $commands
     */
    private function getColumnWidth(array $commands): int
    {
        $widths = [];

        foreach ($commands as $command) {
            if ($command instanceof Command) {
                $widths[] = Helper::width($command->getName());
                foreach ($command->getAliases() as $alias) {
                    $widths[] = Helper::width($alias);
                }
            } else {
                $widths[] = Helper::width($command);
            }
        }

        return $widths ? max($widths) + 2 : 0;
    }

    /**
     * @param InputOption[] $options
     */
    private function calculateTotalWidthForOptions(array $options): int
    {
        $totalWidth = 0;
        foreach ($options as $option) {
            // "-" + shortcut + ", --" + name
            $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;
            }
            $totalWidth = max($totalWidth, $nameLength);
        }

        return $totalWidth;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;

/**
 * XML descriptor.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class XmlDescriptor extends Descriptor
{
    public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($definitionXML = $dom->createElement('definition'));

        $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
        foreach ($definition->getArguments() as $argument) {
            $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
        }

        $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
        foreach ($definition->getOptions() as $option) {
            $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
        }

        return $dom;
    }

    public function getCommandDocument(Command $command, bool $short = false): \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($commandXML = $dom->createElement('command'));

        $commandXML->setAttribute('id', $command->getName());
        $commandXML->setAttribute('name', $command->getName());
        $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);

        $commandXML->appendChild($usagesXML = $dom->createElement('usages'));

        $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));

        if ($short) {
            foreach ($command->getAliases() as $usage) {
                $usagesXML->appendChild($dom->createElement('usage', $usage));
            }
        } else {
            $command->mergeApplicationDefinition(false);

            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, bool $short = false): \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($rootXml = $dom->createElement('symfony'));

        if ('UNKNOWN' !== $application->getName()) {
            $rootXml->setAttribute('name', $application->getName());
            if ('UNKNOWN' !== $application->getVersion()) {
                $rootXml->setAttribute('version', $application->getVersion());
            }
        }

        $rootXml->appendChild($commandsXML = $dom->createElement('commands'));

        $description = new ApplicationDescription($application, $namespace, true);

        if ($namespace) {
            $commandsXML->setAttribute('namespace', $namespace);
        }

        foreach ($description->getCommands() as $command) {
            $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
        }

        if (!$namespace) {
            $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));

            foreach ($description->getNamespaces() as $namespaceDescription) {
                $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
                $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);

                foreach ($namespaceDescription['commands'] as $name) {
                    $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
                    $commandXML->appendChild($dom->createTextNode($name));
                }
            }
        }

        return $dom;
    }

    protected function describeInputArgument(InputArgument $argument, array $options = []): void
    {
        $this->writeDocument($this->getInputArgumentDocument($argument));
    }

    protected function describeInputOption(InputOption $option, array $options = []): void
    {
        $this->writeDocument($this->getInputOptionDocument($option));
    }

    protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
    {
        $this->writeDocument($this->getInputDefinitionDocument($definition));
    }

    protected function describeCommand(Command $command, array $options = []): void
    {
        $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
    }

    protected function describeApplication(Application $application, array $options = []): void
    {
        $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));
    }

    /**
     * Appends document children to parent node.
     */
    private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void
    {
        foreach ($importedParent->childNodes as $childNode) {
            $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
        }
    }

    /**
     * Writes DOM document.
     */
    private function writeDocument(\DOMDocument $dom): void
    {
        $dom->formatOutput = true;
        $this->write($dom->saveXML());
    }

    private function getInputArgumentDocument(InputArgument $argument): \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');

        $dom->appendChild($objectXML = $dom->createElement('argument'));
        $objectXML->setAttribute('name', $argument->getName());
        $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
        $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));

        $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
        $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
        foreach ($defaults as $default) {
            $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
            $defaultXML->appendChild($dom->createTextNode($default));
        }

        return $dom;
    }

    private function getInputOptionDocument(InputOption $option): \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');

        $dom->appendChild($objectXML = $dom->createElement('option'));
        $objectXML->setAttribute('name', '--'.$option->getName());
        $pos = strpos($option->getShortcut() ?? '', '|');
        if (false !== $pos) {
            $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
            $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
        } else {
            $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
        }
        $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
        $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
        $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));

        if ($option->acceptValue()) {
            $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));
            $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));

            if (!empty($defaults)) {
                foreach ($defaults as $default) {
                    $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
                    $defaultXML->appendChild($dom->createTextNode($default));
                }
            }
        }

        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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Event;

/**
 * Allows to do things before the command is executed, like skipping the command or executing code before the command is
 * going to be executed.
 *
 * Changing the input arguments will have no effect.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
final class ConsoleCommandEvent extends ConsoleEvent
{
    /**
     * The return code for skipped commands, this will also be passed into the terminate event.
     */
    public const RETURN_CODE_DISABLED = 113;

    /**
     * Indicates if the command should be run or skipped.
     */
    private bool $commandShouldRun = true;

    /**
     * Disables the command, so it won't be run.
     */
    public function disableCommand(): bool
    {
        return $this->commandShouldRun = false;
    }

    public function enableCommand(): bool
    {
        return $this->commandShouldRun = true;
    }

    /**
     * Returns true if the command is runnable, false otherwise.
     */
    public function commandShouldRun(): bool
    {
        return $this->commandShouldRun;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Allows to handle throwables thrown while running a command.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
final class ConsoleErrorEvent extends ConsoleEvent
{
    private \Throwable $error;
    private int $exitCode;

    public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null)
    {
        parent::__construct($command, $input, $output);

        $this->error = $error;
    }

    public function getError(): \Throwable
    {
        return $this->error;
    }

    public function setError(\Throwable $error): void
    {
        $this->error = $error;
    }

    public function setExitCode(int $exitCode): void
    {
        $this->exitCode = $exitCode;

        $r = new \ReflectionProperty($this->error, 'code');
        $r->setValue($this->error, $this->exitCode);
    }

    public function getExitCode(): int
    {
        return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Contracts\EventDispatcher\Event;

/**
 * Allows to inspect input and output of a command.
 *
 * @author Francesco Levorato <git@flevour.net>
 */
class ConsoleEvent extends Event
{
    protected $command;

    private InputInterface $input;
    private OutputInterface $output;

    public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
    {
        $this->command = $command;
        $this->input = $input;
        $this->output = $output;
    }

    /**
     * Gets the command that is executed.
     */
    public function getCommand(): ?Command
    {
        return $this->command;
    }

    /**
     * Gets the input instance.
     */
    public function getInput(): InputInterface
    {
        return $this->input;
    }

    /**
     * Gets the output instance.
     */
    public function getOutput(): OutputInterface
    {
        return $this->output;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author marie <marie@users.noreply.github.com>
 */
final class ConsoleSignalEvent extends ConsoleEvent
{
    private int $handlingSignal;
    private int|false $exitCode;

    public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0)
    {
        parent::__construct($command, $input, $output);
        $this->handlingSignal = $handlingSignal;
        $this->exitCode = $exitCode;
    }

    public function getHandlingSignal(): int
    {
        return $this->handlingSignal;
    }

    public function setExitCode(int $exitCode): void
    {
        if ($exitCode < 0 || $exitCode > 255) {
            throw new \InvalidArgumentException('Exit code must be between 0 and 255.');
        }

        $this->exitCode = $exitCode;
    }

    public function abortExit(): void
    {
        $this->exitCode = false;
    }

    public function getExitCode(): int|false
    {
        return $this->exitCode;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Event;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Allows to manipulate the exit code of a command after its execution.
 *
 * @author Francesco Levorato <git@flevour.net>
 * @author Jules Pietri <jules@heahprod.com>
 */
final class ConsoleTerminateEvent extends ConsoleEvent
{
    public function __construct(
        Command $command,
        InputInterface $input,
        OutputInterface $output,
        private int $exitCode,
        private readonly ?int $interruptingSignal = null,
    ) {
        parent::__construct($command, $input, $output);
    }

    public function setExitCode(int $exitCode): void
    {
        $this->exitCode = $exitCode;
    }

    public function getExitCode(): int
    {
        return $this->exitCode;
    }

    public function getInterruptingSignal(): ?int
    {
        return $this->interruptingSignal;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\EventListener;

use Psr\Log\LoggerInterface;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * @author James Halsall <james.t.halsall@googlemail.com>
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class ErrorListener implements EventSubscriberInterface
{
    private ?LoggerInterface $logger;

    public function __construct(?LoggerInterface $logger = null)
    {
        $this->logger = $logger;
    }

    /**
     * @return void
     */
    public function onConsoleError(ConsoleErrorEvent $event)
    {
        if (null === $this->logger) {
            return;
        }

        $error = $event->getError();

        if (!$inputString = $this->getInputString($event)) {
            $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);

            return;
        }

        $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
    }

    /**
     * @return void
     */
    public function onConsoleTerminate(ConsoleTerminateEvent $event)
    {
        if (null === $this->logger) {
            return;
        }

        $exitCode = $event->getExitCode();

        if (0 === $exitCode) {
            return;
        }

        if (!$inputString = $this->getInputString($event)) {
            $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);

            return;
        }

        $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
    }

    public static function getSubscribedEvents(): array
    {
        return [
            ConsoleEvents::ERROR => ['onConsoleError', -128],
            ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],
        ];
    }

    private static function getInputString(ConsoleEvent $event): ?string
    {
        $commandName = $event->getCommand()?->getName();
        $input = $event->getInput();

        if ($input instanceof \Stringable) {
            if ($commandName) {
                return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
            }

            return (string) $input;
        }

        return $commandName;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * Represents an incorrect command name typed in the console.
 *
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
    private array $alternatives;

    /**
     * @param string          $message      Exception message to throw
     * @param string[]        $alternatives List of similar defined names
     * @param int             $code         Exception code
     * @param \Throwable|null $previous     Previous exception used for the exception chaining
     */
    public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);

        $this->alternatives = $alternatives;
    }

    /**
     * @return string[]
     */
    public function getAlternatives(): array
    {
        return $this->alternatives;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * ExceptionInterface.
 *
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * Represents an incorrect option name or value typed in the console.
 *
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * Represents failure to read input from stdin.
 *
 * @author Gabriel Ostrolucký <gabriel.ostrolucky@gmail.com>
 */
class MissingInputException extends RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * Represents an incorrect namespace typed in the console.
 *
 * @author Pierre du Plessis <pdples@gmail.com>
 */
class NamespaceNotFoundException extends CommandNotFoundException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

use Symfony\Component\Console\Messenger\RunCommandContext;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunCommandFailedException extends RuntimeException
{
    public function __construct(\Throwable|string $exception, public readonly RunCommandContext $context)
    {
        parent::__construct(
            $exception instanceof \Throwable ? $exception->getMessage() : $exception,
            $exception instanceof \Throwable ? $exception->getCode() : 0,
            $exception instanceof \Throwable ? $exception : null,
        );
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Exception;

/**
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

/**
 * @author Tien Xuan Vo <tien.xuan.vo@gmail.com>
 */
final class NullOutputFormatter implements OutputFormatterInterface
{
    private NullOutputFormatterStyle $style;

    public function format(?string $message): ?string
    {
        return null;
    }

    public function getStyle(string $name): OutputFormatterStyleInterface
    {
        // to comply with the interface we must return a OutputFormatterStyleInterface
        return $this->style ??= new NullOutputFormatterStyle();
    }

    public function hasStyle(string $name): bool
    {
        return false;
    }

    public function isDecorated(): bool
    {
        return false;
    }

    public function setDecorated(bool $decorated): void
    {
        // do nothing
    }

    public function setStyle(string $name, OutputFormatterStyleInterface $style): void
    {
        // do nothing
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

/**
 * @author Tien Xuan Vo <tien.xuan.vo@gmail.com>
 */
final class NullOutputFormatterStyle implements OutputFormatterStyleInterface
{
    public function apply(string $text): string
    {
        return $text;
    }

    public function setBackground(?string $color = null): void
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        // do nothing
    }

    public function setForeground(?string $color = null): void
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        // do nothing
    }

    public function setOption(string $option): void
    {
        // do nothing
    }

    public function setOptions(array $options): void
    {
        // do nothing
    }

    public function unsetOption(string $option): void
    {
        // do nothing
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Helper\Helper;

use function Symfony\Component\String\b;

/**
 * Formatter class for console output.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
class OutputFormatter implements WrappableOutputFormatterInterface
{
    private bool $decorated;
    private array $styles = [];
    private OutputFormatterStyleStack $styleStack;

    public function __clone()
    {
        $this->styleStack = clone $this->styleStack;
        foreach ($this->styles as $key => $value) {
            $this->styles[$key] = clone $value;
        }
    }

    /**
     * Escapes "<" and ">" special chars in given text.
     */
    public static function escape(string $text): string
    {
        $text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);

        return self::escapeTrailingBackslash($text);
    }

    /**
     * Escapes trailing "\" in given text.
     *
     * @internal
     */
    public static function escapeTrailingBackslash(string $text): string
    {
        if (str_ends_with($text, '\\')) {
            $len = \strlen($text);
            $text = rtrim($text, '\\');
            $text = str_replace("\0", '', $text);
            $text .= str_repeat("\0", $len - \strlen($text));
        }

        return $text;
    }

    /**
     * Initializes console output formatter.
     *
     * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
     */
    public function __construct(bool $decorated = false, array $styles = [])
    {
        $this->decorated = $decorated;

        $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
        $this->setStyle('info', new OutputFormatterStyle('green'));
        $this->setStyle('comment', new OutputFormatterStyle('yellow'));
        $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));

        foreach ($styles as $name => $style) {
            $this->setStyle($name, $style);
        }

        $this->styleStack = new OutputFormatterStyleStack();
    }

    /**
     * @return void
     */
    public function setDecorated(bool $decorated)
    {
        $this->decorated = $decorated;
    }

    public function isDecorated(): bool
    {
        return $this->decorated;
    }

    /**
     * @return void
     */
    public function setStyle(string $name, OutputFormatterStyleInterface $style)
    {
        $this->styles[strtolower($name)] = $style;
    }

    public function hasStyle(string $name): bool
    {
        return isset($this->styles[strtolower($name)]);
    }

    public function getStyle(string $name): OutputFormatterStyleInterface
    {
        if (!$this->hasStyle($name)) {
            throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name));
        }

        return $this->styles[strtolower($name)];
    }

    public function format(?string $message): ?string
    {
        return $this->formatAndWrap($message, 0);
    }

    /**
     * @return string
     */
    public function formatAndWrap(?string $message, int $width)
    {
        if (null === $message) {
            return '';
        }

        $offset = 0;
        $output = '';
        $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
        $closeTagRegex = '[a-z][^<>]*+';
        $currentLineLength = 0;
        preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
        foreach ($matches[0] as $i => $match) {
            $pos = $match[1];
            $text = $match[0];

            if (0 != $pos && '\\' == $message[$pos - 1]) {
                continue;
            }

            // convert byte position to character position.
            $pos = Helper::length(substr($message, 0, $pos));
            // add the text up to the next tag
            $output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
            $offset = $pos + Helper::length($text);

            // opening tag?
            if ($open = '/' !== $text[1]) {
                $tag = $matches[1][$i][0];
            } else {
                $tag = $matches[3][$i][0] ?? '';
            }

            if (!$open && !$tag) {
                // </>
                $this->styleStack->pop();
            } elseif (null === $style = $this->createStyleFromString($tag)) {
                $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
            } elseif ($open) {
                $this->styleStack->push($style);
            } else {
                $this->styleStack->pop($style);
            }
        }

        $output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength);

        return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
    }

    public function getStyleStack(): OutputFormatterStyleStack
    {
        return $this->styleStack;
    }

    /**
     * Tries to create new style instance from string.
     */
    private function createStyleFromString(string $string): ?OutputFormatterStyleInterface
    {
        if (isset($this->styles[$string])) {
            return $this->styles[$string];
        }

        if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
            return null;
        }

        $style = new OutputFormatterStyle();
        foreach ($matches as $match) {
            array_shift($match);
            $match[0] = strtolower($match[0]);

            if ('fg' == $match[0]) {
                $style->setForeground(strtolower($match[1]));
            } elseif ('bg' == $match[0]) {
                $style->setBackground(strtolower($match[1]));
            } elseif ('href' === $match[0]) {
                $url = preg_replace('{\\\\([<>])}', '$1', $match[1]);
                $style->setHref($url);
            } elseif ('options' === $match[0]) {
                preg_match_all('([^,;]+)', strtolower($match[1]), $options);
                $options = array_shift($options);
                foreach ($options as $option) {
                    $style->setOption($option);
                }
            } else {
                return null;
            }
        }

        return $style;
    }

    /**
     * Applies current style from stack to text, if must be applied.
     */
    private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string
    {
        if ('' === $text) {
            return '';
        }

        if (!$width) {
            return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;
        }

        if (!$currentLineLength && '' !== $current) {
            $text = ltrim($text);
        }

        if ($currentLineLength) {
            $lines = explode("\n", $text, 2);
            $prefix = Helper::substr($lines[0], 0, $i = $width - $currentLineLength)."\n";
            $text = Helper::substr($lines[0], $i);

            if (isset($lines[1])) {
                // $prefix may contain the full first line in which the \n is already a part of $prefix.
                if ('' !== $text) {
                    $text .= "\n";
                }

                $text .= $lines[1];
            }
        } else {
            $prefix = '';
        }

        preg_match('~(\\n)$~', $text, $matches);
        $text = $prefix.$this->addLineBreaks($text, $width);
        $text = rtrim($text, "\n").($matches[1] ?? '');

        if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) {
            $text = "\n".$text;
        }

        $lines = explode("\n", $text);

        foreach ($lines as $i => $line) {
            $currentLineLength = 0 === $i ? $currentLineLength + Helper::length($line) : Helper::length($line);
            if ($width <= $currentLineLength) {
                $currentLineLength = 0;
            }
        }

        if ($this->isDecorated()) {
            foreach ($lines as $i => $line) {
                $lines[$i] = $this->styleStack->getCurrent()->apply($line);
            }
        }

        return implode("\n", $lines);
    }

    private function addLineBreaks(string $text, int $width): string
    {
        $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';

        return b($text)->toUnicodeString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

/**
 * Formatter interface for console output.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface OutputFormatterInterface
{
    /**
     * Sets the decorated flag.
     *
     * @return void
     */
    public function setDecorated(bool $decorated);

    /**
     * Whether the output will decorate messages.
     */
    public function isDecorated(): bool;

    /**
     * Sets a new style.
     *
     * @return void
     */
    public function setStyle(string $name, OutputFormatterStyleInterface $style);

    /**
     * Checks if output formatter has style with specified name.
     */
    public function hasStyle(string $name): bool;

    /**
     * Gets style options from style with specified name.
     *
     * @throws \InvalidArgumentException When style isn't defined
     */
    public function getStyle(string $name): OutputFormatterStyleInterface;

    /**
     * Formats a message according to the given styles.
     */
    public function format(?string $message): ?string;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Color;

/**
 * Formatter style class for defining styles.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class OutputFormatterStyle implements OutputFormatterStyleInterface
{
    private Color $color;
    private string $foreground;
    private string $background;
    private array $options;
    private ?string $href = null;
    private bool $handlesHrefGracefully;

    /**
     * Initializes output formatter style.
     *
     * @param string|null $foreground The style foreground color name
     * @param string|null $background The style background color name
     */
    public function __construct(?string $foreground = null, ?string $background = null, array $options = [])
    {
        $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
    }

    /**
     * @return void
     */
    public function setForeground(?string $color = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
    }

    /**
     * @return void
     */
    public function setBackground(?string $color = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
    }

    public function setHref(string $url): void
    {
        $this->href = $url;
    }

    /**
     * @return void
     */
    public function setOption(string $option)
    {
        $this->options[] = $option;
        $this->color = new Color($this->foreground, $this->background, $this->options);
    }

    /**
     * @return void
     */
    public function unsetOption(string $option)
    {
        $pos = array_search($option, $this->options);
        if (false !== $pos) {
            unset($this->options[$pos]);
        }

        $this->color = new Color($this->foreground, $this->background, $this->options);
    }

    /**
     * @return void
     */
    public function setOptions(array $options)
    {
        $this->color = new Color($this->foreground, $this->background, $this->options = $options);
    }

    public function apply(string $text): string
    {
        $this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
            && (!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\\";
        }

        return $this->color->apply($text);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

/**
 * Formatter style interface for defining styles.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface OutputFormatterStyleInterface
{
    /**
     * Sets style foreground color.
     *
     * @return void
     */
    public function setForeground(?string $color);

    /**
     * Sets style background color.
     *
     * @return void
     */
    public function setBackground(?string $color);

    /**
     * Sets some specific style option.
     *
     * @return void
     */
    public function setOption(string $option);

    /**
     * Unsets some specific style option.
     *
     * @return void
     */
    public function unsetOption(string $option);

    /**
     * Sets multiple style options at once.
     *
     * @return void
     */
    public function setOptions(array $options);

    /**
     * Applies the style to a given text.
     */
    public function apply(string $text): string;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Contracts\Service\ResetInterface;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class OutputFormatterStyleStack implements ResetInterface
{
    /**
     * @var OutputFormatterStyleInterface[]
     */
    private array $styles = [];

    private OutputFormatterStyleInterface $emptyStyle;

    public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)
    {
        $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
        $this->reset();
    }

    /**
     * Resets stack (ie. empty internal arrays).
     *
     * @return void
     */
    public function reset()
    {
        $this->styles = [];
    }

    /**
     * Pushes a style in the stack.
     *
     * @return void
     */
    public function push(OutputFormatterStyleInterface $style)
    {
        $this->styles[] = $style;
    }

    /**
     * Pops a style from the stack.
     *
     * @throws InvalidArgumentException When style tags incorrectly nested
     */
    public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface
    {
        if (!$this->styles) {
            return $this->emptyStyle;
        }

        if (null === $style) {
            return array_pop($this->styles);
        }

        foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
            if ($style->apply('') === $stackedStyle->apply('')) {
                $this->styles = \array_slice($this->styles, 0, $index);

                return $stackedStyle;
            }
        }

        throw new InvalidArgumentException('Incorrectly nested style tag found.');
    }

    /**
     * Computes current style with stacks top codes.
     */
    public function getCurrent(): OutputFormatterStyleInterface
    {
        if (!$this->styles) {
            return $this->emptyStyle;
        }

        return $this->styles[\count($this->styles) - 1];
    }

    /**
     * @return $this
     */
    public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle): static
    {
        $this->emptyStyle = $emptyStyle;

        return $this;
    }

    public function getEmptyStyle(): OutputFormatterStyleInterface
    {
        return $this->emptyStyle;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Formatter;

/**
 * Formatter interface for console output that supports word wrapping.
 *
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
interface WrappableOutputFormatterInterface extends OutputFormatterInterface
{
    /**
     * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
     *
     * @return string
     */
    public function formatAndWrap(?string $message, int $width);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

/**
 * Helps outputting debug information when running an external program from a command.
 *
 * An external program can be a Process, an HTTP request, or anything else.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DebugFormatterHelper extends Helper
{
    private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
    private array $started = [];
    private int $count = -1;

    /**
     * Starts a debug formatting session.
     */
    public function start(string $id, string $message, string $prefix = 'RUN'): string
    {
        $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)];

        return \sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
    }

    /**
     * Adds progress to a formatting session.
     */
    public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR'): string
    {
        $message = '';

        if ($error) {
            if (isset($this->started[$id]['out'])) {
                $message .= "\n";
                unset($this->started[$id]['out']);
            }
            if (!isset($this->started[$id]['err'])) {
                $message .= \sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);
                $this->started[$id]['err'] = true;
            }

            $message .= str_replace("\n", \sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
        } else {
            if (isset($this->started[$id]['err'])) {
                $message .= "\n";
                unset($this->started[$id]['err']);
            }
            if (!isset($this->started[$id]['out'])) {
                $message .= \sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);
                $this->started[$id]['out'] = true;
            }

            $message .= str_replace("\n", \sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
        }

        return $message;
    }

    /**
     * Stops a formatting session.
     */
    public function stop(string $id, string $message, bool $successful, string $prefix = 'RES'): string
    {
        $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';

        if ($successful) {
            return \sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
        }

        $message = \sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);

        unset($this->started[$id]['out'], $this->started[$id]['err']);

        return $message;
    }

    private function getBorder(string $id): string
    {
        return \sprintf('<bg=%s> </>', self::COLORS[$this->started[$id]['border']]);
    }

    public function getName(): string
    {
        return 'debug_formatter';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Descriptor\DescriptorInterface;
use Symfony\Component\Console\Descriptor\JsonDescriptor;
use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * This class adds helper method to describe objects in various formats.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class DescriptorHelper extends Helper
{
    /**
     * @var DescriptorInterface[]
     */
    private array $descriptors = [];

    public function __construct()
    {
        $this
            ->register('txt', new TextDescriptor())
            ->register('xml', new XmlDescriptor())
            ->register('json', new JsonDescriptor())
            ->register('md', new MarkdownDescriptor())
            ->register('rst', new ReStructuredTextDescriptor())
        ;
    }

    /**
     * Describes an object if supported.
     *
     * Available options are:
     * * format: string, the output format name
     * * raw_text: boolean, sets output type as raw
     *
     * @return void
     *
     * @throws InvalidArgumentException when the given format is not supported
     */
    public function describe(OutputInterface $output, ?object $object, array $options = [])
    {
        $options = array_merge([
            'raw_text' => false,
            'format' => 'txt',
        ], $options);

        if (!isset($this->descriptors[$options['format']])) {
            throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format']));
        }

        $descriptor = $this->descriptors[$options['format']];
        $descriptor->describe($output, $object, $options);
    }

    /**
     * Registers a descriptor.
     *
     * @return $this
     */
    public function register(string $format, DescriptorInterface $descriptor): static
    {
        $this->descriptors[$format] = $descriptor;

        return $this;
    }

    public function getName(): string
    {
        return 'descriptor';
    }

    public function getFormats(): array
    {
        return array_keys($this->descriptors);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;

/**
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
final class Dumper
{
    private OutputInterface $output;
    private ?CliDumper $dumper;
    private ?ClonerInterface $cloner;
    private \Closure $handler;

    public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null)
    {
        $this->output = $output;
        $this->dumper = $dumper;
        $this->cloner = $cloner;

        if (class_exists(CliDumper::class)) {
            $this->handler = function ($var): string {
                $dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
                $dumper->setColors($this->output->isDecorated());

                return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true));
            };
        } else {
            $this->handler = fn ($var): string => match (true) {
                null === $var => 'null',
                true === $var => 'true',
                false === $var => 'false',
                \is_string($var) => '"'.$var.'"',
                default => rtrim(print_r($var, true)),
            };
        }
    }

    public function __invoke(mixed $var): string
    {
        return ($this->handler)($var);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatter;

/**
 * The Formatter class provides helpers to format messages.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FormatterHelper extends Helper
{
    /**
     * Formats a message within a section.
     */
    public function formatSection(string $section, string $message, string $style = 'info'): string
    {
        return \sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
    }

    /**
     * Formats a message as a block of text.
     */
    public function formatBlock(string|array $messages, string $style, bool $large = false): string
    {
        if (!\is_array($messages)) {
            $messages = [$messages];
        }

        $len = 0;
        $lines = [];
        foreach ($messages as $message) {
            $message = OutputFormatter::escape($message);
            $lines[] = \sprintf($large ? '  %s  ' : ' %s ', $message);
            $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::width($lines[$i]));
        }
        if ($large) {
            $messages[] = str_repeat(' ', $len);
        }

        for ($i = 0; isset($messages[$i]); ++$i) {
            $messages[$i] = \sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
        }

        return implode("\n", $messages);
    }

    /**
     * Truncates a message to the given length.
     */
    public function truncate(string $message, int $length, string $suffix = '...'): string
    {
        $computedLength = $length - self::width($suffix);

        if ($computedLength > self::width($message)) {
            return $message;
        }

        return self::substr($message, 0, $length).$suffix;
    }

    public function getName(): string
    {
        return 'formatter';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\String\UnicodeString;

/**
 * Helper is the base class for all helper classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Helper implements HelperInterface
{
    protected $helperSet;

    /**
     * @return void
     */
    public function setHelperSet(?HelperSet $helperSet = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        $this->helperSet = $helperSet;
    }

    public function getHelperSet(): ?HelperSet
    {
        return $this->helperSet;
    }

    /**
     * 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 ??= '';

        if (preg_match('//u', $string)) {
            $string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count);

            return (new UnicodeString($string))->width(false) + $count;
        }

        if (false === $encoding = mb_detect_encoding($string, null, true)) {
            return \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 ??= '';

        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.
     */
    public static function substr(?string $string, int $from, ?int $length = null): string
    {
        $string ??= '';

        if (preg_match('//u', $string)) {
            return (new UnicodeString($string))->slice($from, $length);
        }

        if (false === $encoding = mb_detect_encoding($string, null, true)) {
            return substr($string, $from, $length);
        }

        return mb_substr($string, $from, $length, $encoding);
    }

    /**
     * @return string
     */
    public static function formatTime(int|float $secs, int $precision = 1)
    {
        $secs = (int) floor($secs);

        if (0 === $secs) {
            return '< 1 sec';
        }

        static $timeFormats = [
            [1, '1 sec', 'secs'],
            [60, '1 min', 'mins'],
            [3600, '1 hr', 'hrs'],
            [86400, '1 day', 'days'],
        ];

        $times = [];
        foreach ($timeFormats as $index => $format) {
            $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs;

            if (isset($times[$index - $precision])) {
                unset($times[$index - $precision]);
            }

            if (0 === $seconds) {
                continue;
            }

            $unitCount = ($seconds / $format[0]);
            $times[$index] = 1 === $unitCount ? $format[1] : $unitCount.' '.$format[2];

            if ($secs === $seconds) {
                break;
            }

            $secs -= $seconds;
        }

        return implode(', ', array_reverse($times));
    }

    /**
     * @return string
     */
    public static function formatMemory(int $memory)
    {
        if ($memory >= 1024 * 1024 * 1024) {
            return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
        }

        if ($memory >= 1024 * 1024) {
            return \sprintf('%.1f MiB', $memory / 1024 / 1024);
        }

        if ($memory >= 1024) {
            return \sprintf('%d KiB', $memory / 1024);
        }

        return \sprintf('%d B', $memory);
    }

    /**
     * @return string
     */
    public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
    {
        $isDecorated = $formatter->isDecorated();
        $formatter->setDecorated(false);
        // remove <...> formatting
        $string = $formatter->format($string ?? '');
        // remove already formatted characters
        $string = preg_replace("/\033\[[^m]*m/", '', $string ?? '');
        // remove terminal hyperlinks
        $string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? '');
        $formatter->setDecorated($isDecorated);

        return $string;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

/**
 * HelperInterface is the interface all helpers must implement.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface HelperInterface
{
    /**
     * Sets the helper set associated with this helper.
     *
     * @return void
     */
    public function setHelperSet(?HelperSet $helperSet);

    /**
     * Gets the helper set associated with this helper.
     */
    public function getHelperSet(): ?HelperSet;

    /**
     * Returns the canonical name of this helper.
     *
     * @return string
     */
    public function getName();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * HelperSet represents a set of helpers to be used with a command.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @implements \IteratorAggregate<string, HelperInterface>
 */
class HelperSet implements \IteratorAggregate
{
    /** @var array<string, HelperInterface> */
    private array $helpers = [];

    /**
     * @param HelperInterface[] $helpers
     */
    public function __construct(array $helpers = [])
    {
        foreach ($helpers as $alias => $helper) {
            $this->set($helper, \is_int($alias) ? null : $alias);
        }
    }

    /**
     * @return void
     */
    public function set(HelperInterface $helper, ?string $alias = null)
    {
        $this->helpers[$helper->getName()] = $helper;
        if (null !== $alias) {
            $this->helpers[$alias] = $helper;
        }

        $helper->setHelperSet($this);
    }

    /**
     * Returns true if the helper if defined.
     */
    public function has(string $name): bool
    {
        return isset($this->helpers[$name]);
    }

    /**
     * Gets a helper value.
     *
     * @throws InvalidArgumentException if the helper is not defined
     */
    public function get(string $name): HelperInterface
    {
        if (!$this->has($name)) {
            throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name));
        }

        return $this->helpers[$name];
    }

    public function getIterator(): \Traversable
    {
        return new \ArrayIterator($this->helpers);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Input\InputAwareInterface;
use Symfony\Component\Console\Input\InputInterface;

/**
 * An implementation of InputAwareInterface for Helpers.
 *
 * @author Wouter J <waldio.webdesign@gmail.com>
 */
abstract class InputAwareHelper extends Helper implements InputAwareInterface
{
    protected $input;

    /**
     * @return void
     */
    public function setInput(InputInterface $input)
    {
        $this->input = $input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

/**
 * Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow
 * answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN).
 *
 *  (?:
 *       # -- Words/Characters
 *       (                       # (1 start)
 *            (?>                     # Atomic Group - Match words with valid breaks
 *                 .{1,16}                 #  1-N characters
 *                                         #  Followed by one of 4 prioritized, non-linebreak whitespace
 *                 (?:                     #  break types:
 *                      (?<= [^\S\r\n] )        # 1. - Behind a non-linebreak whitespace
 *                      [^\S\r\n]?              #      ( optionally accept an extra non-linebreak whitespace )
 *                   |  (?= \r? \n )            # 2. - Ahead a linebreak
 *                   |  $                       # 3. - EOS
 *                   |  [^\S\r\n]               # 4. - Accept an extra non-linebreak whitespace
 *                 )
 *            )                       # End atomic group
 *         |
 *            .{1,16}                 # No valid word breaks, just break on the N'th character
 *       )                       # (1 end)
 *       (?: \r? \n )?           # Optional linebreak after Words/Characters
 *    |
 *       # -- Or, Linebreak
 *       (?: \r? \n | $ )        # Stand alone linebreak or at EOS
 *  )
 *
 * @author Krisztián Ferenczi <ferenczi.krisztian@gmail.com>
 *
 * @see https://stackoverflow.com/a/20434776/1476819
 */
final class OutputWrapper
{
    private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
    private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+';
    private const URL_PATTERN = 'https?://\S+';

    public function __construct(
        private bool $allowCutUrls = false,
    ) {
    }

    public function wrap(string $text, int $width, string $break = "\n"): string
    {
        if (!$width) {
            return $text;
        }

        $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT);
        $limitPattern = "{1,$width}";
        $patternBlocks = [$tagPattern];
        if (!$this->allowCutUrls) {
            $patternBlocks[] = self::URL_PATTERN;
        }
        $patternBlocks[] = '.';
        $blocks = implode('|', $patternBlocks);
        $rowPattern = "(?:$blocks)$limitPattern";
        $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern);
        $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break);

        return str_replace(' '.$break, $break, $output);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

/**
 * The ProcessHelper class provides helpers to run external processes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @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 callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     */
    public function run(OutputInterface $output, array|Process $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".');
        }

        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }

        $formatter = $this->getHelperSet()->get('debug_formatter');

        if ($cmd instanceof Process) {
            $cmd = [$cmd];
        }

        if (\is_string($cmd[0] ?? null)) {
            $process = new Process($cmd);
            $cmd = [];
        } elseif (($cmd[0] ?? null) instanceof Process) {
            $process = $cmd[0];
            unset($cmd[0]);
        } else {
            throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
        }

        if ($verbosity <= $output->getVerbosity()) {
            $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
        }

        if ($output->isDebug()) {
            $callback = $this->wrapCallback($output, $process, $callback);
        }

        $process->run($callback, $cmd);

        if ($verbosity <= $output->getVerbosity()) {
            $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode());
            $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
        }

        if (!$process->isSuccessful() && null !== $error) {
            $output->writeln(\sprintf('<error>%s</error>', $this->escapeString($error)));
        }

        return $process;
    }

    /**
     * Runs the process.
     *
     * This is identical to run() except that an exception is thrown if the process
     * exits with a non-zero exit code.
     *
     * @param array|Process $cmd      An instance of Process or a command to run
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @throws ProcessFailedException
     *
     * @see run()
     */
    public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process
    {
        $process = $this->run($output, $cmd, $error, $callback);

        if (!$process->isSuccessful()) {
            throw new ProcessFailedException($process);
        }

        return $process;
    }

    /**
     * Wraps a Process callback to add debugging output.
     */
    public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }

        $formatter = $this->getHelperSet()->get('debug_formatter');

        return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
            $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));

            if (null !== $callback) {
                $callback($type, $buffer);
            }
        };
    }

    private function escapeString(string $str): string
    {
        return str_replace('<', '\\<', $str);
    }

    public function getName(): string
    {
        return 'process';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Terminal;

/**
 * The ProgressBar provides helpers to display progress output.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Chris Jones <leeked@gmail.com>
 */
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 int $barWidth = 28;
    private string $barChar;
    private string $emptyBarChar = '-';
    private string $progressChar = '>';
    private ?string $format = null;
    private ?string $internalFormat = null;
    private ?int $redrawFreq = 1;
    private int $writeCount = 0;
    private float $lastWriteTime = 0;
    private float $minSecondsBetweenRedraws = 0;
    private float $maxSecondsBetweenRedraws = 1;
    private OutputInterface $output;
    private int $step = 0;
    private int $startingStep = 0;
    private ?int $max = null;
    private int $startTime;
    private int $stepWidth;
    private float $percent = 0.0;
    private array $messages = [];
    private bool $overwrite = true;
    private Terminal $terminal;
    private ?string $previousMessage = null;
    private Cursor $cursor;
    private array $placeholders = [];

    private static array $formatters;
    private static array $formats;

    /**
     * @param int $max Maximum steps (0 if unknown)
     */
    public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }

        $this->output = $output;
        $this->setMaxSteps($max);
        $this->terminal = new Terminal();

        if (0 < $minSecondsBetweenRedraws) {
            $this->redrawFreq = null;
            $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
        }

        if (!$this->output->isDecorated()) {
            // disable overwrite when output does not support ANSI codes.
            $this->overwrite = false;

            // set a reasonable redraw frequency so output isn't flooded
            $this->redrawFreq = null;
        }

        $this->startTime = time();
        $this->cursor = new Cursor($output);
    }

    /**
     * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar.
     *
     * This method also allow you to override an existing placeholder.
     *
     * @param string                       $name     The placeholder name (including the delimiter char like %)
     * @param callable(ProgressBar):string $callable A PHP callable
     */
    public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void
    {
        self::$formatters ??= self::initPlaceholderFormatters();

        self::$formatters[$name] = $callable;
    }

    /**
     * Gets the placeholder formatter for a given name.
     *
     * @param string $name The placeholder name (including the delimiter char like %)
     */
    public static function getPlaceholderFormatterDefinition(string $name): ?callable
    {
        self::$formatters ??= self::initPlaceholderFormatters();

        return self::$formatters[$name] ?? null;
    }

    /**
     * Sets a placeholder formatter for a given name, for this instance only.
     *
     * @param callable(ProgressBar):string $callable A PHP callable
     */
    public function setPlaceholderFormatter(string $name, callable $callable): void
    {
        $this->placeholders[$name] = $callable;
    }

    /**
     * Gets the placeholder formatter for a given name.
     *
     * @param string $name The placeholder name (including the delimiter char like %)
     */
    public function getPlaceholderFormatter(string $name): ?callable
    {
        return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name);
    }

    /**
     * Sets a format for a given name.
     *
     * This method also allow you to override an existing format.
     *
     * @param string $name   The format name
     * @param string $format A format string
     */
    public static function setFormatDefinition(string $name, string $format): void
    {
        self::$formats ??= self::initFormats();

        self::$formats[$name] = $format;
    }

    /**
     * Gets the format for a given name.
     *
     * @param string $name The format name
     */
    public static function getFormatDefinition(string $name): ?string
    {
        self::$formats ??= self::initFormats();

        return self::$formats[$name] ?? null;
    }

    /**
     * Associates a text with a named placeholder.
     *
     * The text is displayed when the progress bar is rendered but only
     * when the corresponding placeholder is part of the custom format line
     * (by wrapping the name with %).
     *
     * @param string $message The text to associate with the placeholder
     * @param string $name    The name of the placeholder
     */
    public function setMessage(string $message, string $name = 'message'): void
    {
        $this->messages[$name] = $message;
    }

    public function getMessage(string $name = 'message'): ?string
    {
        return $this->messages[$name] ?? null;
    }

    public function getStartTime(): int
    {
        return $this->startTime;
    }

    public function getMaxSteps(): int
    {
        return $this->max;
    }

    public function getProgress(): int
    {
        return $this->step;
    }

    private function getStepWidth(): int
    {
        return $this->stepWidth;
    }

    public function getProgressPercent(): float
    {
        return $this->percent;
    }

    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 (0 === $this->step || $this->step === $this->startingStep) {
            return 0;
        }

        return round((time() - $this->startTime) / ($this->step - $this->startingStep) * $this->max);
    }

    public function getRemaining(): float
    {
        if (0 === $this->step || $this->step === $this->startingStep) {
            return 0;
        }

        return round((time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step));
    }

    public function setBarWidth(int $size): void
    {
        $this->barWidth = max(1, $size);
    }

    public function getBarWidth(): int
    {
        return $this->barWidth;
    }

    public function setBarCharacter(string $char): void
    {
        $this->barChar = $char;
    }

    public function getBarCharacter(): string
    {
        return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
    }

    public function setEmptyBarCharacter(string $char): void
    {
        $this->emptyBarChar = $char;
    }

    public function getEmptyBarCharacter(): string
    {
        return $this->emptyBarChar;
    }

    public function setProgressCharacter(string $char): void
    {
        $this->progressChar = $char;
    }

    public function getProgressCharacter(): string
    {
        return $this->progressChar;
    }

    public function setFormat(string $format): void
    {
        $this->format = null;
        $this->internalFormat = $format;
    }

    /**
     * Sets the redraw frequency.
     *
     * @param int|null $freq The frequency in steps
     */
    public function setRedrawFrequency(?int $freq): void
    {
        $this->redrawFreq = null !== $freq ? max(1, $freq) : null;
    }

    public function minSecondsBetweenRedraws(float $seconds): void
    {
        $this->minSecondsBetweenRedraws = $seconds;
    }

    public function maxSecondsBetweenRedraws(float $seconds): void
    {
        $this->maxSecondsBetweenRedraws = $seconds;
    }

    /**
     * Returns an iterator that will automatically update the progress bar when iterated.
     *
     * @template TKey
     * @template TValue
     *
     * @param iterable<TKey, TValue> $iterable
     * @param int|null               $max      Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
     *
     * @return iterable<TKey, TValue>
     */
    public function iterate(iterable $iterable, ?int $max = null): iterable
    {
        $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));

        foreach ($iterable as $key => $value) {
            yield $key => $value;

            $this->advance();
        }

        $this->finish();
    }

    /**
     * Starts the progress output.
     *
     * @param int|null $max     Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
     * @param int      $startAt The starting point of the bar (useful e.g. when resuming a previously started bar)
     */
    public function start(?int $max = null, int $startAt = 0): void
    {
        $this->startTime = time();
        $this->step = $startAt;
        $this->startingStep = $startAt;

        $startAt > 0 ? $this->setProgress($startAt) : $this->percent = 0.0;

        if (null !== $max) {
            $this->setMaxSteps($max);
        }

        $this->display();
    }

    /**
     * Advances the progress output X steps.
     *
     * @param int $step Number of steps to advance
     */
    public function advance(int $step = 1): void
    {
        $this->setProgress($this->step + $step);
    }

    /**
     * Sets whether to overwrite the progressbar, false for new line.
     */
    public function setOverwrite(bool $overwrite): void
    {
        $this->overwrite = $overwrite;
    }

    public function setProgress(int $step): void
    {
        if ($this->max && $step > $this->max) {
            $this->max = $step;
        } elseif ($step < 0) {
            $step = 0;
        }

        $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
        $prevPeriod = (int) ($this->step / $redrawFreq);
        $currPeriod = (int) ($step / $redrawFreq);
        $this->step = $step;
        $this->percent = $this->max ? (float) $this->step / $this->max : 0;
        $timeInterval = microtime(true) - $this->lastWriteTime;

        // Draw regardless of other limits
        if ($this->max === $step) {
            $this->display();

            return;
        }

        // Throttling
        if ($timeInterval < $this->minSecondsBetweenRedraws) {
            return;
        }

        // Draw each step period, but not too late
        if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
            $this->display();
        }
    }

    public function setMaxSteps(int $max): void
    {
        $this->format = null;
        $this->max = max(0, $max);
        $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
    }

    /**
     * Finishes the progress output.
     */
    public function finish(): void
    {
        if (!$this->max) {
            $this->max = $this->step;
        }

        if ($this->step === $this->max && !$this->overwrite) {
            // prevent double 100% output
            return;
        }

        $this->setProgress($this->max);
    }

    /**
     * Outputs the current progress string.
     */
    public function display(): void
    {
        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
            return;
        }

        if (null === $this->format) {
            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
        }

        $this->overwrite($this->buildLine());
    }

    /**
     * Removes the progress bar from the current line.
     *
     * This is useful if you wish to write some output
     * while a progress bar is running.
     * Call display() to show the progress bar again.
     */
    public function clear(): void
    {
        if (!$this->overwrite) {
            return;
        }

        if (null === $this->format) {
            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
        }

        $this->overwrite('');
    }

    private function setRealFormat(string $format): void
    {
        // try to use the _nomax variant if available
        if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
            $this->format = self::getFormatDefinition($format.'_nomax');
        } elseif (null !== self::getFormatDefinition($format)) {
            $this->format = self::getFormatDefinition($format);
        } else {
            $this->format = $format;
        }
    }

    /**
     * Overwrites a previous message to the output.
     */
    private function overwrite(string $message): void
    {
        if ($this->previousMessage === $message) {
            return;
        }

        $originalMessage = $message;

        if ($this->overwrite) {
            if (null !== $this->previousMessage) {
                if ($this->output instanceof ConsoleSectionOutput) {
                    $messageLines = explode("\n", $this->previousMessage);
                    $lineCount = \count($messageLines);

                    $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? '');

                    // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again
                    if ('' === $lastLineWithoutDecoration) {
                        --$lineCount;
                    }

                    foreach ($messageLines as $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 {
                    $lineCount = substr_count($this->previousMessage, "\n");
                    for ($i = 0; $i < $lineCount; ++$i) {
                        $this->cursor->moveToColumn(1);
                        $this->cursor->clearLine();
                        $this->cursor->moveUp();
                    }

                    $this->cursor->moveToColumn(1);
                    $this->cursor->clearLine();
                }
            }
        } elseif ($this->step > 0) {
            $message = \PHP_EOL.$message;
        }

        $this->previousMessage = $originalMessage;
        $this->lastWriteTime = microtime(true);

        $this->output->write($message);
        ++$this->writeCount;
    }

    private function determineBestFormat(): string
    {
        return match ($this->output->getVerbosity()) {
            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
            OutputInterface::VERBOSITY_VERBOSE => $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX,
            OutputInterface::VERBOSITY_VERY_VERBOSE => $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX,
            OutputInterface::VERBOSITY_DEBUG => $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX,
            default => $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX,
        };
    }

    private static function initPlaceholderFormatters(): array
    {
        return [
            'bar' => function (self $bar, OutputInterface $output) {
                $completeBars = $bar->getBarOffset();
                $display = str_repeat($bar->getBarCharacter(), $completeBars);
                if ($completeBars < $bar->getBarWidth()) {
                    $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));
                    $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
                }

                return $display;
            },
            'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2),
            'remaining' => function (self $bar) {
                if (!$bar->getMaxSteps()) {
                    throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
                }

                return Helper::formatTime($bar->getRemaining(), 2);
            },
            '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.');
                }

                return Helper::formatTime($bar->getEstimated(), 2);
            },
            'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)),
            'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT),
            'max' => fn (self $bar) => $bar->getMaxSteps(),
            'percent' => fn (self $bar) => floor($bar->getProgressPercent() * 100),
        ];
    }

    private static function initFormats(): array
    {
        return [
            self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%',
            self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]',

            self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
            self::FORMAT_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%',

            self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
            self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
        ];
    }

    private function buildLine(): string
    {
        \assert(null !== $this->format);

        $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
        $callback = function ($matches) {
            if ($formatter = $this->getPlaceholderFormatter($matches[1])) {
                $text = $formatter($this, $this->output);
            } elseif (isset($this->messages[$matches[1]])) {
                $text = $this->messages[$matches[1]];
            } else {
                return $matches[0];
            }

            if (isset($matches[2])) {
                $text = \sprintf('%'.$matches[2], $text);
            }

            return $text;
        };
        $line = preg_replace_callback($regex, $callback, $this->format);

        // gets string length for each sub line with multiline format
        $linesLength = array_map(fn ($subLine) => Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))), explode("\n", $line));

        $linesWidth = max($linesLength);

        $terminalWidth = $this->terminal->getWidth();
        if ($linesWidth <= $terminalWidth) {
            return $line;
        }

        $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);

        return preg_replace_callback($regex, $callback, $this->format);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
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 OutputInterface $output;
    private int $startTime;
    private ?string $format = null;
    private ?string $message = null;
    private array $indicatorValues;
    private int $indicatorCurrent;
    private int $indicatorChangeInterval;
    private float $indicatorUpdateTime;
    private bool $started = false;

    /**
     * @var array<string, callable>
     */
    private static array $formatters;

    /**
     * @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)
    {
        $this->output = $output;

        $format ??= $this->determineBestFormat();
        $indicatorValues ??= ['-', '\\', '|', '/'];
        $indicatorValues = array_values($indicatorValues);

        if (2 > \count($indicatorValues)) {
            throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
        }

        $this->format = self::getFormatDefinition($format);
        $this->indicatorChangeInterval = $indicatorChangeInterval;
        $this->indicatorValues = $indicatorValues;
        $this->startTime = time();
    }

    /**
     * Sets the current indicator message.
     *
     * @return void
     */
    public function setMessage(?string $message)
    {
        $this->message = $message;

        $this->display();
    }

    /**
     * Starts the indicator output.
     *
     * @return void
     */
    public function start(string $message)
    {
        if ($this->started) {
            throw new LogicException('Progress indicator already started.');
        }

        $this->message = $message;
        $this->started = true;
        $this->startTime = time();
        $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
        $this->indicatorCurrent = 0;

        $this->display();
    }

    /**
     * Advances the indicator.
     *
     * @return void
     */
    public function advance()
    {
        if (!$this->started) {
            throw new LogicException('Progress indicator has not yet been started.');
        }

        if (!$this->output->isDecorated()) {
            return;
        }

        $currentTime = $this->getCurrentTimeInMilliseconds();

        if ($currentTime < $this->indicatorUpdateTime) {
            return;
        }

        $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
        ++$this->indicatorCurrent;

        $this->display();
    }

    /**
     * Finish the indicator with message.
     *
     * @return void
     */
    public function finish(string $message)
    {
        if (!$this->started) {
            throw new LogicException('Progress indicator has not yet been started.');
        }

        $this->message = $message;
        $this->display();
        $this->output->writeln('');
        $this->started = false;
    }

    /**
     * Gets the format for a given name.
     */
    public static function getFormatDefinition(string $name): ?string
    {
        return self::FORMATS[$name] ?? null;
    }

    /**
     * Sets a placeholder formatter for a given name.
     *
     * This method also allow you to override an existing placeholder.
     *
     * @return void
     */
    public static function setPlaceholderFormatterDefinition(string $name, callable $callable)
    {
        self::$formatters ??= self::initPlaceholderFormatters();

        self::$formatters[$name] = $callable;
    }

    /**
     * Gets the placeholder formatter for a given name (including the delimiter char like %).
     */
    public static function getPlaceholderFormatterDefinition(string $name): ?callable
    {
        self::$formatters ??= self::initPlaceholderFormatters();

        return self::$formatters[$name] ?? null;
    }

    private function display(): void
    {
        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
            return;
        }

        $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
            if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
                return $formatter($this);
            }

            return $matches[0];
        }, $this->format ?? ''));
    }

    private function determineBestFormat(): string
    {
        return match ($this->output->getVerbosity()) {
            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
            OutputInterface::VERBOSITY_VERBOSE => $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi',
            OutputInterface::VERBOSITY_VERY_VERBOSE,
            OutputInterface::VERBOSITY_DEBUG => $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi',
            default => $this->output->isDecorated() ? 'normal' : 'normal_no_ansi',
        };
    }

    /**
     * Overwrites a previous message to the output.
     */
    private function overwrite(string $message): void
    {
        if ($this->output->isDecorated()) {
            $this->output->write("\x0D\x1B[2K");
            $this->output->write($message);
        } else {
            $this->output->writeln($message);
        }
    }

    private function getCurrentTimeInMilliseconds(): float
    {
        return round(microtime(true) * 1000);
    }

    /**
     * @return array<string, \Closure>
     */
    private static function initPlaceholderFormatters(): array
    {
        return [
            'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)],
            'message' => fn (self $indicator) => $indicator->message,
            'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime, 2),
            'memory' => fn () => Helper::formatMemory(memory_get_usage(true)),
        ];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\StreamableInputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;

use function Symfony\Component\String\s;

/**
 * The QuestionHelper class provides helpers to interact with the user.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class QuestionHelper extends Helper
{
    /**
     * @var resource|null
     */
    private $inputStream;

    private static bool $stty = true;
    private static bool $stdinIsInteractive;

    /**
     * Asks a question to the user.
     *
     * @return mixed The user answer
     *
     * @throws RuntimeException If there is no data to read in the input stream
     */
    public function ask(InputInterface $input, OutputInterface $output, Question $question): mixed
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }

        if (!$input->isInteractive()) {
            return $this->getDefaultAnswer($question);
        }

        if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
            $this->inputStream = $stream;
        }

        try {
            if (!$question->getValidator()) {
                return $this->doAsk($output, $question);
            }

            $interviewer = fn () => $this->doAsk($output, $question);

            return $this->validateAttempts($interviewer, $output, $question);
        } catch (MissingInputException $exception) {
            $input->setInteractive(false);

            if (null === $fallbackOutput = $this->getDefaultAnswer($question)) {
                throw $exception;
            }

            return $fallbackOutput;
        }
    }

    public function getName(): string
    {
        return 'question';
    }

    /**
     * Prevents usage of stty.
     *
     * @return void
     */
    public static function disableStty()
    {
        self::$stty = false;
    }

    /**
     * Asks the question to the user.
     *
     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
     */
    private function doAsk(OutputInterface $output, Question $question): mixed
    {
        $this->writePrompt($output, $question);

        $inputStream = $this->inputStream ?: \STDIN;
        $autocomplete = $question->getAutocompleterCallback();

        if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
            $ret = false;
            if ($question->isHidden()) {
                try {
                    $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
                    $ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
                } catch (RuntimeException $e) {
                    if (!$question->isHiddenFallback()) {
                        throw $e;
                    }
                }
            }

            if (false === $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.');
                }
                if ($question->isTrimmable()) {
                    $ret = trim($ret);
                }
            }
        } else {
            $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
            $ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
        }

        if ($output instanceof ConsoleSectionOutput) {
            $output->addContent(''); // add EOL to the question
            $output->addContent($ret);
        }

        $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();

        if ($normalizer = $question->getNormalizer()) {
            return $normalizer($ret);
        }

        return $ret;
    }

    private function getDefaultAnswer(Question $question): mixed
    {
        $default = $question->getDefault();

        if (null === $default) {
            return $default;
        }

        if ($validator = $question->getValidator()) {
            return \call_user_func($validator, $default);
        } elseif ($question instanceof ChoiceQuestion) {
            $choices = $question->getChoices();

            if (!$question->isMultiselect()) {
                return $choices[$default] ?? $default;
            }

            $default = explode(',', $default);
            foreach ($default as $k => $v) {
                $v = $question->isTrimmable() ? trim($v) : $v;
                $default[$k] = $choices[$v] ?? $v;
            }
        }

        return $default;
    }

    /**
     * Outputs the question prompt.
     *
     * @return void
     */
    protected function writePrompt(OutputInterface $output, Question $question)
    {
        $message = $question->getQuestion();

        if ($question instanceof ChoiceQuestion) {
            $output->writeln(array_merge([
                $question->getQuestion(),
            ], $this->formatChoiceQuestionChoices($question, 'info')));

            $message = $question->getPrompt();
        }

        $output->write($message);
    }

    /**
     * @return string[]
     */
    protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag): array
    {
        $messages = [];

        $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices())));

        foreach ($choices as $key => $value) {
            $padding = str_repeat(' ', $maxWidth - self::width($key));

            $messages[] = \sprintf("  [<$tag>%s$padding</$tag>] %s", $key, $value);
        }

        return $messages;
    }

    /**
     * Outputs an error message.
     *
     * @return void
     */
    protected function writeError(OutputInterface $output, \Exception $error)
    {
        if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
            $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
        } else {
            $message = '<error>'.$error->getMessage().'</error>';
        }

        $output->writeln($message);
    }

    /**
     * Autocompletes a question.
     *
     * @param resource $inputStream
     */
    private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
    {
        $cursor = new Cursor($output, $inputStream);

        $fullChoice = '';
        $ret = '';

        $i = 0;
        $ofs = -1;
        $matches = $autocomplete($ret);
        $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');

        // Add highlighted text style
        $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));

        // 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('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);
                }

                if (0 === $i) {
                    $ofs = -1;
                    $matches = $autocomplete($ret);
                    $numMatches = \count($matches);
                } else {
                    $numMatches = 0;
                }

                // Pop the last character off the end of our string
                $ret = self::substr($ret, 0, $i);
            } elseif ("\033" === $c) {
                // Did we read an escape sequence?
                $c .= fread($inputStream, 2);

                // A = Up Arrow. B = Down Arrow
                if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
                    if ('A' === $c[2] && -1 === $ofs) {
                        $ofs = 0;
                    }

                    if (0 === $numMatches) {
                        continue;
                    }

                    $ofs += ('A' === $c[2]) ? -1 : 1;
                    $ofs = ($numMatches + $ofs) % $numMatches;
                }
            } elseif ('' === $c || \ord($c) < 32) {
                if ("\t" === $c || "\n" === $c) {
                    if ($numMatches > 0 && -1 !== $ofs) {
                        $ret = (string) $matches[$ofs];
                        // Echo out remaining chars for current match
                        $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
                        $output->write($remainingCharacters);
                        $fullChoice .= $remainingCharacters;
                        $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding);

                        $matches = array_filter(
                            $autocomplete($ret),
                            fn ($match) => '' === $ret || str_starts_with($match, $ret)
                        );
                        $numMatches = \count($matches);
                        $ofs = -1;
                    }

                    if ("\n" === $c) {
                        $output->write($c);
                        break;
                    }

                    $numMatches = 0;
                }

                continue;
            } else {
                if ("\x80" <= $c) {
                    $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
                }

                $output->write($c);
                $ret .= $c;
                $fullChoice .= $c;
                ++$i;

                $tempRet = $ret;

                if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
                    $tempRet = $this->mostRecentlyEnteredValue($fullChoice);
                }

                $numMatches = 0;
                $ofs = 0;

                foreach ($autocomplete($ret) as $value) {
                    // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
                    if (str_starts_with($value, $tempRet)) {
                        $matches[$numMatches++] = $value;
                    }
                }
            }

            $cursor->clearLineAfter();

            if ($numMatches > 0 && -1 !== $ofs) {
                $cursor->savePosition();
                // Write highlighted text, complete the partially entered response
                $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
                $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');
                $cursor->restorePosition();
            }
        }

        // Reset stty so it behaves normally again
        shell_exec('stty '.$sttyMode);

        return $fullChoice;
    }

    private function mostRecentlyEnteredValue(string $entered): string
    {
        // Determine the most recent value that the user entered
        if (!str_contains($entered, ',')) {
            return $entered;
        }

        $choices = explode(',', $entered);
        if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) {
            return $lastChoice;
        }

        return $entered;
    }

    /**
     * Gets a hidden response from user.
     *
     * @param resource $inputStream The handler resource
     * @param bool     $trimmable   Is the answer trimmable
     *
     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
     */
    private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';

            // handle code running from a phar
            if (str_starts_with(__FILE__, 'phar:')) {
                $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
                copy($exe, $tmpExe);
                $exe = $tmpExe;
            }

            $sExec = shell_exec('"'.$exe.'"');
            $value = $trimmable ? rtrim($sExec) : $sExec;
            $output->writeln('');

            if (isset($tmpExe)) {
                unlink($tmpExe);
            }

            return $value;
        }

        if (self::$stty && Terminal::hasSttyAvailable()) {
            $sttyMode = shell_exec('stty -g');
            shell_exec('stty -echo');
        } elseif ($this->isInteractiveInput($inputStream)) {
            throw new RuntimeException('Unable to hide the response.');
        }

        $value = fgets($inputStream, 4096);

        if (4095 === \strlen($value)) {
            $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
            $errOutput->warning('The value was possibly truncated by your shell or terminal emulator');
        }

        if (self::$stty && Terminal::hasSttyAvailable()) {
            shell_exec('stty '.$sttyMode);
        }

        if (false === $value) {
            throw new MissingInputException('Aborted.');
        }
        if ($trimmable) {
            $value = trim($value);
        }
        $output->writeln('');

        return $value;
    }

    /**
     * Validates an attempt.
     *
     * @param callable $interviewer A callable that will ask for a question and return the result
     *
     * @throws \Exception In case the max number of attempts has been reached and no valid response has been given
     */
    private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question): mixed
    {
        $error = null;
        $attempts = $question->getMaxAttempts();

        while (null === $attempts || $attempts--) {
            if (null !== $error) {
                $this->writeError($output, $error);
            }

            try {
                return $question->getValidator()($interviewer());
            } catch (RuntimeException $e) {
                throw $e;
            } catch (\Exception $error) {
            }
        }

        throw $error;
    }

    private function isInteractiveInput($inputStream): bool
    {
        if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) {
            return false;
        }

        if (isset(self::$stdinIsInteractive)) {
            return self::$stdinIsInteractive;
        }

        return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));
    }

    /**
     * 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
     */
    private function readInput($inputStream, Question $question): string|false
    {
        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 ("\x4" === $char || \PHP_EOL === "{$ret}{$char}") {
                break;
            }
            $ret .= $char;
        }

        if (stream_get_meta_data($inputStream)['seekable']) {
            fseek($inputStream, ftell($multiLineStreamReader));
        }

        return $this->resetIOCodepage($cp, $ret);
    }

    private function setIOCodepage(): int
    {
        if (\function_exists('sapi_windows_cp_set')) {
            $cp = sapi_windows_cp_get();
            sapi_windows_cp_set(sapi_windows_cp_get('oem'));

            return $cp;
        }

        return 0;
    }

    /**
     * Sets console I/O to the specified code page and converts the user input.
     */
    private function resetIOCodepage(int $cp, string|false $input): string|false
    {
        if (0 !== $cp) {
            sapi_windows_cp_set($cp);

            if (false !== $input && '' !== $input) {
                $input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * Symfony Style Guide compliant question helper.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class SymfonyQuestionHelper extends QuestionHelper
{
    /**
     * @return void
     */
    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(' <info>%s</info>:', $text);

                break;

            case $question instanceof ConfirmationQuestion:
                $text = \sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');

                break;

            case $question instanceof ChoiceQuestion && $question->isMultiselect():
                $choices = $question->getChoices();
                $default = explode(',', $default);

                foreach ($default as $key => $value) {
                    $default[$key] = $choices[trim($value)];
                }

                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));

                break;

            case $question instanceof ChoiceQuestion:
                $choices = $question->getChoices();
                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));

                break;

            default:
                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
        }

        $output->writeln($text);

        $prompt = ' > ';

        if ($question instanceof ChoiceQuestion) {
            $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));

            $prompt = $question->getPrompt();
        }

        $output->write($prompt);
    }

    /**
     * @return void
     */
    protected function writeError(OutputInterface $output, \Exception $error)
    {
        if ($output instanceof SymfonyStyle) {
            $output->newLine();
            $output->error($error->getMessage());

            return;
        }

        parent::writeError($output, $error);
    }

    private function getEofShortcut(): string
    {
        if ('Windows' === \PHP_OS_FAMILY) {
            return '<comment>Ctrl+Z</comment> then <comment>Enter</comment>';
        }

        return '<comment>Ctrl+D</comment>';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Provides helpers to display a table.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Саша Стаменковић <umpirsky@gmail.com>
 * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
 * @author Max Grigorian <maxakawizard@gmail.com>
 * @author Dany Maillard <danymaillard93b@gmail.com>
 */
class Table
{
    private const SEPARATOR_TOP = 0;
    private const SEPARATOR_TOP_BOTTOM = 1;
    private const SEPARATOR_MID = 2;
    private const SEPARATOR_BOTTOM = 3;
    private const BORDER_OUTSIDE = 0;
    private const BORDER_INSIDE = 1;
    private const DISPLAY_ORIENTATION_DEFAULT = 'default';
    private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal';
    private const DISPLAY_ORIENTATION_VERTICAL = 'vertical';

    private ?string $headerTitle = null;
    private ?string $footerTitle = null;
    private array $headers = [];
    private array $rows = [];
    private array $effectiveColumnWidths = [];
    private int $numberOfColumns;
    private OutputInterface $output;
    private TableStyle $style;
    private array $columnStyles = [];
    private array $columnWidths = [];
    private array $columnMaxWidths = [];
    private bool $rendered = false;
    private string $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT;

    private static array $styles;

    public function __construct(OutputInterface $output)
    {
        $this->output = $output;

        self::$styles ??= self::initStyles();

        $this->setStyle('default');
    }

    /**
     * Sets a style definition.
     *
     * @return void
     */
    public static function setStyleDefinition(string $name, TableStyle $style)
    {
        self::$styles ??= self::initStyles();

        self::$styles[$name] = $style;
    }

    /**
     * Gets a style definition by name.
     */
    public static function getStyleDefinition(string $name): TableStyle
    {
        self::$styles ??= self::initStyles();

        return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
    }

    /**
     * Sets table style.
     *
     * @return $this
     */
    public function setStyle(TableStyle|string $name): static
    {
        $this->style = $this->resolveStyle($name);

        return $this;
    }

    /**
     * Gets the current table style.
     */
    public function getStyle(): TableStyle
    {
        return $this->style;
    }

    /**
     * Sets table column style.
     *
     * @param TableStyle|string $name The style name or a TableStyle instance
     *
     * @return $this
     */
    public function setColumnStyle(int $columnIndex, TableStyle|string $name): static
    {
        $this->columnStyles[$columnIndex] = $this->resolveStyle($name);

        return $this;
    }

    /**
     * Gets the current style for a column.
     *
     * If style was not set, it returns the global table style.
     */
    public function getColumnStyle(int $columnIndex): TableStyle
    {
        return $this->columnStyles[$columnIndex] ?? $this->getStyle();
    }

    /**
     * Sets the minimum width of a column.
     *
     * @return $this
     */
    public function setColumnWidth(int $columnIndex, int $width): static
    {
        $this->columnWidths[$columnIndex] = $width;

        return $this;
    }

    /**
     * Sets the minimum width of all columns.
     *
     * @return $this
     */
    public function setColumnWidths(array $widths): static
    {
        $this->columnWidths = [];
        foreach ($widths as $index => $width) {
            $this->setColumnWidth($index, $width);
        }

        return $this;
    }

    /**
     * Sets the maximum width of a column.
     *
     * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while
     * formatted strings are preserved.
     *
     * @return $this
     */
    public function setColumnMaxWidth(int $columnIndex, int $width): static
    {
        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_debug_type($this->output->getFormatter())));
        }

        $this->columnMaxWidths[$columnIndex] = $width;

        return $this;
    }

    /**
     * @return $this
     */
    public function setHeaders(array $headers): static
    {
        $headers = array_values($headers);
        if ($headers && !\is_array($headers[0])) {
            $headers = [$headers];
        }

        $this->headers = $headers;

        return $this;
    }

    /**
     * @return $this
     */
    public function setRows(array $rows)
    {
        $this->rows = [];

        return $this->addRows($rows);
    }

    /**
     * @return $this
     */
    public function addRows(array $rows): static
    {
        foreach ($rows as $row) {
            $this->addRow($row);
        }

        return $this;
    }

    /**
     * @return $this
     */
    public function addRow(TableSeparator|array $row): static
    {
        if ($row instanceof TableSeparator) {
            $this->rows[] = $row;

            return $this;
        }

        $this->rows[] = array_values($row);

        return $this;
    }

    /**
     * Adds a row to the table, and re-renders the table.
     *
     * @return $this
     */
    public function appendRow(TableSeparator|array $row): static
    {
        if (!$this->output instanceof ConsoleSectionOutput) {
            throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
        }

        if ($this->rendered) {
            $this->output->clear($this->calculateRowCount());
        }

        $this->addRow($row);
        $this->render();

        return $this;
    }

    /**
     * @return $this
     */
    public function setRow(int|string $column, array $row): static
    {
        $this->rows[$column] = $row;

        return $this;
    }

    /**
     * @return $this
     */
    public function setHeaderTitle(?string $title): static
    {
        $this->headerTitle = $title;

        return $this;
    }

    /**
     * @return $this
     */
    public function setFooterTitle(?string $title): static
    {
        $this->footerTitle = $title;

        return $this;
    }

    /**
     * @return $this
     */
    public function setHorizontal(bool $horizontal = true): static
    {
        $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT;

        return $this;
    }

    /**
     * @return $this
     */
    public function setVertical(bool $vertical = true): static
    {
        $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT;

        return $this;
    }

    /**
     * Renders table to output.
     *
     * Example:
     *
     *     +---------------+-----------------------+------------------+
     *     | ISBN          | Title                 | Author           |
     *     +---------------+-----------------------+------------------+
     *     | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |
     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
     *     | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
     *     +---------------+-----------------------+------------------+
     *
     * @return void
     */
    public function render()
    {
        $divider = new TableSeparator();
        $isCellWithColspan = static fn ($cell) => $cell instanceof TableCell && $cell->getColspan() >= 2;

        $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation;
        $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation;

        $rows = [];
        if ($horizontal) {
            foreach ($this->headers[0] ?? [] as $i => $header) {
                $rows[$i] = [$header];
                foreach ($this->rows as $row) {
                    if ($row instanceof TableSeparator) {
                        continue;
                    }
                    if (isset($row[$i])) {
                        $rows[$i][] = $row[$i];
                    } elseif ($isCellWithColspan($rows[$i][0])) {
                        // Noop, there is a "title"
                    } else {
                        $rows[$i][] = null;
                    }
                }
            }
        } elseif ($vertical) {
            $formatter = $this->output->getFormatter();
            $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn ($max, $header) => max($max, Helper::width(Helper::removeDecoration($formatter, $header))), 0);

            foreach ($this->rows as $row) {
                if ($row instanceof TableSeparator) {
                    continue;
                }

                if ($rows) {
                    $rows[] = [$divider];
                }

                $containsColspan = false;
                foreach ($row as $cell) {
                    if ($containsColspan = $isCellWithColspan($cell)) {
                        break;
                    }
                }

                $headers = $this->headers[0] ?? [];
                $maxRows = max(\count($headers), \count($row));
                for ($i = 0; $i < $maxRows; ++$i) {
                    $cell = (string) ($row[$i] ?? '');

                    $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n";
                    $parts = explode($eol, $cell);
                    foreach ($parts as $idx => $part) {
                        if ($headers && !$containsColspan) {
                            if (0 === $idx) {
                                $rows[] = [\sprintf(
                                    '<comment>%s%s</>: %s',
                                    str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))),
                                    $headers[$i] ?? '',
                                    $part
                                )];
                            } else {
                                $rows[] = [\sprintf(
                                    '%s  %s',
                                    str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT),
                                    $part
                                )];
                            }
                        } elseif ('' !== $cell) {
                            $rows[] = [$part];
                        }
                    }
                }
            }
        } else {
            $rows = array_merge($this->headers, [$divider], $this->rows);
        }

        $this->calculateNumberOfColumns($rows);

        $rowGroups = $this->buildTableRows($rows);
        $this->calculateColumnsWidth($rowGroups);

        $isHeader = !$horizontal;
        $isFirstRow = $horizontal;
        $hasTitle = (bool) $this->headerTitle;

        foreach ($rowGroups as $rowGroup) {
            $isHeaderSeparatorRendered = false;

            foreach ($rowGroup as $row) {
                if ($divider === $row) {
                    $isHeader = false;
                    $isFirstRow = true;

                    continue;
                }

                if ($row instanceof TableSeparator) {
                    $this->renderRowSeparator();

                    continue;
                }

                if (!$row) {
                    continue;
                }

                if ($isHeader && !$isHeaderSeparatorRendered) {
                    $this->renderRowSeparator(
                        self::SEPARATOR_TOP,
                        $hasTitle ? $this->headerTitle : null,
                        $hasTitle ? $this->style->getHeaderTitleFormat() : null
                    );
                    $hasTitle = false;
                    $isHeaderSeparatorRendered = true;
                }

                if ($isFirstRow) {
                    $this->renderRowSeparator(
                        $horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
                        $hasTitle ? $this->headerTitle : null,
                        $hasTitle ? $this->style->getHeaderTitleFormat() : null
                    );
                    $isFirstRow = false;
                    $hasTitle = false;
                }

                if ($vertical) {
                    $isHeader = false;
                    $isFirstRow = false;
                }

                if ($horizontal) {
                    $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
                } else {
                    $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
                }
            }
        }
        $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());

        $this->cleanup();
        $this->rendered = true;
    }

    /**
     * Renders horizontal header separator.
     *
     * Example:
     *
     *     +-----+-----------+-------+
     */
    private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null): void
    {
        if (!$count = $this->numberOfColumns) {
            return;
        }

        $borders = $this->style->getBorderChars();
        if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
            return;
        }

        $crossings = $this->style->getCrossingChars();
        if (self::SEPARATOR_MID === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
        } elseif (self::SEPARATOR_TOP === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
        } elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
        } else {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
        }

        $markup = $leftChar;
        for ($column = 0; $column < $count; ++$column) {
            $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
            $markup .= $column === $count - 1 ? $rightChar : $midChar;
        }

        if (null !== $title) {
            $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::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, '')));
                $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
            }

            $titleStart = intdiv($markupLength - $titleLength, 2);
            if (false === mb_detect_encoding($markup, null, true)) {
                $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
            } else {
                $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength);
            }
        }

        $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup));
    }

    /**
     * Renders vertical column separator.
     */
    private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string
    {
        $borders = $this->style->getBorderChars();

        return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
    }

    /**
     * Renders table row.
     *
     * Example:
     *
     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
     */
    private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null): void
    {
        $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
        $columns = $this->getRowColumns($row);
        $last = \count($columns) - 1;
        foreach ($columns as $i => $column) {
            if ($firstCellFormat && 0 === $i) {
                $rowContent .= $this->renderCell($row, $column, $firstCellFormat);
            } else {
                $rowContent .= $this->renderCell($row, $column, $cellFormat);
            }
            $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
        }
        $this->output->writeln($rowContent);
    }

    /**
     * Renders table cell with padding.
     */
    private function renderCell(array $row, int $column, string $cellFormat): string
    {
        $cell = $row[$column] ?? '';
        $width = $this->effectiveColumnWidths[$column];
        if ($cell instanceof TableCell && $cell->getColspan() > 1) {
            // add the width of the following columns(numbers of colspan).
            foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
                $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
            }
        }

        // str_pad won't work properly with multi-byte strings, we need to fix the padding
        $width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0");
        $style = $this->getColumnStyle($column);

        if ($cell instanceof TableSeparator) {
            return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));
        }

        $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell));
        $content = \sprintf($style->getCellRowContentFormat(), $cell);

        $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 (str_contains($content, '</>')) {
                    $content = str_replace('</>', '', $content);
                    $width -= 3;
                }
                if (str_contains($content, '<fg=default;bg=default>')) {
                    $content = str_replace('<fg=default;bg=default>', '', $content);
                    $width -= \strlen('<fg=default;bg=default>');
                }
            }

            $padType = $cell->getStyle()->getPadByAlign();
        }

        return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType));
    }

    /**
     * Calculate number of columns for this table.
     */
    private function calculateNumberOfColumns(array $rows): void
    {
        $columns = [0];
        foreach ($rows as $row) {
            if ($row instanceof TableSeparator) {
                continue;
            }

            $columns[] = $this->getNumberOfColumns($row);
        }

        $this->numberOfColumns = max($columns);
    }

    private function buildTableRows(array $rows): TableRows
    {
        /** @var WrappableOutputFormatterInterface $formatter */
        $formatter = $this->output->getFormatter();
        $unmergedRows = [];
        for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
            $rows = $this->fillNextRows($rows, $rowKey);

            // Remove any new line breaks and replace it with a new line
            foreach ($rows[$rowKey] as $column => $cell) {
                $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;

                $minWrappedWidth = 0;
                $widthApplied = [];
                $lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2;
                for ($i = $column; $i < ($column + $colspan); ++$i) {
                    if (isset($this->columnMaxWidths[$i])) {
                        $minWrappedWidth += $this->columnMaxWidths[$i];
                        $widthApplied[] = ['type' => 'max', 'column' => $i];
                    } elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) {
                        $minWrappedWidth += $this->columnWidths[$i];
                        $widthApplied[] = ['type' => 'min', 'column' => $i];
                    }
                }
                if (1 === \count($widthApplied)) {
                    if ($colspan > 1) {
                        $minWrappedWidth *= $colspan;  // previous logic
                    }
                } elseif (\count($widthApplied) > 1) {
                    $minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder;
                }

                $cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell));
                if ($minWrappedWidth && $cellWidth > $minWrappedWidth) {
                    $cell = $formatter->formatAndWrap($cell, $minWrappedWidth);
                }
                // update minimal columnWidths for spanned columns
                if ($colspan > 1 && $minWrappedWidth > 0) {
                    $columnsMinWidthProcessed = [];
                    $cellWidth = min($cellWidth, $minWrappedWidth);
                    foreach ($widthApplied as $item) {
                        if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) {
                            $minWidthColumn = $this->columnMaxWidths[$item['column']];
                            $this->columnWidths[$item['column']] = $minWidthColumn;
                            $columnsMinWidthProcessed[$item['column']] = true;
                            $cellWidth -= $minWidthColumn + $lengthColumnBorder;
                        }
                    }
                    for ($i = $column; $i < ($column + $colspan); ++$i) {
                        if (isset($columnsMinWidthProcessed[$i])) {
                            continue;
                        }
                        $this->columnWidths[$i] = $cellWidth + $lengthColumnBorder;
                    }
                }
                if (!str_contains($cell ?? '', "\n")) {
                    continue;
                }
                $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n";
                $escaped = implode($eol, array_map(OutputFormatter::escapeTrailingBackslash(...), explode($eol, $cell)));
                $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
                $lines = explode($eol, str_replace($eol, '<fg=default;bg=default></>'.$eol, $cell));
                foreach ($lines as $lineKey => $line) {
                    if ($colspan > 1) {
                        $line = new TableCell($line, ['colspan' => $colspan]);
                    }
                    if (0 === $lineKey) {
                        $rows[$rowKey][$column] = $line;
                    } else {
                        if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
                            $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
                        }
                        $unmergedRows[$rowKey][$lineKey][$column] = $line;
                    }
                }
            }
        }

        return new TableRows(function () use ($rows, $unmergedRows): \Traversable {
            foreach ($rows as $rowKey => $row) {
                $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];

                if (isset($unmergedRows[$rowKey])) {
                    foreach ($unmergedRows[$rowKey] as $row) {
                        $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);
                    }
                }
                yield $rowGroup;
            }
        });
    }

    private function calculateRowCount(): int
    {
        $numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));

        if ($this->headers) {
            ++$numberOfRows; // Add row for header separator
        }

        if ($this->rows) {
            ++$numberOfRows; // Add row for footer separator
        }

        return $numberOfRows;
    }

    /**
     * fill rows that contains rowspan > 1.
     *
     * @throws InvalidArgumentException
     */
    private function fillNextRows(array $rows, int $line): array
    {
        $unmergedRows = [];
        foreach ($rows[$line] as $column => $cell) {
            if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) {
                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;
                $lines = [$cell];
                if (str_contains($cell, "\n")) {
                    $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n";
                    $lines = explode($eol, str_replace($eol, '<fg=default;bg=default>'.$eol.'</>', $cell));
                    $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines;

                    $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
                    unset($lines[0]);
                }

                // create a two dimensional array (rowspan x colspan)
                $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(), 'style' => $cell->getStyle()]);
                    if ($nbLines === $unmergedRowKey - $line) {
                        break;
                    }
                }
            }
        }

        foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
            // we need to know if $unmergedRow will be merged or inserted into $rows
            if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
                foreach ($unmergedRow as $cellKey => $cell) {
                    // insert cell into row at cellKey position
                    array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
                }
            } else {
                $row = $this->copyRow($rows, $unmergedRowKey - 1);
                foreach ($unmergedRow as $column => $cell) {
                    if (!empty($cell)) {
                        $row[$column] = $unmergedRow[$column];
                    }
                }
                array_splice($rows, $unmergedRowKey, 0, [$row]);
            }
        }

        return $rows;
    }

    /**
     * fill cells for a row that contains colspan > 1.
     */
    private function fillCells(iterable $row): iterable
    {
        $newRow = [];

        foreach ($row as $column => $cell) {
            $newRow[] = $cell;
            if ($cell instanceof TableCell && $cell->getColspan() > 1) {
                foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
                    // insert empty value at column position
                    $newRow[] = '';
                }
            }
        }

        return $newRow ?: $row;
    }

    private function copyRow(array $rows, int $line): array
    {
        $row = $rows[$line];
        foreach ($row as $cellKey => $cellValue) {
            $row[$cellKey] = '';
            if ($cellValue instanceof TableCell) {
                $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
            }
        }

        return $row;
    }

    /**
     * Gets number of columns by row.
     */
    private function getNumberOfColumns(array $row): int
    {
        $columns = \count($row);
        foreach ($row as $column) {
            $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
        }

        return $columns;
    }

    /**
     * Gets list of columns for the given row.
     */
    private function getRowColumns(array $row): array
    {
        $columns = range(0, $this->numberOfColumns - 1);
        foreach ($row as $cellKey => $cell) {
            if ($cell instanceof TableCell && $cell->getColspan() > 1) {
                // exclude grouped columns.
                $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
            }
        }

        return $columns;
    }

    /**
     * Calculates columns widths.
     */
    private function calculateColumnsWidth(iterable $groups): void
    {
        for ($column = 0; $column < $this->numberOfColumns; ++$column) {
            $lengths = [];
            foreach ($groups as $group) {
                foreach ($group as $row) {
                    if ($row instanceof TableSeparator) {
                        continue;
                    }

                    foreach ($row as $i => $cell) {
                        if ($cell instanceof TableCell) {
                            $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
                            $textLength = Helper::width($textContent);
                            if ($textLength > 0) {
                                $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));
                                foreach ($contentColumns as $position => $content) {
                                    $row[$i + $position] = $content;
                                }
                            }
                        }
                    }

                    $lengths[] = $this->getCellWidth($row, $column);
                }
            }

            $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2;
        }
    }

    private function getColumnSeparatorWidth(): int
    {
        return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
    }

    private function getCellWidth(array $row, int $column): int
    {
        $cellWidth = 0;

        if (isset($row[$column])) {
            $cell = $row[$column];
            $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell));
        }

        $columnWidth = $this->columnWidths[$column] ?? 0;
        $cellWidth = max($cellWidth, $columnWidth);

        return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
    }

    /**
     * Called after rendering to cleanup cache data.
     */
    private function cleanup(): void
    {
        $this->effectiveColumnWidths = [];
        unset($this->numberOfColumns);
    }

    /**
     * @return array<string, TableStyle>
     */
    private static function initStyles(): array
    {
        $borderless = new TableStyle();
        $borderless
            ->setHorizontalBorderChars('=')
            ->setVerticalBorderChars(' ')
            ->setDefaultCrossingChar(' ')
        ;

        $compact = new TableStyle();
        $compact
            ->setHorizontalBorderChars('')
            ->setVerticalBorderChars('')
            ->setDefaultCrossingChar('')
            ->setCellRowContentFormat('%s ')
        ;

        $styleGuide = new TableStyle();
        $styleGuide
            ->setHorizontalBorderChars('-')
            ->setVerticalBorderChars(' ')
            ->setDefaultCrossingChar(' ')
            ->setCellHeaderFormat('%s')
        ;

        $box = (new TableStyle())
            ->setHorizontalBorderChars('─')
            ->setVerticalBorderChars('│')
            ->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├')
        ;

        $boxDouble = (new TableStyle())
            ->setHorizontalBorderChars('═', '─')
            ->setVerticalBorderChars('║', '│')
            ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣')
        ;

        return [
            'default' => new TableStyle(),
            'borderless' => $borderless,
            'compact' => $compact,
            'symfony-style-guide' => $styleGuide,
            'box' => $box,
            'box-double' => $boxDouble,
        ];
    }

    private function resolveStyle(TableStyle|string $name): TableStyle
    {
        if ($name instanceof TableStyle) {
            return $name;
        }

        return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
 */
class TableCell
{
    private string $value;
    private array $options = [
        'rowspan' => 1,
        'colspan' => 1,
        'style' => null,
    ];

    public function __construct(string $value = '', array $options = [])
    {
        $this->value = $value;

        // check option names
        if ($diff = array_diff(array_keys($options), array_keys($this->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);
    }

    /**
     * Returns the cell value.
     */
    public function __toString(): string
    {
        return $this->value;
    }

    /**
     * Gets number of colspan.
     */
    public function getColspan(): int
    {
        return (int) $this->options['colspan'];
    }

    /**
     * Gets number of rowspan.
     */
    public function getRowspan(): int
    {
        return (int) $this->options['rowspan'];
    }

    public function getStyle(): ?TableCellStyle
    {
        return $this->options['style'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * @author Yewhen Khoptynskyi <khoptynskyi@gmail.com>
 */
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 array $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(): array
    {
        return array_filter(
            $this->getOptions(),
            fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]),
            \ARRAY_FILTER_USE_KEY
        );
    }

    public function getPadByAlign(): int
    {
        return self::ALIGN_MAP[$this->getOptions()['align']];
    }

    public function getCellFormat(): ?string
    {
        return $this->getOptions()['cellFormat'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

/**
 * @internal
 */
class TableRows implements \IteratorAggregate
{
    private \Closure $generator;

    public function __construct(\Closure $generator)
    {
        $this->generator = $generator;
    }

    public function getIterator(): \Traversable
    {
        return ($this->generator)();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

/**
 * Marks a row as being a separator.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class TableSeparator extends TableCell
{
    public function __construct(array $options = [])
    {
        parent::__construct('', $options);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

/**
 * Defines the styles for a Table.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Саша Стаменковић <umpirsky@gmail.com>
 * @author Dany Maillard <danymaillard93b@gmail.com>
 */
class TableStyle
{
    private string $paddingChar = ' ';
    private string $horizontalOutsideBorderChar = '-';
    private string $horizontalInsideBorderChar = '-';
    private string $verticalOutsideBorderChar = '|';
    private string $verticalInsideBorderChar = '|';
    private string $crossingChar = '+';
    private string $crossingTopRightChar = '+';
    private string $crossingTopMidChar = '+';
    private string $crossingTopLeftChar = '+';
    private string $crossingMidRightChar = '+';
    private string $crossingBottomRightChar = '+';
    private string $crossingBottomMidChar = '+';
    private string $crossingBottomLeftChar = '+';
    private string $crossingMidLeftChar = '+';
    private string $crossingTopLeftBottomChar = '+';
    private string $crossingTopMidBottomChar = '+';
    private string $crossingTopRightBottomChar = '+';
    private string $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
    private string $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
    private string $cellHeaderFormat = '<info>%s</info>';
    private string $cellRowFormat = '%s';
    private string $cellRowContentFormat = ' %s ';
    private string $borderFormat = '%s';
    private int $padType = \STR_PAD_RIGHT;

    /**
     * Sets padding character, used for cell padding.
     *
     * @return $this
     */
    public function setPaddingChar(string $paddingChar): static
    {
        if (!$paddingChar) {
            throw new LogicException('The padding char must not be empty.');
        }

        $this->paddingChar = $paddingChar;

        return $this;
    }

    /**
     * Gets padding character, used for cell padding.
     */
    public function getPaddingChar(): string
    {
        return $this->paddingChar;
    }

    /**
     * Sets horizontal border characters.
     *
     * <code>
     * ╔═══════════════╤══════════════════════════╤══════════════════╗
     * 1 ISBN          2 Title                    │ Author           ║
     * ╠═══════════════╪══════════════════════════╪══════════════════╣
     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
     * ╚═══════════════╧══════════════════════════╧══════════════════╝
     * </code>
     *
     * @return $this
     */
    public function setHorizontalBorderChars(string $outside, ?string $inside = null): static
    {
        $this->horizontalOutsideBorderChar = $outside;
        $this->horizontalInsideBorderChar = $inside ?? $outside;

        return $this;
    }

    /**
     * Sets vertical border characters.
     *
     * <code>
     * ╔═══════════════╤══════════════════════════╤══════════════════╗
     * ║ ISBN          │ Title                    │ Author           ║
     * ╠═══════1═══════╪══════════════════════════╪══════════════════╣
     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
     * ╟───────2───────┼──────────────────────────┼──────────────────╢
     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
     * ╚═══════════════╧══════════════════════════╧══════════════════╝
     * </code>
     *
     * @return $this
     */
    public function setVerticalBorderChars(string $outside, ?string $inside = null): static
    {
        $this->verticalOutsideBorderChar = $outside;
        $this->verticalInsideBorderChar = $inside ?? $outside;

        return $this;
    }

    /**
     * Gets border characters.
     *
     * @internal
     */
    public function getBorderChars(): array
    {
        return [
            $this->horizontalOutsideBorderChar,
            $this->verticalOutsideBorderChar,
            $this->horizontalInsideBorderChar,
            $this->verticalInsideBorderChar,
        ];
    }

    /**
     * Sets crossing characters.
     *
     * Example:
     * <code>
     * 1═══════════════2══════════════════════════2══════════════════3
     * ║ ISBN          │ Title                    │ Author           ║
     * 8'══════════════0'═════════════════════════0'═════════════════4'
     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║
     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║
     * 8───────────────0──────────────────────────0──────────────────4
     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║
     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
     * 7═══════════════6══════════════════════════6══════════════════5
     * </code>
     *
     * @param string      $cross          Crossing char (see #0 of example)
     * @param string      $topLeft        Top left char (see #1 of example)
     * @param string      $topMid         Top mid char (see #2 of example)
     * @param string      $topRight       Top right char (see #3 of example)
     * @param string      $midRight       Mid right char (see #4 of example)
     * @param string      $bottomRight    Bottom right char (see #5 of example)
     * @param string      $bottomMid      Bottom mid char (see #6 of example)
     * @param string      $bottomLeft     Bottom left char (see #7 of example)
     * @param string      $midLeft        Mid left char (see #8 of example)
     * @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): static
    {
        $this->crossingChar = $cross;
        $this->crossingTopLeftChar = $topLeft;
        $this->crossingTopMidChar = $topMid;
        $this->crossingTopRightChar = $topRight;
        $this->crossingMidRightChar = $midRight;
        $this->crossingBottomRightChar = $bottomRight;
        $this->crossingBottomMidChar = $bottomMid;
        $this->crossingBottomLeftChar = $bottomLeft;
        $this->crossingMidLeftChar = $midLeft;
        $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
        $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
        $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;

        return $this;
    }

    /**
     * Sets default crossing character used for each cross.
     *
     * @see {@link setCrossingChars()} for setting each crossing individually.
     */
    public function setDefaultCrossingChar(string $char): self
    {
        return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
    }

    /**
     * Gets crossing character.
     */
    public function getCrossingChar(): string
    {
        return $this->crossingChar;
    }

    /**
     * Gets crossing characters.
     *
     * @internal
     */
    public function getCrossingChars(): array
    {
        return [
            $this->crossingChar,
            $this->crossingTopLeftChar,
            $this->crossingTopMidChar,
            $this->crossingTopRightChar,
            $this->crossingMidRightChar,
            $this->crossingBottomRightChar,
            $this->crossingBottomMidChar,
            $this->crossingBottomLeftChar,
            $this->crossingMidLeftChar,
            $this->crossingTopLeftBottomChar,
            $this->crossingTopMidBottomChar,
            $this->crossingTopRightBottomChar,
        ];
    }

    /**
     * Sets header cell format.
     *
     * @return $this
     */
    public function setCellHeaderFormat(string $cellHeaderFormat): static
    {
        $this->cellHeaderFormat = $cellHeaderFormat;

        return $this;
    }

    /**
     * Gets header cell format.
     */
    public function getCellHeaderFormat(): string
    {
        return $this->cellHeaderFormat;
    }

    /**
     * Sets row cell format.
     *
     * @return $this
     */
    public function setCellRowFormat(string $cellRowFormat): static
    {
        $this->cellRowFormat = $cellRowFormat;

        return $this;
    }

    /**
     * Gets row cell format.
     */
    public function getCellRowFormat(): string
    {
        return $this->cellRowFormat;
    }

    /**
     * Sets row cell content format.
     *
     * @return $this
     */
    public function setCellRowContentFormat(string $cellRowContentFormat): static
    {
        $this->cellRowContentFormat = $cellRowContentFormat;

        return $this;
    }

    /**
     * Gets row cell content format.
     */
    public function getCellRowContentFormat(): string
    {
        return $this->cellRowContentFormat;
    }

    /**
     * Sets table border format.
     *
     * @return $this
     */
    public function setBorderFormat(string $borderFormat): static
    {
        $this->borderFormat = $borderFormat;

        return $this;
    }

    /**
     * Gets table border format.
     */
    public function getBorderFormat(): string
    {
        return $this->borderFormat;
    }

    /**
     * Sets cell padding type.
     *
     * @return $this
     */
    public function setPadType(int $padType): static
    {
        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).');
        }

        $this->padType = $padType;

        return $this;
    }

    /**
     * Gets cell padding type.
     */
    public function getPadType(): int
    {
        return $this->padType;
    }

    public function getHeaderTitleFormat(): string
    {
        return $this->headerTitleFormat;
    }

    /**
     * @return $this
     */
    public function setHeaderTitleFormat(string $format): static
    {
        $this->headerTitleFormat = $format;

        return $this;
    }

    public function getFooterTitleFormat(): string
    {
        return $this->footerTitleFormat;
    }

    /**
     * @return $this
     */
    public function setFooterTitleFormat(string $format): static
    {
        $this->footerTitleFormat = $format;

        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\RuntimeException;

/**
 * ArgvInput represents an input coming from the CLI arguments.
 *
 * Usage:
 *
 *     $input = new ArgvInput();
 *
 * By default, the `$_SERVER['argv']` array is used for the input values.
 *
 * This can be overridden by explicitly passing the input values in the constructor:
 *
 *     $input = new ArgvInput($_SERVER['argv']);
 *
 * If you pass it yourself, don't forget that the first element of the array
 * is the name of the running application.
 *
 * When passing an argument to the constructor, be sure that it respects
 * the same rules as the argv one. It's almost always better to use the
 * `StringInput` when you want to provide your own input.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
 * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
 */
class ArgvInput extends Input
{
    private array $tokens;
    private array $parsed;

    public function __construct(?array $argv = null, ?InputDefinition $definition = null)
    {
        $argv ??= $_SERVER['argv'] ?? [];

        // strip the application name
        array_shift($argv);

        $this->tokens = $argv;

        parent::__construct($definition);
    }

    /**
     * @return void
     */
    protected function setTokens(array $tokens)
    {
        $this->tokens = $tokens;
    }

    /**
     * @return void
     */
    protected function parse()
    {
        $parseOptions = true;
        $this->parsed = $this->tokens;
        while (null !== $token = array_shift($this->parsed)) {
            $parseOptions = $this->parseToken($token, $parseOptions);
        }
    }

    protected function parseToken(string $token, bool $parseOptions): bool
    {
        if ($parseOptions && '' == $token) {
            $this->parseArgument($token);
        } elseif ($parseOptions && '--' == $token) {
            return false;
        } elseif ($parseOptions && str_starts_with($token, '--')) {
            $this->parseLongOption($token);
        } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
            $this->parseShortOption($token);
        } else {
            $this->parseArgument($token);
        }

        return $parseOptions;
    }

    /**
     * Parses a short option.
     */
    private function parseShortOption(string $token): void
    {
        $name = substr($token, 1);

        if (\strlen($name) > 1) {
            if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
                // an option with a value (with no space)
                $this->addShortOption($name[0], substr($name, 1));
            } else {
                $this->parseShortOptionSet($name);
            }
        } else {
            $this->addShortOption($name, null);
        }
    }

    /**
     * Parses a short option set.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function parseShortOptionSet(string $name): void
    {
        $len = \strlen($name);
        for ($i = 0; $i < $len; ++$i) {
            if (!$this->definition->hasShortcut($name[$i])) {
                $encoding = mb_detect_encoding($name, null, true);
                throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));
            }

            $option = $this->definition->getOptionForShortcut($name[$i]);
            if ($option->acceptValue()) {
                $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));

                break;
            } else {
                $this->addLongOption($option->getName(), null);
            }
        }
    }

    /**
     * Parses a long option.
     */
    private function parseLongOption(string $token): void
    {
        $name = substr($token, 2);

        if (false !== $pos = strpos($name, '=')) {
            if ('' === $value = substr($name, $pos + 1)) {
                array_unshift($this->parsed, $value);
            }
            $this->addLongOption(substr($name, 0, $pos), $value);
        } else {
            $this->addLongOption($name, null);
        }
    }

    /**
     * Parses an argument.
     *
     * @throws RuntimeException When too many arguments are given
     */
    private function parseArgument(string $token): void
    {
        $c = \count($this->arguments);

        // if input is expecting another argument, add it
        if ($this->definition->hasArgument($c)) {
            $arg = $this->definition->getArgument($c);
            $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;

        // if last argument isArray(), append token to last argument
        } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
            $arg = $this->definition->getArgument($c - 1);
            $this->arguments[$arg->getName()][] = $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)) {
                if ($symfonyCommandName) {
                    $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all)));
                } else {
                    $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all)));
                }
            } elseif ($symfonyCommandName) {
                $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token);
            } else {
                $message = \sprintf('No arguments expected, got "%s".', $token);
            }

            throw new RuntimeException($message);
        }
    }

    /**
     * Adds a short option value.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function addShortOption(string $shortcut, mixed $value): void
    {
        if (!$this->definition->hasShortcut($shortcut)) {
            throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }

        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
    }

    /**
     * Adds a long option value.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function addLongOption(string $name, mixed $value): void
    {
        if (!$this->definition->hasOption($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);

        if (null !== $value && !$option->acceptValue()) {
            throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name));
        }

        if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {
            // if option accepts an optional or mandatory argument
            // let's see if there is one provided
            $next = array_shift($this->parsed);
            if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
                $value = $next;
            } else {
                array_unshift($this->parsed, $next);
            }
        }

        if (null === $value) {
            if ($option->isValueRequired()) {
                throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name));
            }

            if (!$option->isArray() && !$option->isValueOptional()) {
                $value = true;
            }
        }

        if ($option->isArray()) {
            $this->options[$name][] = $value;
        } else {
            $this->options[$name] = $value;
        }
    }

    public function getFirstArgument(): ?string
    {
        $isOption = false;
        foreach ($this->tokens as $i => $token) {
            if ($token && '-' === $token[0]) {
                if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) {
                    continue;
                }

                // If it's a long option, consider that everything after "--" is the option name.
                // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
                $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
                if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
                    // noop
                } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
                    $isOption = true;
                }

                continue;
            }

            if ($isOption) {
                $isOption = false;
                continue;
            }

            return $token;
        }

        return null;
    }

    public function hasParameterOption(string|array $values, bool $onlyParams = false): bool
    {
        $values = (array) $values;

        foreach ($this->tokens as $token) {
            if ($onlyParams && '--' === $token) {
                return false;
            }
            foreach ($values as $value) {
                // Options with values:
                //   For long options, test for '--option=' at beginning
                //   For short options, test for '-o' at beginning
                $leading = str_starts_with($value, '--') ? $value.'=' : $value;
                if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) {
                    return true;
                }
            }
        }

        return false;
    }

    public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed
    {
        $values = (array) $values;
        $tokens = $this->tokens;

        while (0 < \count($tokens)) {
            $token = array_shift($tokens);
            if ($onlyParams && '--' === $token) {
                return $default;
            }

            foreach ($values as $value) {
                if ($token === $value) {
                    return array_shift($tokens);
                }
                // Options with values:
                //   For long options, test for '--option=' at beginning
                //   For short options, test for '-o' at beginning
                $leading = str_starts_with($value, '--') ? $value.'=' : $value;
                if ('' !== $leading && str_starts_with($token, $leading)) {
                    return substr($token, \strlen($leading));
                }
            }
        }

        return $default;
    }

    /**
     * Returns a stringified representation of the args passed to the command.
     */
    public function __toString(): string
    {
        $tokens = array_map(function ($token) {
            if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
                return $match[1].$this->escapeToken($match[2]);
            }

            if ($token && '-' !== $token[0]) {
                return $this->escapeToken($token);
            }

            return $token;
        }, $this->tokens);

        return implode(' ', $tokens);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\InvalidOptionException;

/**
 * ArrayInput represents an input provided as an array.
 *
 * Usage:
 *
 *     $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ArrayInput extends Input
{
    private array $parameters;

    public function __construct(array $parameters, ?InputDefinition $definition = null)
    {
        $this->parameters = $parameters;

        parent::__construct($definition);
    }

    public function getFirstArgument(): ?string
    {
        foreach ($this->parameters as $param => $value) {
            if ($param && \is_string($param) && '-' === $param[0]) {
                continue;
            }

            return $value;
        }

        return null;
    }

    public function hasParameterOption(string|array $values, bool $onlyParams = false): bool
    {
        $values = (array) $values;

        foreach ($this->parameters as $k => $v) {
            if (!\is_int($k)) {
                $v = $k;
            }

            if ($onlyParams && '--' === $v) {
                return false;
            }

            if (\in_array($v, $values)) {
                return true;
            }
        }

        return false;
    }

    public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed
    {
        $values = (array) $values;

        foreach ($this->parameters as $k => $v) {
            if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) {
                return $default;
            }

            if (\is_int($k)) {
                if (\in_array($v, $values)) {
                    return true;
                }
            } elseif (\in_array($k, $values)) {
                return $v;
            }
        }

        return $default;
    }

    /**
     * Returns a stringified representation of the args passed to the command.
     */
    public function __toString(): string
    {
        $params = [];
        foreach ($this->parameters as $param => $val) {
            if ($param && \is_string($param) && '-' === $param[0]) {
                $glue = ('-' === $param[1]) ? '=' : ' ';
                if (\is_array($val)) {
                    foreach ($val as $v) {
                        $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
                    }
                } else {
                    $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
                }
            } else {
                $params[] = \is_array($val) ? implode(' ', array_map($this->escapeToken(...), $val)) : $this->escapeToken($val);
            }
        }

        return implode(' ', $params);
    }

    /**
     * @return void
     */
    protected function parse()
    {
        foreach ($this->parameters as $key => $value) {
            if ('--' === $key) {
                return;
            }
            if (str_starts_with($key, '--')) {
                $this->addLongOption(substr($key, 2), $value);
            } elseif (str_starts_with($key, '-')) {
                $this->addShortOption(substr($key, 1), $value);
            } else {
                $this->addArgument($key, $value);
            }
        }
    }

    /**
     * Adds a short option value.
     *
     * @throws InvalidOptionException When option given doesn't exist
     */
    private function addShortOption(string $shortcut, mixed $value): void
    {
        if (!$this->definition->hasShortcut($shortcut)) {
            throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }

        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
    }

    /**
     * Adds a long option value.
     *
     * @throws InvalidOptionException When option given doesn't exist
     * @throws InvalidOptionException When a required value is missing
     */
    private function addLongOption(string $name, mixed $value): void
    {
        if (!$this->definition->hasOption($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);

        if (null === $value) {
            if ($option->isValueRequired()) {
                throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name));
            }

            if (!$option->isValueOptional()) {
                $value = true;
            }
        }

        $this->options[$name] = $value;
    }

    /**
     * Adds an argument value.
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    private function addArgument(string|int $name, mixed $value): void
    {
        if (!$this->definition->hasArgument($name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }

        $this->arguments[$name] = $value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;

/**
 * Input is the base class for all concrete Input classes.
 *
 * Three concrete classes are provided by default:
 *
 *  * `ArgvInput`: The input comes from the CLI arguments (argv)
 *  * `StringInput`: The input is provided as a string
 *  * `ArrayInput`: The input is provided as an array
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Input implements InputInterface, StreamableInputInterface
{
    protected $definition;
    /** @var resource */
    protected $stream;
    protected $options = [];
    protected $arguments = [];
    protected $interactive = true;

    public function __construct(?InputDefinition $definition = null)
    {
        if (null === $definition) {
            $this->definition = new InputDefinition();
        } else {
            $this->bind($definition);
            $this->validate();
        }
    }

    /**
     * @return void
     */
    public function bind(InputDefinition $definition)
    {
        $this->arguments = [];
        $this->options = [];
        $this->definition = $definition;

        $this->parse();
    }

    /**
     * Processes command line arguments.
     *
     * @return void
     */
    abstract protected function parse();

    /**
     * @return void
     */
    public function validate()
    {
        $definition = $this->definition;
        $givenArguments = $this->arguments;

        $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired());

        if (\count($missingArguments) > 0) {
            throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
        }
    }

    public function isInteractive(): bool
    {
        return $this->interactive;
    }

    /**
     * @return void
     */
    public function setInteractive(bool $interactive)
    {
        $this->interactive = $interactive;
    }

    public function getArguments(): array
    {
        return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
    }

    public function getArgument(string $name): mixed
    {
        if (!$this->definition->hasArgument($name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }

        return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
    }

    /**
     * @return void
     */
    public function setArgument(string $name, mixed $value)
    {
        if (!$this->definition->hasArgument($name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }

        $this->arguments[$name] = $value;
    }

    public function hasArgument(string $name): bool
    {
        return $this->definition->hasArgument($name);
    }

    public function getOptions(): array
    {
        return array_merge($this->definition->getOptionDefaults(), $this->options);
    }

    public function getOption(string $name): mixed
    {
        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));
        }

        return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
    }

    /**
     * @return void
     */
    public function setOption(string $name, mixed $value)
    {
        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));
        }

        $this->options[$name] = $value;
    }

    public function hasOption(string $name): bool
    {
        return $this->definition->hasOption($name) || $this->definition->hasNegation($name);
    }

    /**
     * Escapes a token through escapeshellarg if it contains unsafe chars.
     */
    public function escapeToken(string $token): string
    {
        return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
    }

    /**
     * @param resource $stream
     *
     * @return void
     */
    public function setStream($stream)
    {
        $this->stream = $stream;
    }

    /**
     * @return resource
     */
    public function getStream()
    {
        return $this->stream;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

/**
 * Represents a command line argument.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputArgument
{
    public const REQUIRED = 1;
    public const OPTIONAL = 2;
    public const IS_ARRAY = 4;

    private string $name;
    private int $mode;
    private string|int|bool|array|float|null $default;
    private array|\Closure $suggestedValues;
    private string $description;

    /**
     * @param string                                                                        $name            The argument name
     * @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)
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     *
     * @throws InvalidArgumentException When argument mode is not valid
     */
    public function __construct(string $name, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, \Closure|array $suggestedValues = [])
    {
        if (null === $mode) {
            $mode = self::OPTIONAL;
        } elseif ($mode > 7 || $mode < 1) {
            throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode));
        }

        $this->name = $name;
        $this->mode = $mode;
        $this->description = $description;
        $this->suggestedValues = $suggestedValues;

        $this->setDefault($default);
    }

    /**
     * Returns the argument name.
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * Returns true if the argument is required.
     *
     * @return bool true if parameter mode is self::REQUIRED, false otherwise
     */
    public function isRequired(): bool
    {
        return self::REQUIRED === (self::REQUIRED & $this->mode);
    }

    /**
     * Returns true if the argument can take multiple values.
     *
     * @return bool true if mode is self::IS_ARRAY, false otherwise
     */
    public function isArray(): bool
    {
        return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
    }

    /**
     * Sets the default value.
     *
     * @return void
     *
     * @throws LogicException When incorrect default value is given
     */
    public function setDefault(string|bool|int|float|array|null $default = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        if ($this->isRequired() && null !== $default) {
            throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
        }

        if ($this->isArray()) {
            if (null === $default) {
                $default = [];
            } elseif (!\is_array($default)) {
                throw new LogicException('A default value for an array argument must be an array.');
            }
        }

        $this->default = $default;
    }

    /**
     * Returns the default value.
     */
    public function getDefault(): string|bool|int|float|array|null
    {
        return $this->default;
    }

    public function hasCompletion(): bool
    {
        return [] !== $this->suggestedValues;
    }

    /**
     * Adds suggestions to $suggestions for the current completion input.
     *
     * @see Command::complete()
     */
    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        $values = $this->suggestedValues;
        if ($values instanceof \Closure && !\is_array($values = $values($input))) {
            throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values)));
        }
        if ($values) {
            $suggestions->suggestValues($values);
        }
    }

    /**
     * Returns the description text.
     */
    public function getDescription(): string
    {
        return $this->description;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

/**
 * InputAwareInterface should be implemented by classes that depends on the
 * Console Input.
 *
 * @author Wouter J <waldio.webdesign@gmail.com>
 */
interface InputAwareInterface
{
    /**
     * Sets the Console Input.
     *
     * @return void
     */
    public function setInput(InputInterface $input);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

/**
 * A InputDefinition represents a set of valid command line arguments and options.
 *
 * Usage:
 *
 *     $definition = new InputDefinition([
 *         new InputArgument('name', InputArgument::REQUIRED),
 *         new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
 *     ]);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputDefinition
{
    private array $arguments = [];
    private int $requiredCount = 0;
    private ?InputArgument $lastArrayArgument = null;
    private ?InputArgument $lastOptionalArgument = null;
    private array $options = [];
    private array $negations = [];
    private array $shortcuts = [];

    /**
     * @param array $definition An array of InputArgument and InputOption instance
     */
    public function __construct(array $definition = [])
    {
        $this->setDefinition($definition);
    }

    /**
     * Sets the definition of the input.
     *
     * @return void
     */
    public function setDefinition(array $definition)
    {
        $arguments = [];
        $options = [];
        foreach ($definition as $item) {
            if ($item instanceof InputOption) {
                $options[] = $item;
            } else {
                $arguments[] = $item;
            }
        }

        $this->setArguments($arguments);
        $this->setOptions($options);
    }

    /**
     * Sets the InputArgument objects.
     *
     * @param InputArgument[] $arguments An array of InputArgument objects
     *
     * @return void
     */
    public function setArguments(array $arguments = [])
    {
        $this->arguments = [];
        $this->requiredCount = 0;
        $this->lastOptionalArgument = null;
        $this->lastArrayArgument = null;
        $this->addArguments($arguments);
    }

    /**
     * Adds an array of InputArgument objects.
     *
     * @param InputArgument[] $arguments An array of InputArgument objects
     *
     * @return void
     */
    public function addArguments(?array $arguments = [])
    {
        if (null !== $arguments) {
            foreach ($arguments as $argument) {
                $this->addArgument($argument);
            }
        }
    }

    /**
     * @return void
     *
     * @throws LogicException When incorrect argument is given
     */
    public function addArgument(InputArgument $argument)
    {
        if (isset($this->arguments[$argument->getName()])) {
            throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName()));
        }

        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() && 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->lastArrayArgument = $argument;
        }

        if ($argument->isRequired()) {
            ++$this->requiredCount;
        } else {
            $this->lastOptionalArgument = $argument;
        }

        $this->arguments[$argument->getName()] = $argument;
    }

    /**
     * Returns an InputArgument by name or by position.
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    public function getArgument(string|int $name): InputArgument
    {
        if (!$this->hasArgument($name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }

        $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;

        return $arguments[$name];
    }

    /**
     * Returns true if an InputArgument object exists by name or position.
     */
    public function hasArgument(string|int $name): bool
    {
        $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments;

        return isset($arguments[$name]);
    }

    /**
     * Gets the array of InputArgument objects.
     *
     * @return InputArgument[]
     */
    public function getArguments(): array
    {
        return $this->arguments;
    }

    /**
     * Returns the number of InputArguments.
     */
    public function getArgumentCount(): int
    {
        return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
    }

    /**
     * Returns the number of required InputArguments.
     */
    public function getArgumentRequiredCount(): int
    {
        return $this->requiredCount;
    }

    /**
     * @return array<string|bool|int|float|array|null>
     */
    public function getArgumentDefaults(): array
    {
        $values = [];
        foreach ($this->arguments as $argument) {
            $values[$argument->getName()] = $argument->getDefault();
        }

        return $values;
    }

    /**
     * Sets the InputOption objects.
     *
     * @param InputOption[] $options An array of InputOption objects
     *
     * @return void
     */
    public function setOptions(array $options = [])
    {
        $this->options = [];
        $this->shortcuts = [];
        $this->negations = [];
        $this->addOptions($options);
    }

    /**
     * Adds an array of InputOption objects.
     *
     * @param InputOption[] $options An array of InputOption objects
     *
     * @return void
     */
    public function addOptions(array $options = [])
    {
        foreach ($options as $option) {
            $this->addOption($option);
        }
    }

    /**
     * @return void
     *
     * @throws LogicException When option given already exist
     */
    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) {
                if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
                    throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut));
                }
            }
        }

        $this->options[$option->getName()] = $option;
        if ($option->getShortcut()) {
            foreach (explode('|', $option->getShortcut()) as $shortcut) {
                $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.
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function getOption(string $name): InputOption
    {
        if (!$this->hasOption($name)) {
            throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name));
        }

        return $this->options[$name];
    }

    /**
     * Returns true if an InputOption object exists by name.
     *
     * This method can't be used to check if the user included the option when
     * executing the command (use getOption() instead).
     */
    public function hasOption(string $name): bool
    {
        return isset($this->options[$name]);
    }

    /**
     * Gets the array of InputOption objects.
     *
     * @return InputOption[]
     */
    public function getOptions(): array
    {
        return $this->options;
    }

    /**
     * Returns true if an InputOption object exists by shortcut.
     */
    public function hasShortcut(string $name): bool
    {
        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.
     */
    public function getOptionForShortcut(string $shortcut): InputOption
    {
        return $this->getOption($this->shortcutToName($shortcut));
    }

    /**
     * @return array<string|bool|int|float|array|null>
     */
    public function getOptionDefaults(): array
    {
        $values = [];
        foreach ($this->options as $option) {
            $values[$option->getName()] = $option->getDefault();
        }

        return $values;
    }

    /**
     * Returns the InputOption name given a shortcut.
     *
     * @throws InvalidArgumentException When option given does not exist
     *
     * @internal
     */
    public function shortcutToName(string $shortcut): string
    {
        if (!isset($this->shortcuts[$shortcut])) {
            throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }

        return $this->shortcuts[$shortcut];
    }

    /**
     * Returns the InputOption name given a negation.
     *
     * @throws InvalidArgumentException When option given does not exist
     *
     * @internal
     */
    public function negationToName(string $negation): string
    {
        if (!isset($this->negations[$negation])) {
            throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation));
        }

        return $this->negations[$negation];
    }

    /**
     * Gets the synopsis.
     */
    public function getSynopsis(bool $short = false): string
    {
        $elements = [];

        if ($short && $this->getOptions()) {
            $elements[] = '[options]';
        } elseif (!$short) {
            foreach ($this->getOptions() as $option) {
                $value = '';
                if ($option->acceptValue()) {
                    $value = \sprintf(
                        ' %s%s%s',
                        $option->isValueOptional() ? '[' : '',
                        strtoupper($option->getName()),
                        $option->isValueOptional() ? ']' : ''
                    );
                }

                $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : '';
                $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : '';
                $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation);
            }
        }

        if (\count($elements) && $this->getArguments()) {
            $elements[] = '[--]';
        }

        $tail = '';
        foreach ($this->getArguments() as $argument) {
            $element = '<'.$argument->getName().'>';
            if ($argument->isArray()) {
                $element .= '...';
            }

            if (!$argument->isRequired()) {
                $element = '['.$element;
                $tail .= ']';
            }

            $elements[] = $element;
        }

        return implode(' ', $elements).$tail;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;

/**
 * InputInterface is the interface implemented by all input classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @method string __toString() Returns a stringified representation of the args passed to the command.
 *                             InputArguments MUST be escaped as well as the InputOption values passed to the command.
 */
interface InputInterface
{
    /**
     * Returns the first argument from the raw parameters (not parsed).
     */
    public function getFirstArgument(): ?string;

    /**
     * Returns true if the raw parameters (not parsed) contain a value.
     *
     * This method is to be used to introspect the input parameters
     * before they have been validated. It must be used carefully.
     * Does not necessarily return the correct result for short options
     * when multiple flags are combined in the same option.
     *
     * @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
     */
    public function hasParameterOption(string|array $values, bool $onlyParams = false): bool;

    /**
     * Returns the value of a raw option (not parsed).
     *
     * This method is to be used to introspect the input parameters
     * before they have been validated. It must be used carefully.
     * Does not necessarily return the correct result for short options
     * when multiple flags are combined in the same option.
     *
     * @param string|array                     $values     The value(s) to look for in the raw parameters (can be an array)
     * @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
     */
    public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false);

    /**
     * Binds the current Input instance with the given arguments and options.
     *
     * @return void
     *
     * @throws RuntimeException
     */
    public function bind(InputDefinition $definition);

    /**
     * Validates the input.
     *
     * @return void
     *
     * @throws RuntimeException When not enough arguments are given
     */
    public function validate();

    /**
     * Returns all the given arguments merged with the default values.
     *
     * @return array<string|bool|int|float|array|null>
     */
    public function getArguments(): array;

    /**
     * Returns the argument value for a given argument name.
     *
     * @return mixed
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    public function getArgument(string $name);

    /**
     * Sets an argument value by name.
     *
     * @return void
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    public function setArgument(string $name, mixed $value);

    /**
     * Returns true if an InputArgument object exists by name or position.
     */
    public function hasArgument(string $name): bool;

    /**
     * Returns all the given options merged with the default values.
     *
     * @return array<string|bool|int|float|array|null>
     */
    public function getOptions(): array;

    /**
     * Returns the option value for a given option name.
     *
     * @return mixed
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function getOption(string $name);

    /**
     * Sets an option value by name.
     *
     * @return void
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function setOption(string $name, mixed $value);

    /**
     * Returns true if an InputOption object exists by name.
     */
    public function hasOption(string $name): bool;

    /**
     * Is this input means interactive?
     */
    public function isInteractive(): bool;

    /**
     * Sets the input interactivity.
     *
     * @return void
     */
    public function setInteractive(bool $interactive);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

/**
 * Represents a command line option.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputOption
{
    /**
     * Do not accept input for the option (e.g. --yell). This is the default behavior of options.
     */
    public const VALUE_NONE = 1;

    /**
     * A value must be passed when the option is used (e.g. --iterations=5 or -i5).
     */
    public const VALUE_REQUIRED = 2;

    /**
     * The option may or may not have a value (e.g. --yell or --yell=loud).
     */
    public const VALUE_OPTIONAL = 4;

    /**
     * The option accepts multiple values (e.g. --dir=/foo --dir=/bar).
     */
    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 string $name;
    private string|array|null $shortcut;
    private int $mode;
    private string|int|bool|array|float|null $default;
    private array|\Closure $suggestedValues;
    private string $description;

    /**
     * @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)
     * @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
     *
     * @throws InvalidArgumentException If option mode is invalid or incompatible
     */
    public function __construct(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, array|\Closure $suggestedValues = [])
    {
        if (str_starts_with($name, '--')) {
            $name = substr($name, 2);
        }

        if (empty($name)) {
            throw new InvalidArgumentException('An option name cannot be empty.');
        }

        if ('' === $shortcut || [] === $shortcut || false === $shortcut) {
            $shortcut = null;
        }

        if (null !== $shortcut) {
            if (\is_array($shortcut)) {
                $shortcut = implode('|', $shortcut);
            }
            $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
            $shortcuts = array_filter($shortcuts, 'strlen');
            $shortcut = implode('|', $shortcuts);

            if ('' === $shortcut) {
                throw new InvalidArgumentException('An option shortcut cannot be empty.');
            }
        }

        if (null === $mode) {
            $mode = self::VALUE_NONE;
        } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) {
            throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode));
        }

        $this->name = $name;
        $this->shortcut = $shortcut;
        $this->mode = $mode;
        $this->description = $description;
        $this->suggestedValues = $suggestedValues;

        if ($suggestedValues && !$this->acceptValue()) {
            throw new LogicException('Cannot set suggested values if the option does not accept a value.');
        }
        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);
    }

    /**
     * Returns the option shortcut.
     */
    public function getShortcut(): ?string
    {
        return $this->shortcut;
    }

    /**
     * Returns the option name.
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * Returns true if the option accepts a value.
     *
     * @return bool true if value mode is not self::VALUE_NONE, false otherwise
     */
    public function acceptValue(): bool
    {
        return $this->isValueRequired() || $this->isValueOptional();
    }

    /**
     * Returns true if the option requires a value.
     *
     * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise
     */
    public function isValueRequired(): bool
    {
        return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
    }

    /**
     * Returns true if the option takes an optional value.
     *
     * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise
     */
    public function isValueOptional(): bool
    {
        return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
    }

    /**
     * Returns true if the option can take multiple values.
     *
     * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise
     */
    public function isArray(): bool
    {
        return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
    }

    public function isNegatable(): bool
    {
        return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);
    }

    /**
     * @return void
     */
    public function setDefault(string|bool|int|float|array|null $default = null)
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
            throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
        }

        if ($this->isArray()) {
            if (null === $default) {
                $default = [];
            } elseif (!\is_array($default)) {
                throw new LogicException('A default value for an array option must be an array.');
            }
        }

        $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false;
    }

    /**
     * Returns the default value.
     */
    public function getDefault(): string|bool|int|float|array|null
    {
        return $this->default;
    }

    /**
     * Returns the description text.
     */
    public function getDescription(): string
    {
        return $this->description;
    }

    public function hasCompletion(): bool
    {
        return [] !== $this->suggestedValues;
    }

    /**
     * Adds suggestions to $suggestions for the current completion input.
     *
     * @see Command::complete()
     */
    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        $values = $this->suggestedValues;
        if ($values instanceof \Closure && !\is_array($values = $values($input))) {
            throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values)));
        }
        if ($values) {
            $suggestions->suggestValues($values);
        }
    }

    /**
     * Checks whether the given option equals this one.
     */
    public function equals(self $option): bool
    {
        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()
        ;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

/**
 * StreamableInputInterface is the interface implemented by all input classes
 * that have an input stream.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
interface StreamableInputInterface extends InputInterface
{
    /**
     * Sets the input stream to read from when interacting with the user.
     *
     * This is mainly useful for testing purpose.
     *
     * @param resource $stream The input stream
     *
     * @return void
     */
    public function setStream($stream);

    /**
     * Returns the input stream.
     *
     * @return resource|null
     */
    public function getStream();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * StringInput represents an input provided as a string.
 *
 * Usage:
 *
 *     $input = new StringInput('foo --bar="foobar"');
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class StringInput extends ArgvInput
{
    /**
     * @deprecated since Symfony 6.1
     */
    public const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
    public const REGEX_UNQUOTED_STRING = '([^\s\\\\]+?)';
    public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';

    /**
     * @param string $input A string representing the parameters from the CLI
     */
    public function __construct(string $input)
    {
        parent::__construct([]);

        $this->setTokens($this->tokenize($input));
    }

    /**
     * Tokenizes a string.
     *
     * @throws InvalidArgumentException When unable to parse input (should never happen)
     */
    private function tokenize(string $input): array
    {
        $tokens = [];
        $length = \strlen($input);
        $cursor = 0;
        $token = null;
        while ($cursor < $length) {
            if ('\\' === $input[$cursor]) {
                $token .= $input[++$cursor] ?? '';
                ++$cursor;
                continue;
            }

            if (preg_match('/\s+/A', $input, $match, 0, $cursor)) {
                if (null !== $token) {
                    $tokens[] = $token;
                    $token = null;
                }
            } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) {
                $token .= $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1)));
            } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
                $token .= stripcslashes(substr($match[0], 1, -1));
            } elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
                $token .= $match[1];
            } else {
                // should never happen
                throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10)));
            }

            $cursor += \strlen($match[0]);
        }

        if (null !== $token) {
            $tokens[] = $token;
        }

        return $tokens;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Logger;

use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * PSR-3 compliant console logger.
 *
 * @author Kévin Dunglas <dunglas@gmail.com>
 *
 * @see https://www.php-fig.org/psr/psr-3/
 */
class ConsoleLogger extends AbstractLogger
{
    public const INFO = 'info';
    public const ERROR = 'error';

    private OutputInterface $output;
    private array $verbosityLevelMap = [
        LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
        LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
        LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
        LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
        LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
        LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
        LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
        LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
    ];
    private array $formatLevelMap = [
        LogLevel::EMERGENCY => self::ERROR,
        LogLevel::ALERT => self::ERROR,
        LogLevel::CRITICAL => self::ERROR,
        LogLevel::ERROR => self::ERROR,
        LogLevel::WARNING => self::INFO,
        LogLevel::NOTICE => self::INFO,
        LogLevel::INFO => self::INFO,
        LogLevel::DEBUG => self::INFO,
    ];
    private bool $errored = false;

    public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
    {
        $this->output = $output;
        $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
        $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
    }

    public function log($level, $message, array $context = []): void
    {
        if (!isset($this->verbosityLevelMap[$level])) {
            throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level));
        }

        $output = $this->output;

        // Write to the error output if necessary and available
        if (self::ERROR === $this->formatLevelMap[$level]) {
            if ($this->output instanceof ConsoleOutputInterface) {
                $output = $output->getErrorOutput();
            }
            $this->errored = true;
        }

        // the if condition check isn't necessary -- it's the same one that $output will do internally anyway.
        // We only do it for efficiency here as the message formatting is relatively expensive.
        if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
            $output->writeln(\sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
        }
    }

    /**
     * Returns true when any messages have been logged at error levels.
     */
    public function hasErrored(): bool
    {
        return $this->errored;
    }

    /**
     * Interpolates context values into the message placeholders.
     *
     * @author PHP Framework Interoperability Group
     */
    private function interpolate(string $message, array $context): string
    {
        if (!str_contains($message, '{')) {
            return $message;
        }

        $replacements = [];
        foreach ($context as $key => $val) {
            if (null === $val || \is_scalar($val) || $val instanceof \Stringable) {
                $replacements["{{$key}}"] = $val;
            } elseif ($val instanceof \DateTimeInterface) {
                $replacements["{{$key}}"] = $val->format(\DateTimeInterface::RFC3339);
            } elseif (\is_object($val)) {
                $replacements["{{$key}}"] = '[object '.$val::class.']';
            } else {
                $replacements["{{$key}}"] = '['.\gettype($val).']';
            }
        }

        return strtr($message, $replacements);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Messenger;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunCommandContext
{
    public function __construct(
        public readonly RunCommandMessage $message,
        public readonly int $exitCode,
        public readonly string $output,
    ) {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Messenger;

use Symfony\Component\Console\Exception\RunCommandFailedException;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class RunCommandMessage implements \Stringable
{
    /**
     * @param bool $throwOnFailure  If the command has a non-zero exit code, throw {@see RunCommandFailedException}
     * @param bool $catchExceptions @see Application::setCatchExceptions()
     */
    public function __construct(
        public readonly string $input,
        public readonly bool $throwOnFailure = true,
        public readonly bool $catchExceptions = false,
    ) {
    }

    public function __toString(): string
    {
        return $this->input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Messenger;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\RunCommandFailedException;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface;
use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunCommandMessageHandler
{
    public function __construct(private readonly Application $application)
    {
    }

    public function __invoke(RunCommandMessage $message): RunCommandContext
    {
        $input = new StringInput($message->input);
        $output = new BufferedOutput();

        $this->application->setCatchExceptions($message->catchExceptions);

        try {
            $exitCode = $this->application->run($input, $output);
        } catch (UnrecoverableExceptionInterface|RecoverableExceptionInterface $e) {
            throw $e;
        } catch (\Throwable $e) {
            throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch()));
        }

        if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) {
            throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch()));
        }

        return new RunCommandContext($message, $exitCode, $output->fetch());
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Julien Boudry <julien@condorcet.vote>
 */
enum AnsiColorMode
{
    /*
     * Classical 4-bit Ansi colors, including 8 classical colors and 8 bright color. Output syntax is "ESC[${foreGroundColorcode};${backGroundColorcode}m"
     * Must be compatible with all terminals and it's the minimal version supported.
     */
    case Ansi4;

    /*
     * 8-bit Ansi colors (240 different colors + 16 duplicate color codes, ensuring backward compatibility).
     * Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m"
     * Should be compatible with most terminals.
     */
    case Ansi8;

    /*
     * 24-bit Ansi colors (RGB).
     * Output syntax is: "ESC[38;2;${foreGroundColorcodeRed};${foreGroundColorcodeGreen};${foreGroundColorcodeBlue};48;2;${backGroundColorcodeRed};${backGroundColorcodeGreen};${backGroundColorcodeBlue}m"
     * May be compatible with many modern terminals.
     */
    case Ansi24;

    /**
     * Converts an RGB hexadecimal color to the corresponding Ansi code.
     */
    public function convertFromHexToAnsiColorCode(string $hexColor): string
    {
        $hexColor = str_replace('#', '', $hexColor);

        if (3 === \strlen($hexColor)) {
            $hexColor = $hexColor[0].$hexColor[0].$hexColor[1].$hexColor[1].$hexColor[2].$hexColor[2];
        }

        if (6 !== \strlen($hexColor)) {
            throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor));
        }

        $color = hexdec($hexColor);

        $r = ($color >> 16) & 255;
        $g = ($color >> 8) & 255;
        $b = $color & 255;

        return match ($this) {
            self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b),
            self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)),
            self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b),
        };
    }

    private function convertFromRGB(int $r, int $g, int $b): int
    {
        return match ($this) {
            self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b),
            self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b),
            default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."),
        };
    }

    private function degradeHexColorToAnsi4(int $r, int $g, int $b): int
    {
        return round($b / 255) << 2 | (round($g / 255) << 1) | round($r / 255);
    }

    /**
     * Inspired from https://github.com/ajalt/colormath/blob/e464e0da1b014976736cf97250063248fc77b8e7/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/Ansi256.kt code (MIT license).
     */
    private function degradeHexColorToAnsi8(int $r, int $g, int $b): int
    {
        if ($r === $g && $g === $b) {
            if ($r < 8) {
                return 16;
            }

            if ($r > 248) {
                return 231;
            }

            return (int) round(($r - 8) / 247 * 24) + 232;
        } else {
            return 16 +
                    (36 * (int) round($r / 255 * 5)) +
                    (6 * (int) round($g / 255 * 5)) +
                    (int) round($b / 255 * 5);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class BufferedOutput extends Output
{
    private string $buffer = '';

    /**
     * Empties buffer and returns its content.
     */
    public function fetch(): string
    {
        $content = $this->buffer;
        $this->buffer = '';

        return $content;
    }

    /**
     * @return void
     */
    protected function doWrite(string $message, bool $newline)
    {
        $this->buffer .= $message;

        if ($newline) {
            $this->buffer .= \PHP_EOL;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR.
 *
 * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR.
 *
 *     $output = new ConsoleOutput();
 *
 * This is equivalent to:
 *
 *     $output = new StreamOutput(fopen('php://stdout', 'w'));
 *     $stdErr = new StreamOutput(fopen('php://stderr', 'w'));
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{
    private OutputInterface $stderr;
    private array $consoleSectionOutputs = [];

    /**
     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)
     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
     */
    public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
    {
        parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);

        if (null === $formatter) {
            // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter.
            $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);

            return;
        }

        $actualDecorated = $this->isDecorated();
        $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());

        if (null === $decorated) {
            $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
        }
    }

    /**
     * Creates a new output section.
     */
    public function section(): ConsoleSectionOutput
    {
        return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
    }

    /**
     * @return void
     */
    public function setDecorated(bool $decorated)
    {
        parent::setDecorated($decorated);
        $this->stderr->setDecorated($decorated);
    }

    /**
     * @return void
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        parent::setFormatter($formatter);
        $this->stderr->setFormatter($formatter);
    }

    /**
     * @return void
     */
    public function setVerbosity(int $level)
    {
        parent::setVerbosity($level);
        $this->stderr->setVerbosity($level);
    }

    public function getErrorOutput(): OutputInterface
    {
        return $this->stderr;
    }

    /**
     * @return void
     */
    public function setErrorOutput(OutputInterface $error)
    {
        $this->stderr = $error;
    }

    /**
     * Returns true if current environment supports writing console output to
     * STDOUT.
     */
    protected function hasStdoutSupport(): bool
    {
        return false === $this->isRunningOS400();
    }

    /**
     * Returns true if current environment supports writing console output to
     * STDERR.
     */
    protected function hasStderrSupport(): bool
    {
        return false === $this->isRunningOS400();
    }

    /**
     * Checks if current executing environment is IBM iSeries (OS400), which
     * doesn't properly convert character-encodings between ASCII to EBCDIC.
     */
    private function isRunningOS400(): bool
    {
        $checks = [
            \function_exists('php_uname') ? php_uname('s') : '',
            getenv('OSTYPE'),
            \PHP_OS,
        ];

        return false !== stripos(implode(';', $checks), 'OS400');
    }

    /**
     * @return resource
     */
    private function openOutputStream()
    {
        if (!$this->hasStdoutSupport()) {
            return fopen('php://output', 'w');
        }

        // Use STDOUT when possible to prevent from opening too many file descriptors
        return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));
    }

    /**
     * @return resource
     */
    private function openErrorStream()
    {
        if (!$this->hasStderrSupport()) {
            return fopen('php://output', 'w');
        }

        // Use STDERR when possible to prevent from opening too many file descriptors
        return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

/**
 * ConsoleOutputInterface is the interface implemented by ConsoleOutput class.
 * This adds information about stderr and section output stream.
 *
 * @author Dariusz Górecki <darek.krk@gmail.com>
 */
interface ConsoleOutputInterface extends OutputInterface
{
    /**
     * Gets the OutputInterface for errors.
     */
    public function getErrorOutput(): OutputInterface;

    /**
     * @return void
     */
    public function setErrorOutput(OutputInterface $error);

    public function section(): ConsoleSectionOutput;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Terminal;

/**
 * @author Pierre du Plessis <pdples@gmail.com>
 * @author Gabriel Ostrolucký <gabriel.ostrolucky@gmail.com>
 */
class ConsoleSectionOutput extends StreamOutput
{
    private array $content = [];
    private int $lines = 0;
    private array $sections;
    private Terminal $terminal;
    private int $maxHeight = 0;

    /**
     * @param resource               $stream
     * @param ConsoleSectionOutput[] $sections
     */
    public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter)
    {
        parent::__construct($stream, $verbosity, $decorated, $formatter);
        array_unshift($sections, $this);
        $this->sections = &$sections;
        $this->terminal = new Terminal();
    }

    /**
     * Defines a maximum number of lines for this section.
     *
     * When more lines are added, the section will automatically scroll to the
     * end (i.e. remove the first lines to comply with the max height).
     */
    public function setMaxHeight(int $maxHeight): void
    {
        // when changing max height, clear output of current section and redraw again with the new height
        $previousMaxHeight = $this->maxHeight;
        $this->maxHeight = $maxHeight;
        $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines);

        parent::doWrite($this->getVisibleContent(), false);
        parent::doWrite($existingContent, false);
    }

    /**
     * Clears previous output for this section.
     *
     * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared
     *
     * @return void
     */
    public function clear(?int $lines = null)
    {
        if (empty($this->content) || !$this->isDecorated()) {
            return;
        }

        if ($lines) {
            array_splice($this->content, -$lines);
        } else {
            $lines = $this->lines;
            $this->content = [];
        }

        $this->lines -= $lines;

        parent::doWrite($this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $lines) : $lines), false);
    }

    /**
     * Overwrites the previous output with a new message.
     *
     * @return void
     */
    public function overwrite(string|iterable $message)
    {
        $this->clear();
        $this->writeln($message);
    }

    public function getContent(): string
    {
        return implode('', $this->content);
    }

    public function getVisibleContent(): string
    {
        if (0 === $this->maxHeight) {
            return $this->getContent();
        }

        return implode('', \array_slice($this->content, -$this->maxHeight));
    }

    /**
     * @internal
     */
    public function addContent(string $input, bool $newline = true): int
    {
        $width = $this->terminal->getWidth();
        $lines = explode(\PHP_EOL, $input);
        $linesAdded = 0;
        $count = \count($lines) - 1;
        foreach ($lines as $i => $lineContent) {
            // re-add the line break (that has been removed in the above `explode()` for
            // - every line that is not the last line
            // - if $newline is required, also add it to the last line
            if ($i < $count || $newline) {
                $lineContent .= \PHP_EOL;
            }

            // skip line if there is no text (or newline for that matter)
            if ('' === $lineContent) {
                continue;
            }

            // For the first line, check if the previous line (last entry of `$this->content`)
            // needs to be continued (i.e. does not end with a line break).
            if (0 === $i
                && (false !== $lastLine = end($this->content))
                && !str_ends_with($lastLine, \PHP_EOL)
            ) {
                // deduct the line count of the previous line
                $this->lines -= (int) ceil($this->getDisplayLength($lastLine) / $width) ?: 1;
                // concatenate previous and new line
                $lineContent = $lastLine.$lineContent;
                // replace last entry of `$this->content` with the new expanded line
                array_splice($this->content, -1, 1, $lineContent);
            } else {
                // otherwise just add the new content
                $this->content[] = $lineContent;
            }

            $linesAdded += (int) ceil($this->getDisplayLength($lineContent) / $width) ?: 1;
        }

        $this->lines += $linesAdded;

        return $linesAdded;
    }

    /**
     * @internal
     */
    public function addNewLineOfInputSubmit(): void
    {
        $this->content[] = \PHP_EOL;
        ++$this->lines;
    }

    /**
     * @return void
     */
    protected function doWrite(string $message, bool $newline)
    {
        // Simulate newline behavior for consistent output formatting, avoiding extra logic
        if (!$newline && str_ends_with($message, \PHP_EOL)) {
            $message = substr($message, 0, -\strlen(\PHP_EOL));
            $newline = true;
        }

        if (!$this->isDecorated()) {
            parent::doWrite($message, $newline);

            return;
        }

        // Check if the previous line (last entry of `$this->content`) needs to be continued
        // (i.e. does not end with a line break). In which case, it needs to be erased first.
        $linesToClear = $deleteLastLine = ($lastLine = end($this->content) ?: '') && !str_ends_with($lastLine, \PHP_EOL) ? 1 : 0;

        $linesAdded = $this->addContent($message, $newline);

        if ($lineOverflow = $this->maxHeight > 0 && $this->lines > $this->maxHeight) {
            // on overflow, clear the whole section and redraw again (to remove the first lines)
            $linesToClear = $this->maxHeight;
        }

        $erasedContent = $this->popStreamContentUntilCurrentSection($linesToClear);

        if ($lineOverflow) {
            // redraw existing lines of the section
            $previousLinesOfSection = \array_slice($this->content, $this->lines - $this->maxHeight, $this->maxHeight - $linesAdded);
            parent::doWrite(implode('', $previousLinesOfSection), false);
        }

        // if the last line was removed, re-print its content together with the new content.
        // otherwise, just print the new content.
        parent::doWrite($deleteLastLine ? $lastLine.$message : $message, true);
        parent::doWrite($erasedContent, false);
    }

    /**
     * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits
     * current section. Then it erases content it crawled through. Optionally, it erases part of current section too.
     */
    private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string
    {
        $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;
        $erasedContent = [];

        foreach ($this->sections as $section) {
            if ($section === $this) {
                break;
            }

            $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines;
            if ('' !== $sectionContent = $section->getVisibleContent()) {
                if (!str_ends_with($sectionContent, \PHP_EOL)) {
                    $sectionContent .= \PHP_EOL;
                }
                $erasedContent[] = $sectionContent;
            }
        }

        if ($numberOfLinesToClear > 0) {
            // move cursor up n lines
            parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false);
            // erase to end of screen
            parent::doWrite("\x1b[0J", false);
        }

        return implode('', array_reverse($erasedContent));
    }

    private function getDisplayLength(string $text): int
    {
        return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace("\t", '        ', $text)));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\NullOutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * NullOutput suppresses all output.
 *
 *     $output = new NullOutput();
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Tobias Schultze <http://tobion.de>
 */
class NullOutput implements OutputInterface
{
    private NullOutputFormatter $formatter;

    /**
     * @return void
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        // do nothing
    }

    public function getFormatter(): OutputFormatterInterface
    {
        // to comply with the interface we must return a OutputFormatterInterface
        return $this->formatter ??= new NullOutputFormatter();
    }

    /**
     * @return void
     */
    public function setDecorated(bool $decorated)
    {
        // do nothing
    }

    public function isDecorated(): bool
    {
        return false;
    }

    /**
     * @return void
     */
    public function setVerbosity(int $level)
    {
        // do nothing
    }

    public function getVerbosity(): int
    {
        return self::VERBOSITY_QUIET;
    }

    public function isQuiet(): bool
    {
        return true;
    }

    public function isVerbose(): bool
    {
        return false;
    }

    public function isVeryVerbose(): bool
    {
        return false;
    }

    public function isDebug(): bool
    {
        return false;
    }

    /**
     * @return void
     */
    public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL)
    {
        // do nothing
    }

    /**
     * @return void
     */
    public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
    {
        // do nothing
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * Base class for output classes.
 *
 * There are five levels of verbosity:
 *
 *  * normal: no option passed (normal output)
 *  * verbose: -v (more output)
 *  * very verbose: -vv (highly extended output)
 *  * debug: -vvv (all debug output)
 *  * quiet: -q (no output)
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Output implements OutputInterface
{
    private int $verbosity;
    private OutputFormatterInterface $formatter;

    /**
     * @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 = $verbosity ?? self::VERBOSITY_NORMAL;
        $this->formatter = $formatter ?? new OutputFormatter();
        $this->formatter->setDecorated($decorated);
    }

    /**
     * @return void
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        $this->formatter = $formatter;
    }

    public function getFormatter(): OutputFormatterInterface
    {
        return $this->formatter;
    }

    /**
     * @return void
     */
    public function setDecorated(bool $decorated)
    {
        $this->formatter->setDecorated($decorated);
    }

    public function isDecorated(): bool
    {
        return $this->formatter->isDecorated();
    }

    /**
     * @return void
     */
    public function setVerbosity(int $level)
    {
        $this->verbosity = $level;
    }

    public function getVerbosity(): int
    {
        return $this->verbosity;
    }

    public function isQuiet(): bool
    {
        return self::VERBOSITY_QUIET === $this->verbosity;
    }

    public function isVerbose(): bool
    {
        return self::VERBOSITY_VERBOSE <= $this->verbosity;
    }

    public function isVeryVerbose(): bool
    {
        return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
    }

    public function isDebug(): bool
    {
        return self::VERBOSITY_DEBUG <= $this->verbosity;
    }

    /**
     * @return void
     */
    public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL)
    {
        $this->write($messages, true, $options);
    }

    /**
     * @return void
     */
    public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
    {
        if (!is_iterable($messages)) {
            $messages = [$messages];
        }

        $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
        $type = $types & $options ?: self::OUTPUT_NORMAL;

        $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
        $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;

        if ($verbosity > $this->getVerbosity()) {
            return;
        }

        foreach ($messages as $message) {
            switch ($type) {
                case OutputInterface::OUTPUT_NORMAL:
                    $message = $this->formatter->format($message);
                    break;
                case OutputInterface::OUTPUT_RAW:
                    break;
                case OutputInterface::OUTPUT_PLAIN:
                    $message = strip_tags($this->formatter->format($message));
                    break;
            }

            $this->doWrite($message ?? '', $newline);
        }
    }

    /**
     * Writes a message to the output.
     *
     * @return void
     */
    abstract protected function doWrite(string $message, bool $newline);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * OutputInterface is the interface implemented by all Output classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface OutputInterface
{
    public const VERBOSITY_QUIET = 16;
    public const VERBOSITY_NORMAL = 32;
    public const VERBOSITY_VERBOSE = 64;
    public const VERBOSITY_VERY_VERBOSE = 128;
    public const VERBOSITY_DEBUG = 256;

    public const OUTPUT_NORMAL = 1;
    public const OUTPUT_RAW = 2;
    public const OUTPUT_PLAIN = 4;

    /**
     * Writes a message to the output.
     *
     * @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
     *
     * @return void
     */
    public function write(string|iterable $messages, bool $newline = false, int $options = 0);

    /**
     * Writes a message to the output and adds a newline at the end.
     *
     * @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
     *
     * @return void
     */
    public function writeln(string|iterable $messages, int $options = 0);

    /**
     * Sets the verbosity of the output.
     *
     * @param self::VERBOSITY_* $level
     *
     * @return void
     */
    public function setVerbosity(int $level);

    /**
     * Gets the current verbosity of the output.
     *
     * @return self::VERBOSITY_*
     */
    public function getVerbosity(): int;

    /**
     * Returns whether verbosity is quiet (-q).
     */
    public function isQuiet(): bool;

    /**
     * Returns whether verbosity is verbose (-v).
     */
    public function isVerbose(): bool;

    /**
     * Returns whether verbosity is very verbose (-vv).
     */
    public function isVeryVerbose(): bool;

    /**
     * Returns whether verbosity is debug (-vvv).
     */
    public function isDebug(): bool;

    /**
     * Sets the decorated flag.
     *
     * @return void
     */
    public function setDecorated(bool $decorated);

    /**
     * Gets the decorated flag.
     */
    public function isDecorated(): bool;

    /**
     * @return void
     */
    public function setFormatter(OutputFormatterInterface $formatter);

    /**
     * Returns current output formatter instance.
     */
    public function getFormatter(): OutputFormatterInterface;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * StreamOutput writes the output to a given stream.
 *
 * Usage:
 *
 *     $output = new StreamOutput(fopen('php://stdout', 'w'));
 *
 * As `StreamOutput` can use any stream, you can also use a file:
 *
 *     $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class StreamOutput extends Output
{
    /** @var resource */
    private $stream;

    /**
     * @param resource                      $stream    A stream resource
     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)
     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
     *
     * @throws InvalidArgumentException When first argument is not a real stream
     */
    public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
    {
        if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
            throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
        }

        $this->stream = $stream;

        $decorated ??= $this->hasColorSupport();

        parent::__construct($verbosity, $decorated, $formatter);
    }

    /**
     * Gets the stream attached to this StreamOutput instance.
     *
     * @return resource
     */
    public function getStream()
    {
        return $this->stream;
    }

    /**
     * @return void
     */
    protected function doWrite(string $message, bool $newline)
    {
        if ($newline) {
            $message .= \PHP_EOL;
        }

        @fwrite($this->stream, $message);

        fflush($this->stream);
    }

    /**
     * Returns true if the stream supports colorization.
     *
     * Colorization is disabled if not supported by the stream:
     *
     * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
     * terminals via named pipes, so we can only check the environment.
     *
     * Reference: Composer\XdebugHandler\Process::supportsColor
     * https://github.com/composer/xdebug-handler
     *
     * @return bool true if the stream supports colorization, false otherwise
     */
    protected function hasColorSupport(): bool
    {
        // Follow https://no-color.org/
        if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) {
            return false;
        }

        // Detect msysgit/mingw and assume this is a tty because detection
        // does not work correctly, see https://github.com/composer/composer/issues/9690
        if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) {
            return false;
        }

        if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) {
            return true;
        }

        if ('Hyper' === getenv('TERM_PROGRAM')
            || false !== getenv('COLORTERM')
            || false !== getenv('ANSICON')
            || 'ON' === getenv('ConEmuANSI')
        ) {
            return true;
        }

        if ('dumb' === $term = (string) getenv('TERM')) {
            return false;
        }

        // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157
        return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;

/**
 * A BufferedOutput that keeps only the last N chars.
 *
 * @author Jérémy Derussé <jeremy@derusse.com>
 */
class TrimmedBufferOutput extends Output
{
    private int $maxLength;
    private string $buffer = '';

    public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)
    {
        if ($maxLength <= 0) {
            throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
        }

        parent::__construct($verbosity, $decorated, $formatter);
        $this->maxLength = $maxLength;
    }

    /**
     * Empties buffer and returns its content.
     */
    public function fetch(): string
    {
        $content = $this->buffer;
        $this->buffer = '';

        return $content;
    }

    /**
     * @return void
     */
    protected function doWrite(string $message, bool $newline)
    {
        $this->buffer .= $message;

        if ($newline) {
            $this->buffer .= \PHP_EOL;
        }

        $this->buffer = substr($this->buffer, 0 - $this->maxLength);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Question;

use Symfony\Component\Console\Exception\InvalidArgumentException;

/**
 * Represents a choice question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ChoiceQuestion extends Question
{
    private array $choices;
    private bool $multiselect = false;
    private string $prompt = ' > ';
    private string $errorMessage = 'Value "%s" is invalid';

    /**
     * @param string                       $question The question to ask to the user
     * @param array<string|bool|int|float> $choices  The list of available choices
     * @param string|bool|int|float|null   $default  The default answer to return
     */
    public function __construct(string $question, array $choices, string|bool|int|float|null $default = null)
    {
        if (!$choices) {
            throw new \LogicException('Choice question must have at least 1 choice available.');
        }

        parent::__construct($question, $default);

        $this->choices = $choices;
        $this->setValidator($this->getDefaultValidator());
        $this->setAutocompleterValues($choices);
    }

    /**
     * @return array<string|bool|int|float>
     */
    public function getChoices(): array
    {
        return $this->choices;
    }

    /**
     * Sets multiselect option.
     *
     * When multiselect is set to true, multiple choices can be answered.
     *
     * @return $this
     */
    public function setMultiselect(bool $multiselect): static
    {
        $this->multiselect = $multiselect;
        $this->setValidator($this->getDefaultValidator());

        return $this;
    }

    /**
     * Returns whether the choices are multiselect.
     */
    public function isMultiselect(): bool
    {
        return $this->multiselect;
    }

    /**
     * Gets the prompt for choices.
     */
    public function getPrompt(): string
    {
        return $this->prompt;
    }

    /**
     * Sets the prompt for choices.
     *
     * @return $this
     */
    public function setPrompt(string $prompt): static
    {
        $this->prompt = $prompt;

        return $this;
    }

    /**
     * Sets the error message for invalid values.
     *
     * The error message has a string placeholder (%s) for the invalid value.
     *
     * @return $this
     */
    public function setErrorMessage(string $errorMessage): static
    {
        $this->errorMessage = $errorMessage;
        $this->setValidator($this->getDefaultValidator());

        return $this;
    }

    private function getDefaultValidator(): callable
    {
        $choices = $this->choices;
        $errorMessage = $this->errorMessage;
        $multiselect = $this->multiselect;
        $isAssoc = $this->isAssoc($choices);

        return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
            if ($multiselect) {
                // Check for a separated comma values
                if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) {
                    throw new InvalidArgumentException(\sprintf($errorMessage, $selected));
                }

                $selectedChoices = explode(',', (string) $selected);
            } else {
                $selectedChoices = [$selected];
            }

            if ($this->isTrimmable()) {
                foreach ($selectedChoices as $k => $v) {
                    $selectedChoices[$k] = trim((string) $v);
                }
            }

            $multiselectChoices = [];
            foreach ($selectedChoices as $value) {
                $results = [];
                foreach ($choices as $key => $choice) {
                    if ($choice === $value) {
                        $results[] = $key;
                    }
                }

                if (\count($results) > 1) {
                    throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results)));
                }

                $result = array_search($value, $choices);

                if (!$isAssoc) {
                    if (false !== $result) {
                        $result = $choices[$result];
                    } elseif (isset($choices[$value])) {
                        $result = $choices[$value];
                    }
                } elseif (false === $result && isset($choices[$value])) {
                    $result = $value;
                }

                if (false === $result) {
                    throw new InvalidArgumentException(\sprintf($errorMessage, $value));
                }

                // For associative choices, consistently return the key as string:
                $multiselectChoices[] = $isAssoc ? (string) $result : $result;
            }

            if ($multiselect) {
                return $multiselectChoices;
            }

            return current($multiselectChoices);
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Question;

/**
 * Represents a yes/no question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ConfirmationQuestion extends Question
{
    private string $trueAnswerRegex;

    /**
     * @param string $question        The question to ask to the user
     * @param bool   $default         The default answer to return, true or false
     * @param string $trueAnswerRegex A regex to match the "yes" answer
     */
    public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i')
    {
        parent::__construct($question, $default);

        $this->trueAnswerRegex = $trueAnswerRegex;
        $this->setNormalizer($this->getDefaultNormalizer());
    }

    /**
     * Returns the default answer normalizer.
     */
    private function getDefaultNormalizer(): callable
    {
        $default = $this->getDefault();
        $regex = $this->trueAnswerRegex;

        return function ($answer) use ($default, $regex) {
            if (\is_bool($answer)) {
                return $answer;
            }

            $answerIsTrue = (bool) preg_match($regex, $answer);
            if (false === $default) {
                return $answer && $answerIsTrue;
            }

            return '' === $answer || $answerIsTrue;
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Question;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

/**
 * Represents a Question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Question
{
    private string $question;
    private ?int $attempts = null;
    private bool $hidden = false;
    private bool $hiddenFallback = true;
    private ?\Closure $autocompleterCallback = null;
    private ?\Closure $validator = null;
    private string|int|bool|float|null $default;
    private ?\Closure $normalizer = null;
    private bool $trimmable = true;
    private bool $multiline = false;

    /**
     * @param string                     $question The question to ask to the user
     * @param string|bool|int|float|null $default  The default answer to return if the user enters nothing
     */
    public function __construct(string $question, string|bool|int|float|null $default = null)
    {
        $this->question = $question;
        $this->default = $default;
    }

    /**
     * Returns the question.
     */
    public function getQuestion(): string
    {
        return $this->question;
    }

    /**
     * Returns the default answer.
     */
    public function getDefault(): string|bool|int|float|null
    {
        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): static
    {
        $this->multiline = $multiline;

        return $this;
    }

    /**
     * Returns whether the user response must be hidden.
     */
    public function isHidden(): bool
    {
        return $this->hidden;
    }

    /**
     * Sets whether the user response must be hidden or not.
     *
     * @return $this
     *
     * @throws LogicException In case the autocompleter is also used
     */
    public function setHidden(bool $hidden): static
    {
        if ($this->autocompleterCallback) {
            throw new LogicException('A hidden question cannot use the autocompleter.');
        }

        $this->hidden = $hidden;

        return $this;
    }

    /**
     * In case the response cannot be hidden, whether to fallback on non-hidden question or not.
     */
    public function isHiddenFallback(): bool
    {
        return $this->hiddenFallback;
    }

    /**
     * Sets whether to fallback on non-hidden question if the response cannot be hidden.
     *
     * @return $this
     */
    public function setHiddenFallback(bool $fallback): static
    {
        $this->hiddenFallback = $fallback;

        return $this;
    }

    /**
     * Gets values for the autocompleter.
     */
    public function getAutocompleterValues(): ?iterable
    {
        $callback = $this->getAutocompleterCallback();

        return $callback ? $callback('') : null;
    }

    /**
     * Sets values for the autocompleter.
     *
     * @return $this
     *
     * @throws LogicException
     */
    public function setAutocompleterValues(?iterable $values): static
    {
        if (\is_array($values)) {
            $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);

            $callback = static fn () => $values;
        } elseif ($values instanceof \Traversable) {
            $callback = static function () use ($values) {
                static $valueCache;

                return $valueCache ??= iterator_to_array($values, false);
            };
        } else {
            $callback = null;
        }

        return $this->setAutocompleterCallback($callback);
    }

    /**
     * Gets the callback function used for the autocompleter.
     */
    public function getAutocompleterCallback(): ?callable
    {
        return $this->autocompleterCallback;
    }

    /**
     * Sets the callback function used for the autocompleter.
     *
     * The callback is passed the user input as argument and should return an iterable of corresponding suggestions.
     *
     * @return $this
     */
    public function setAutocompleterCallback(?callable $callback = null): static
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        if ($this->hidden && null !== $callback) {
            throw new LogicException('A hidden question cannot use the autocompleter.');
        }

        $this->autocompleterCallback = null === $callback ? null : $callback(...);

        return $this;
    }

    /**
     * Sets a validator for the question.
     *
     * @return $this
     */
    public function setValidator(?callable $validator = null): static
    {
        if (1 > \func_num_args()) {
            trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
        }
        $this->validator = null === $validator ? null : $validator(...);

        return $this;
    }

    /**
     * Gets the validator for the question.
     */
    public function getValidator(): ?callable
    {
        return $this->validator;
    }

    /**
     * Sets the maximum number of attempts.
     *
     * Null means an unlimited number of attempts.
     *
     * @return $this
     *
     * @throws InvalidArgumentException in case the number of attempts is invalid
     */
    public function setMaxAttempts(?int $attempts): static
    {
        if (null !== $attempts && $attempts < 1) {
            throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
        }

        $this->attempts = $attempts;

        return $this;
    }

    /**
     * Gets the maximum number of attempts.
     *
     * Null means an unlimited number of attempts.
     */
    public function getMaxAttempts(): ?int
    {
        return $this->attempts;
    }

    /**
     * Sets a normalizer for the response.
     *
     * The normalizer can be a callable (a string), a closure or a class implementing __invoke.
     *
     * @return $this
     */
    public function setNormalizer(callable $normalizer): static
    {
        $this->normalizer = $normalizer(...);

        return $this;
    }

    /**
     * Gets the normalizer for the response.
     *
     * The normalizer can ba a callable (a string), a closure or a class implementing __invoke.
     */
    public function getNormalizer(): ?callable
    {
        return $this->normalizer;
    }

    /**
     * @return bool
     */
    protected function isAssoc(array $array)
    {
        return (bool) \count(array_filter(array_keys($array), 'is_string'));
    }

    public function isTrimmable(): bool
    {
        return $this->trimmable;
    }

    /**
     * @return $this
     */
    public function setTrimmable(bool $trimmable): static
    {
        $this->trimmable = $trimmable;

        return $this;
    }
}
MZ                @                                       	!L!This program cannot be run in DOS mode.
$       ,;B;B;B2מ:B2-B2ƞ9B2ў?Ba98B;CB2Ȟ:B2֞:B2Ӟ:BRich;B        PE  L MoO         	  
         8           @                      `     ?   @                           "  P    @                      P  p   !                             8!  @                                          .text   	      
                    `.rdata  	       
                 @  @.data      0                    @  .rsrc       @                    @  @.reloc     P      "              @  B                                                                                                                                                                                                                                                                                                                                                        j$@ x  j @ e EPV  @ EЃPV @ MX @ e EP5H @ L @ YY5\ @ EP5` @ D @ YYP @ MMT @ 3H  ; 0@ u  h@   l3@ $40@ 5h3@ 40@ h$0@ h(0@ h 0@  @ 00@ }j  Yjh"@   3ۉ]d   p]俀3@ SVW0 @ ;t;u3Fuh  4 @ 3F|3@ ;u
j\  Y;|3@ u,5|3@ h @ h @   YYtE      5<0@ |3@ ;uh @ h @ l  YY|3@    9]uSW8 @ 93@ th3@   Yt
SjS3@ $0@  @ 5$0@ 5(0@ 5 0@ 80@ 9,0@ u7P @ E	MPQ  YYËeE80@ 39,0@ uPh @ 9<0@ u @ E80@   øMZ  f9  @ t3M< @   @ 8PE  uH  t  uՃ   v39   xtv39   j,0@ p @ jl @ YY3@ 3@  @ t3@  @ p3@  @  x3@ V    =0@  uh@  @ Yg  =0@ u	j @ Y3{  U(  H1@ D1@ @1@ <1@ 581@ =41@ f`1@ fT1@ f01@ f,1@ f%(1@ f-$1@ X1@ E L1@ EP1@ E\1@ 0@   P1@ L0@ @0@ 	 D0@     0@ 0@  @ 0@ j?  Yj   @ h!@ $ @ =0@  uj  Yh	 ( @ P, @ ËUE 8csmu*xu$@= t=!t="t= @u  3] hH@   @ 3% @ jh("@ b  53@ 5 @ YEuu @ Ygj  Ye 53@ ։E53@ YYEEPEPu5l @ YPU  Eu֣3@ uփ3@ E	   E  j  YËUuNYH]ËV!@ !@ W;stЃ;r_^ËV"@ "@ W;stЃ;r_^% @ ̋UMMZ  f9t3]ËA<8PE  u3ҹ  f9H]̋UEH<ASVq3WDv}H;r	X;r
B(;r3_^[]̋UjhH"@ he@ d    PSVW 0@ 1E3PEd    eE    h  @ *tUE-  @ Ph  @ Pt;@$ЃEMd    Y_^[]ËE3=  ËeE3Md    Y_^[]% @ % @ he@ d5    D$l$l$+SVW 0@ 1E3PeuEEEEd    ËMd    Y__^[]QËUuuuuh@ h 0@    ]ËVh   h   3V   tVVVVV   ^3ËU 0@ e e SWN@  ;tt	У0@ `VEP< @ u3u @ 3 @ 3 @ 3EP @ E3E3;uO@u5 0@ ։50@ ^_[%t @ %x @ %| @ % @ % @ % @ % @ % @ % @ Pd5    D$+d$SVW( 0@ 3PEuEEd    ËMd    Y__^[]QËM3M%T @ T$BJ3J3l"@ s                                                                                                                                                                                                                                                     #  #  #  )  r)  b)  H)  4)  )  (  (  (  (  (  (  )      #  $  %  %  &  d&  &  $      ('  '  '  '  '  (  ((  6(  '  H(  Z(  t(  (  '  '   '  '  '  l'  ^'  R'  F'  >'  >(  0'  '  )          @         W@ @                     MoO       l   !    @0@ 0@ bad allocation      H                                                            0@ !@    RSDSьJ!LZ    c:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdb     e                            @ @                 :@             @ @ @ "   d"@                        "          #      $#          &  D   H#          (  h                       #  #  #  )  r)  b)  H)  4)  )  (  (  (  (  (  (  )      #  $  %  %  &  d&  &  $      ('  '  '  '  '  (  ((  6(  '  H(  Z(  t(  (  '  '   '  '  '  l'  ^'  R'  F'  >'  >(  0'  '  )      GetConsoleMode  SetConsoleMode  ;GetStdHandle  KERNEL32.dll   ??$?6DU?$char_traits@D@std@@V?$allocator@D@1@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z ?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A  J?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A  ??$getline@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z  _??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ  {??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ  ?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z  MSVCP90.dll _amsg_exit   __getmainargs ,_cexit  |_exit f _XcptFilter exit   __initenv _initterm _initterm_e <_configthreadlocale  __setusermatherr  _adjust_fdiv   __p__commode   __p__fmode  j_encode_pointer  __set_app_type  K_crt_debugger_hook  C ?terminate@@YAXXZ MSVCR90.dll _unlock  __dllonexit v_lock _onexit `_decode_pointer s_except_handler4_common _invoke_watson  ?_controlfp_s  InterlockedExchange !Sleep InterlockedCompareExchange  -TerminateProcess  GetCurrentProcess >UnhandledExceptionFilter  SetUnhandledExceptionFilter IsDebuggerPresent TQueryPerformanceCounter fGetTickCount  GetCurrentThreadId  GetCurrentProcessId OGetSystemTimeAsFileTime s __CxxFrameHandler3                                                    N@D   $!@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            8                   P                   h                	                   	     @  (        C  V        (4   V S _ V E R S I O N _ I N F O                                                  S t r i n g F i l e I n f o   b   0 4 0 9 0 4 b 0    Q  F i l e D e s c r i p t i o n     R e a d s   f r o m   s t d i n   w i t h o u t   l e a k i n g   i n f o   t o   t h e   t e r m i n a l   a n d   o u t p u t s   b a c k   t o   s t d o u t     6   F i l e V e r s i o n     1 ,   0 ,   0 ,   0     8   I n t e r n a l N a m e   h i d d e n i n p u t   P   L e g a l C o p y r i g h t   J o r d i   B o g g i a n o   -   2 0 1 2   H   O r i g i n a l F i l e n a m e   h i d d e n i n p u t . e x e   :   P r o d u c t N a m e     H i d d e n   I n p u t     :   P r o d u c t V e r s i o n   1 ,   0 ,   0 ,   0     D    V a r F i l e I n f o     $    T r a n s l a t i o n     	<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING   @  00!0/080F0L0T0^0d0n0{000000000000001#1-1@1J1O1T1v1{1111111111111112"2*23292A2M2_2j2p222222222222333%303N3T3Z3`3f3l3s3z333333333333333334444%4;4B444444444445!5^5c5555H6M6_6}666 777*7w7|77777888=8E8P8V8\8b8h8n8t8z88889      $   0001 1t1x12 2@2\2`2h2t2 0     0                                                                                                                                                  <?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\SignalRegistry;

/**
 * @author Grégoire Pineau <lyrixx@lyrixx.info>
 */
class SignalMap
{
    private static array $map;

    public static function getSignalName(int $signal): ?string
    {
        if (!\extension_loaded('pcntl')) {
            return null;
        }

        if (!isset(self::$map)) {
            $r = new \ReflectionExtension('pcntl');
            $c = $r->getConstants();
            $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY);
            self::$map = array_flip($map);
        }

        return self::$map[$signal] ?? null;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\SignalRegistry;

final class SignalRegistry
{
    private array $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
    {
        return \function_exists('pcntl_signal');
    }

    /**
     * @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);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Grégoire Pineau <lyrixx@lyrixx.info>
 */
class SingleCommandApplication extends Command
{
    private string $version = 'UNKNOWN';
    private bool $autoExit = true;
    private bool $running = false;

    /**
     * @return $this
     */
    public function setVersion(string $version): static
    {
        $this->version = $version;

        return $this;
    }

    /**
     * @final
     *
     * @return $this
     */
    public function setAutoExit(bool $autoExit): static
    {
        $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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Decorates output to add console style guide helpers.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
abstract class OutputStyle implements OutputInterface, StyleInterface
{
    private OutputInterface $output;

    public function __construct(OutputInterface $output)
    {
        $this->output = $output;
    }

    /**
     * @return void
     */
    public function newLine(int $count = 1)
    {
        $this->output->write(str_repeat(\PHP_EOL, $count));
    }

    public function createProgressBar(int $max = 0): ProgressBar
    {
        return new ProgressBar($this->output, $max);
    }

    /**
     * @return void
     */
    public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
    {
        $this->output->write($messages, $newline, $type);
    }

    /**
     * @return void
     */
    public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL)
    {
        $this->output->writeln($messages, $type);
    }

    /**
     * @return void
     */
    public function setVerbosity(int $level)
    {
        $this->output->setVerbosity($level);
    }

    public function getVerbosity(): int
    {
        return $this->output->getVerbosity();
    }

    /**
     * @return void
     */
    public function setDecorated(bool $decorated)
    {
        $this->output->setDecorated($decorated);
    }

    public function isDecorated(): bool
    {
        return $this->output->isDecorated();
    }

    /**
     * @return void
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        $this->output->setFormatter($formatter);
    }

    public function getFormatter(): OutputFormatterInterface
    {
        return $this->output->getFormatter();
    }

    public function isQuiet(): bool
    {
        return $this->output->isQuiet();
    }

    public function isVerbose(): bool
    {
        return $this->output->isVerbose();
    }

    public function isVeryVerbose(): bool
    {
        return $this->output->isVeryVerbose();
    }

    public function isDebug(): bool
    {
        return $this->output->isDebug();
    }

    /**
     * @return OutputInterface
     */
    protected function getErrorOutput()
    {
        if (!$this->output instanceof ConsoleOutputInterface) {
            return $this->output;
        }

        return $this->output->getErrorOutput();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Style;

/**
 * Output style helpers.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
interface StyleInterface
{
    /**
     * Formats a command title.
     *
     * @return void
     */
    public function title(string $message);

    /**
     * Formats a section title.
     *
     * @return void
     */
    public function section(string $message);

    /**
     * Formats a list.
     *
     * @return void
     */
    public function listing(array $elements);

    /**
     * Formats informational text.
     *
     * @return void
     */
    public function text(string|array $message);

    /**
     * Formats a success result bar.
     *
     * @return void
     */
    public function success(string|array $message);

    /**
     * Formats an error result bar.
     *
     * @return void
     */
    public function error(string|array $message);

    /**
     * Formats an warning result bar.
     *
     * @return void
     */
    public function warning(string|array $message);

    /**
     * Formats a note admonition.
     *
     * @return void
     */
    public function note(string|array $message);

    /**
     * Formats a caution admonition.
     *
     * @return void
     */
    public function caution(string|array $message);

    /**
     * Formats a table.
     *
     * @return void
     */
    public function table(array $headers, array $rows);

    /**
     * Asks a question.
     */
    public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed;

    /**
     * Asks a question with the user input hidden.
     */
    public function askHidden(string $question, ?callable $validator = null): mixed;

    /**
     * Asks for confirmation.
     */
    public function confirm(string $question, bool $default = true): bool;

    /**
     * Asks a choice question.
     */
    public function choice(string $question, array $choices, mixed $default = null): mixed;

    /**
     * Add newline(s).
     *
     * @return void
     */
    public function newLine(int $count = 1);

    /**
     * Starts the progress output.
     *
     * @return void
     */
    public function progressStart(int $max = 0);

    /**
     * Advances the progress output X steps.
     *
     * @return void
     */
    public function progressAdvance(int $step = 1);

    /**
     * Finishes the progress output.
     *
     * @return void
     */
    public function progressFinish();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\OutputWrapper;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\TrimmedBufferOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;

/**
 * Output decorator helpers for the Symfony Style Guide.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class SymfonyStyle extends OutputStyle
{
    public const MAX_LINE_LENGTH = 120;

    private InputInterface $input;
    private OutputInterface $output;
    private SymfonyQuestionHelper $questionHelper;
    private ProgressBar $progressBar;
    private int $lineLength;
    private TrimmedBufferOutput $bufferedOutput;

    public function __construct(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());
        // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
        $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
        $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);

        parent::__construct($this->output = $output);
    }

    /**
     * Formats a message as a block of text.
     *
     * @return void
     */
    public function block(string|array $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
    {
        $messages = \is_array($messages) ? array_values($messages) : [$messages];

        $this->autoPrependBlock();
        $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
        $this->newLine();
    }

    /**
     * @return void
     */
    public function title(string $message)
    {
        $this->autoPrependBlock();
        $this->writeln([
            \sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
            \sprintf('<comment>%s</>', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
        ]);
        $this->newLine();
    }

    /**
     * @return void
     */
    public function section(string $message)
    {
        $this->autoPrependBlock();
        $this->writeln([
            \sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
            \sprintf('<comment>%s</>', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
        ]);
        $this->newLine();
    }

    /**
     * @return void
     */
    public function listing(array $elements)
    {
        $this->autoPrependText();
        $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements);

        $this->writeln($elements);
        $this->newLine();
    }

    /**
     * @return void
     */
    public function text(string|array $message)
    {
        $this->autoPrependText();

        $messages = \is_array($message) ? array_values($message) : [$message];
        foreach ($messages as $message) {
            $this->writeln(\sprintf(' %s', $message));
        }
    }

    /**
     * Formats a command comment.
     *
     * @return void
     */
    public function comment(string|array $message)
    {
        $this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);
    }

    /**
     * @return void
     */
    public function success(string|array $message)
    {
        $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
    }

    /**
     * @return void
     */
    public function error(string|array $message)
    {
        $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
    }

    /**
     * @return void
     */
    public function warning(string|array $message)
    {
        $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);
    }

    /**
     * @return void
     */
    public function note(string|array $message)
    {
        $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
    }

    /**
     * Formats an info message.
     *
     * @return void
     */
    public function info(string|array $message)
    {
        $this->block($message, 'INFO', 'fg=green', ' ', true);
    }

    /**
     * @return void
     */
    public function caution(string|array $message)
    {
        $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
    }

    /**
     * @return void
     */
    public function table(array $headers, array $rows)
    {
        $this->createTable()
            ->setHeaders($headers)
            ->setRows($rows)
            ->render()
        ;

        $this->newLine();
    }

    /**
     * Formats a horizontal table.
     *
     * @return void
     */
    public function horizontalTable(array $headers, array $rows)
    {
        $this->createTable()
            ->setHorizontal(true)
            ->setHeaders($headers)
            ->setRows($rows)
            ->render()
        ;

        $this->newLine();
    }

    /**
     * Formats a list of key/value horizontally.
     *
     * Each row can be one of:
     * * 'A title'
     * * ['key' => 'value']
     * * new TableSeparator()
     *
     * @return void
     */
    public function definitionList(string|array|TableSeparator ...$list)
    {
        $headers = [];
        $row = [];
        foreach ($list as $value) {
            if ($value instanceof TableSeparator) {
                $headers[] = $value;
                $row[] = $value;
                continue;
            }
            if (\is_string($value)) {
                $headers[] = new TableCell($value, ['colspan' => 2]);
                $row[] = null;
                continue;
            }
            if (!\is_array($value)) {
                throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
            }
            $headers[] = key($value);
            $row[] = current($value);
        }

        $this->horizontalTable($headers, [$row]);
    }

    public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed
    {
        $question = new Question($question, $default);
        $question->setValidator($validator);

        return $this->askQuestion($question);
    }

    public function askHidden(string $question, ?callable $validator = null): mixed
    {
        $question = new Question($question);

        $question->setHidden(true);
        $question->setValidator($validator);

        return $this->askQuestion($question);
    }

    public function confirm(string $question, bool $default = true): bool
    {
        return $this->askQuestion(new ConfirmationQuestion($question, $default));
    }

    public function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed
    {
        if (null !== $default) {
            $values = array_flip($choices);
            $default = $values[$default] ?? $default;
        }

        $questionChoice = new ChoiceQuestion($question, $choices, $default);
        $questionChoice->setMultiselect($multiSelect);

        return $this->askQuestion($questionChoice);
    }

    /**
     * @return void
     */
    public function progressStart(int $max = 0)
    {
        $this->progressBar = $this->createProgressBar($max);
        $this->progressBar->start();
    }

    /**
     * @return void
     */
    public function progressAdvance(int $step = 1)
    {
        $this->getProgressBar()->advance($step);
    }

    /**
     * @return void
     */
    public function progressFinish()
    {
        $this->getProgressBar()->finish();
        $this->newLine(2);
        unset($this->progressBar);
    }

    public function createProgressBar(int $max = 0): ProgressBar
    {
        $progressBar = parent::createProgressBar($max);

        if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
            $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591
            $progressBar->setProgressCharacter('');
            $progressBar->setBarCharacter('▓'); // dark shade character \u2593
        }

        return $progressBar;
    }

    /**
     * @see ProgressBar::iterate()
     *
     * @template TKey
     * @template TValue
     *
     * @param iterable<TKey, TValue> $iterable
     * @param int|null               $max      Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
     *
     * @return iterable<TKey, TValue>
     */
    public function progressIterate(iterable $iterable, ?int $max = null): iterable
    {
        yield from $this->createProgressBar()->iterate($iterable, $max);

        $this->newLine(2);
    }

    public function askQuestion(Question $question): mixed
    {
        if ($this->input->isInteractive()) {
            $this->autoPrependBlock();
        }

        $this->questionHelper ??= new SymfonyQuestionHelper();

        $answer = $this->questionHelper->ask($this->input, $this, $question);

        if ($this->input->isInteractive()) {
            if ($this->output instanceof ConsoleSectionOutput) {
                // add the new line of the `return` to submit the input to ConsoleSectionOutput, because ConsoleSectionOutput is holding all it's lines.
                // this is relevant when a `ConsoleSectionOutput::clear` is called.
                $this->output->addNewLineOfInputSubmit();
            }
            $this->newLine();
            $this->bufferedOutput->write("\n");
        }

        return $answer;
    }

    /**
     * @return void
     */
    public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL)
    {
        if (!is_iterable($messages)) {
            $messages = [$messages];
        }

        foreach ($messages as $message) {
            parent::writeln($message, $type);
            $this->writeBuffer($message, true, $type);
        }
    }

    /**
     * @return void
     */
    public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
    {
        if (!is_iterable($messages)) {
            $messages = [$messages];
        }

        foreach ($messages as $message) {
            parent::write($message, $newline, $type);
            $this->writeBuffer($message, $newline, $type);
        }
    }

    /**
     * @return void
     */
    public function newLine(int $count = 1)
    {
        parent::newLine($count);
        $this->bufferedOutput->write(str_repeat("\n", $count));
    }

    /**
     * Returns a new instance which makes use of stderr if available.
     */
    public function getErrorStyle(): self
    {
        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('<info>%s</info>');

        return (new Table($output))->setStyle($style);
    }

    private function getProgressBar(): ProgressBar
    {
        return $this->progressBar
            ?? throw new RuntimeException('The ProgressBar is not started.');
    }

    private function autoPrependBlock(): void
    {
        $chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);

        if (!isset($chars[0])) {
            $this->newLine(); // empty history, so we should start with a new line.

            return;
        }
        // Prepend new line for each non LF chars (This means no blank line was output before)
        $this->newLine(2 - substr_count($chars, "\n"));
    }

    private function autoPrependText(): void
    {
        $fetched = $this->bufferedOutput->fetch();
        // Prepend new line if last char isn't EOL:
        if ($fetched && !str_ends_with($fetched, "\n")) {
            $this->newLine();
        }
    }

    private function writeBuffer(string $message, bool $newLine, int $type): void
    {
        // We need to know if the last chars are PHP_EOL
        $this->bufferedOutput->write($message, $newLine, $type);
    }

    private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
    {
        $indentLength = 0;
        $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));
        $lines = [];

        if (null !== $type) {
            $type = \sprintf('[%s] ', $type);
            $indentLength = Helper::width($type);
            $lineIndentation = str_repeat(' ', $indentLength);
        }

        // wrap and add newlines for each element
        $outputWrapper = new OutputWrapper();
        foreach ($messages as $key => $message) {
            if ($escape) {
                $message = OutputFormatter::escape($message);
            }

            $lines = array_merge(
                $lines,
                explode(\PHP_EOL, $outputWrapper->wrap(
                    $message,
                    $this->lineLength - $prefixLength - $indentLength,
                    \PHP_EOL
                ))
            );

            if (\count($messages) > 1 && $key < \count($messages) - 1) {
                $lines[] = '';
            }
        }

        $firstLineIndex = 0;
        if ($padding && $this->isDecorated()) {
            $firstLineIndex = 1;
            array_unshift($lines, '');
            $lines[] = '';
        }

        foreach ($lines as $i => &$line) {
            if (null !== $type) {
                $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
            }

            $line = $prefix.$line;
            $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0));

            if ($style) {
                $line = \sprintf('<%s>%s</>', $style, $line);
            }
        }

        return $lines;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console;

use Symfony\Component\Console\Output\AnsiColorMode;

class Terminal
{
    public const DEFAULT_COLOR_MODE = AnsiColorMode::Ansi4;

    private static ?AnsiColorMode $colorMode = null;
    private static ?int $width = null;
    private static ?int $height = null;
    private static ?bool $stty = null;

    /**
     * About Ansi color types: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
     * For more information about true color support with terminals https://github.com/termstandard/colors/.
     */
    public static function getColorMode(): AnsiColorMode
    {
        // Use Cache from previous run (or user forced mode)
        if (null !== self::$colorMode) {
            return self::$colorMode;
        }

        // Try with $COLORTERM first
        if (\is_string($colorterm = getenv('COLORTERM'))) {
            $colorterm = strtolower($colorterm);

            if (str_contains($colorterm, 'truecolor')) {
                self::setColorMode(AnsiColorMode::Ansi24);

                return self::$colorMode;
            }

            if (str_contains($colorterm, '256color')) {
                self::setColorMode(AnsiColorMode::Ansi8);

                return self::$colorMode;
            }
        }

        // Try with $TERM
        if (\is_string($term = getenv('TERM'))) {
            $term = strtolower($term);

            if (str_contains($term, 'truecolor')) {
                self::setColorMode(AnsiColorMode::Ansi24);

                return self::$colorMode;
            }

            if (str_contains($term, '256color')) {
                self::setColorMode(AnsiColorMode::Ansi8);

                return self::$colorMode;
            }
        }

        self::setColorMode(self::DEFAULT_COLOR_MODE);

        return self::$colorMode;
    }

    /**
     * Force a terminal color mode rendering.
     */
    public static function setColorMode(?AnsiColorMode $colorMode): void
    {
        self::$colorMode = $colorMode;
    }

    /**
     * Gets the terminal width.
     */
    public function getWidth(): int
    {
        $width = getenv('COLUMNS');
        if (false !== $width) {
            return (int) trim($width);
        }

        if (null === self::$width) {
            self::initDimensions();
        }

        return self::$width ?: 80;
    }

    /**
     * Gets the terminal height.
     */
    public function getHeight(): int
    {
        $height = getenv('LINES');
        if (false !== $height) {
            return (int) trim($height);
        }

        if (null === self::$height) {
            self::initDimensions();
        }

        return self::$height ?: 50;
    }

    /**
     * @internal
     */
    public static function hasSttyAvailable(): bool
    {
        if (null !== self::$stty) {
            return self::$stty;
        }

        // skip check if shell_exec function is disabled
        if (!\function_exists('shell_exec')) {
            return false;
        }

        return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
    }

    private static function initDimensions(): void
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $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];
                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
            } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
                // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash)
                // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT
                self::initDimensionsUsingStty();
            } elseif (null !== $dimensions = self::getConsoleMode()) {
                // extract [w, h] from "wxh"
                self::$width = (int) $dimensions[0];
                self::$height = (int) $dimensions[1];
            }
        } else {
            self::initDimensionsUsingStty();
        }
    }

    /**
     * Returns whether STDOUT has vt100 support (some Windows 10+ configurations).
     */
    private static function hasVt100Support(): bool
    {
        return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));
    }

    /**
     * Initializes dimensions using the output of an stty columns line.
     */
    private static function initDimensionsUsingStty(): void
    {
        if ($sttyString = self::getSttyColumns()) {
            if (preg_match('/rows.(\d+);.columns.(\d+);/is', $sttyString, $matches)) {
                // extract [w, h] from "rows h; columns w;"
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/is', $sttyString, $matches)) {
                // extract [w, h] from "; h rows; w columns"
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            }
        }
    }

    /**
     * Runs and parses mode CON if it's available, suppressing any error output.
     *
     * @return int[]|null An array composed of the width and the height or null if it could not be parsed
     */
    private static function getConsoleMode(): ?array
    {
        $info = self::readFromProcess('mode CON');

        if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
            return null;
        }

        return [(int) $matches[2], (int) $matches[1]];
    }

    /**
     * Runs and parses stty -a if it's available, suppressing any error output.
     */
    private static function getSttyColumns(): ?string
    {
        return self::readFromProcess(['stty', '-a']);
    }

    private static function readFromProcess(string|array $command): ?string
    {
        if (!\function_exists('proc_open')) {
            return null;
        }

        $descriptorspec = [
            1 => ['pipe', 'w'],
            2 => ['pipe', 'w'],
        ];

        $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;

        if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) {
            return null;
        }

        $info = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($process);

        if ($cp) {
            sapi_windows_cp_set($cp);
        }

        return $info;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;

/**
 * Eases the testing of console applications.
 *
 * When testing an application, don't forget to disable the auto exit flag:
 *
 *     $application = new Application();
 *     $application->setAutoExit(false);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ApplicationTester
{
    use TesterTrait;

    private Application $application;

    public function __construct(Application $application)
    {
        $this->application = $application;
    }

    /**
     * Executes the application.
     *
     * Available options:
     *
     *  * interactive:               Sets the input interactive flag
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     *
     * @return int The command exit code
     */
    public function run(array $input, array $options = []): int
    {
        $prevShellVerbosity = getenv('SHELL_VERBOSITY');

        try {
            $this->input = new ArrayInput($input);
            if (isset($options['interactive'])) {
                $this->input->setInteractive($options['interactive']);
            }

            if ($this->inputs) {
                $this->input->setStream(self::createStream($this->inputs));
            }

            $this->initOutput($options);

            return $this->statusCode = $this->application->run($this->input, $this->output);
        } finally {
            // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
            // to its previous value to avoid one test's verbosity to spread to the following tests
            if (false === $prevShellVerbosity) {
                if (\function_exists('putenv')) {
                    @putenv('SHELL_VERBOSITY');
                }
                unset($_ENV['SHELL_VERBOSITY']);
                unset($_SERVER['SHELL_VERBOSITY']);
            } else {
                if (\function_exists('putenv')) {
                    @putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
                }
                $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
                $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <jerome@tamarelle.net>
 */
class CommandCompletionTester
{
    private Command $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()));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;

/**
 * Eases the testing of console commands.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class CommandTester
{
    use TesterTrait;

    private Command $command;

    public function __construct(Command $command)
    {
        $this->command = $command;
    }

    /**
     * Executes the command.
     *
     * Available execution options:
     *
     *  * interactive:               Sets the input interactive flag
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     *
     * @param array $input   An array of command arguments and options
     * @param array $options An array of execution options
     *
     * @return int The command exit code
     */
    public function execute(array $input, array $options = []): int
    {
        // set the command name automatically if the application requires
        // this argument and no command name was passed
        if (!isset($input['command'])
            && (null !== $application = $this->command->getApplication())
            && $application->getDefinition()->hasArgument('command')
        ) {
            $input = array_merge(['command' => $this->command->getName()], $input);
        }

        $this->input = new ArrayInput($input);
        // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN.
        $this->input->setStream(self::createStream($this->inputs));

        if (isset($options['interactive'])) {
            $this->input->setInteractive($options['interactive']);
        }

        if (!isset($options['decorated'])) {
            $options['decorated'] = false;
        }

        $this->initOutput($options);

        return $this->statusCode = $this->command->run($this->input, $this->output);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Console\Tester\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use Symfony\Component\Console\Command\Command;

final class CommandIsSuccessful extends Constraint
{
    public function toString(): string
    {
        return 'is successful';
    }

    protected function matches($other): bool
    {
        return Command::SUCCESS === $other;
    }

    protected function failureDescription($other): string
    {
        return 'the command '.$this->toString();
    }

    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);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <hamza.simperfit@gmail.com>
 */
trait TesterTrait
{
    private StreamOutput $output;
    private array $inputs = [];
    private bool $captureStreamsIndependently = false;
    private InputInterface $input;
    private int $statusCode;

    /**
     * Gets the display returned by the last execution of the command or application.
     *
     * @throws \RuntimeException If it's called before the execute method
     */
    public function getDisplay(bool $normalize = false): string
    {
        if (!isset($this->output)) {
            throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
        }

        rewind($this->output->getStream());

        $display = stream_get_contents($this->output->getStream());

        if ($normalize) {
            $display = str_replace(\PHP_EOL, "\n", $display);
        }

        return $display;
    }

    /**
     * Gets the output written to STDERR by the application.
     *
     * @param bool $normalize Whether to normalize end of lines to \n or not
     */
    public function getErrorOutput(bool $normalize = false): string
    {
        if (!$this->captureStreamsIndependently) {
            throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
        }

        rewind($this->output->getErrorOutput()->getStream());

        $display = stream_get_contents($this->output->getErrorOutput()->getStream());

        if ($normalize) {
            $display = str_replace(\PHP_EOL, "\n", $display);
        }

        return $display;
    }

    /**
     * Gets the input instance used by the last execution of the command or application.
     */
    public function getInput(): InputInterface
    {
        return $this->input;
    }

    /**
     * Gets the output instance used by the last execution of the command or application.
     */
    public function getOutput(): OutputInterface
    {
        return $this->output;
    }

    /**
     * Gets the status code returned by the last execution of the command or application.
     *
     * @throws \RuntimeException If it's called before the execute method
     */
    public function getStatusCode(): int
    {
        return $this->statusCode ?? throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?');
    }

    public function assertCommandIsSuccessful(string $message = ''): void
    {
        Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message);
    }

    /**
     * Sets the user inputs.
     *
     * @param array $inputs An array of strings representing each input
     *                      passed to the command input stream
     *
     * @return $this
     */
    public function setInputs(array $inputs): static
    {
        $this->inputs = $inputs;

        return $this;
    }

    /**
     * Initializes the output property.
     *
     * Available options:
     *
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     */
    private function initOutput(array $options): void
    {
        $this->captureStreamsIndependently = $options['capture_stderr_separately'] ?? false;
        if (!$this->captureStreamsIndependently) {
            $this->output = new StreamOutput(fopen('php://memory', 'w', false));
            if (isset($options['decorated'])) {
                $this->output->setDecorated($options['decorated']);
            }
            if (isset($options['verbosity'])) {
                $this->output->setVerbosity($options['verbosity']);
            }
        } else {
            $this->output = new ConsoleOutput(
                $options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL,
                $options['decorated'] ?? null
            );

            $errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
            $errorOutput->setFormatter($this->output->getFormatter());
            $errorOutput->setVerbosity($this->output->getVerbosity());
            $errorOutput->setDecorated($this->output->isDecorated());

            $reflectedOutput = new \ReflectionObject($this->output);
            $strErrProperty = $reflectedOutput->getProperty('stderr');
            $strErrProperty->setValue($this->output, $errorOutput);

            $reflectedParent = $reflectedOutput->getParentClass();
            $streamProperty = $reflectedParent->getProperty('stream');
            $streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
        }
    }

    /**
     * @return resource
     */
    private static function createStream(array $inputs)
    {
        $stream = fopen('php://memory', 'r+', false);

        foreach ($inputs as $input) {
            fwrite($stream, $input);

            if (!str_ends_with($input, "\x4")) {
                fwrite($stream, \PHP_EOL);
            }
        }

        rewind($stream);

        return $stream;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (!function_exists('trigger_deprecation')) {
    /**
     * Triggers a silenced deprecation notice.
     *
     * @param string $package The name of the Composer package that is triggering the deprecation
     * @param string $version The version of the package that introduced the deprecation
     * @param string $message The message of the deprecation
     * @param mixed  ...$args Values to insert in the message using printf() formatting
     *
     * @author Nicolas Grekas <p@tchwork.com>
     */
    function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void
    {
        @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher\Attribute;

/**
 * Service tag to autoconfigure event listeners.
 *
 * @author Alexander M. Turek <me@derrabus.de>
 */
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsEventListener
{
    public function __construct(
        public ?string $event = null,
        public ?string $method = null,
        public int $priority = 0,
        public ?string $dispatcher = null,
    ) {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher\Debug;

use Psr\EventDispatcher\StoppableEventInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Contracts\Service\ResetInterface;

/**
 * Collects some data about event listeners.
 *
 * This event dispatcher delegates the dispatching to another one.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface
{
    protected $logger;
    protected $stopwatch;

    /**
     * @var \SplObjectStorage<WrappedListener, array{string, string}>|null
     */
    private ?\SplObjectStorage $callStack = null;
    private EventDispatcherInterface $dispatcher;
    private array $wrappedListeners = [];
    private array $orphanedEvents = [];
    private ?RequestStack $requestStack;
    private string $currentRequestHash = '';

    public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, ?LoggerInterface $logger = null, ?RequestStack $requestStack = null)
    {
        $this->dispatcher = $dispatcher;
        $this->stopwatch = $stopwatch;
        $this->logger = $logger;
        $this->requestStack = $requestStack;
    }

    /**
     * @return void
     */
    public function addListener(string $eventName, callable|array $listener, int $priority = 0)
    {
        $this->dispatcher->addListener($eventName, $listener, $priority);
    }

    /**
     * @return void
     */
    public function addSubscriber(EventSubscriberInterface $subscriber)
    {
        $this->dispatcher->addSubscriber($subscriber);
    }

    /**
     * @return void
     */
    public function removeListener(string $eventName, callable|array $listener)
    {
        if (isset($this->wrappedListeners[$eventName])) {
            foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
                if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
                    $listener = $wrappedListener;
                    unset($this->wrappedListeners[$eventName][$index]);
                    break;
                }
            }
        }

        $this->dispatcher->removeListener($eventName, $listener);
    }

    /**
     * @return void
     */
    public function removeSubscriber(EventSubscriberInterface $subscriber)
    {
        $this->dispatcher->removeSubscriber($subscriber);
    }

    public function getListeners(?string $eventName = null): array
    {
        return $this->dispatcher->getListeners($eventName);
    }

    public function getListenerPriority(string $eventName, callable|array $listener): ?int
    {
        // we might have wrapped listeners for the event (if called while dispatching)
        // in that case get the priority by wrapper
        if (isset($this->wrappedListeners[$eventName])) {
            foreach ($this->wrappedListeners[$eventName] as $wrappedListener) {
                if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
                    return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
                }
            }
        }

        return $this->dispatcher->getListenerPriority($eventName, $listener);
    }

    public function hasListeners(?string $eventName = null): bool
    {
        return $this->dispatcher->hasListeners($eventName);
    }

    public function dispatch(object $event, ?string $eventName = null): object
    {
        $eventName ??= $event::class;

        $this->callStack ??= new \SplObjectStorage();

        $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';

        if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
            $this->logger->debug(\sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
        }

        $this->preProcess($eventName);
        try {
            $this->beforeDispatch($eventName, $event);
            try {
                $e = $this->stopwatch->start($eventName, 'section');
                try {
                    $this->dispatcher->dispatch($event, $eventName);
                } finally {
                    if ($e->isStarted()) {
                        $e->stop();
                    }
                }
            } finally {
                $this->afterDispatch($eventName, $event);
            }
        } finally {
            $this->currentRequestHash = $currentRequestHash;
            $this->postProcess($eventName);
        }

        return $event;
    }

    public function getCalledListeners(?Request $request = null): array
    {
        if (null === $this->callStack) {
            return [];
        }

        $hash = $request ? spl_object_hash($request) : null;
        $called = [];
        foreach ($this->callStack as $listener) {
            [$eventName, $requestHash] = $this->callStack->getInfo();
            if (null === $hash || $hash === $requestHash) {
                $called[] = $listener->getInfo($eventName);
            }
        }

        return $called;
    }

    public function getNotCalledListeners(?Request $request = null): array
    {
        try {
            $allListeners = $this->dispatcher instanceof EventDispatcher ? $this->getListenersWithPriority() : $this->getListenersWithoutPriority();
        } catch (\Exception $e) {
            $this->logger?->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]);

            // unable to retrieve the uncalled listeners
            return [];
        }

        $hash = $request ? spl_object_hash($request) : null;
        $calledListeners = [];

        if (null !== $this->callStack) {
            foreach ($this->callStack as $calledListener) {
                [, $requestHash] = $this->callStack->getInfo();

                if (null === $hash || $hash === $requestHash) {
                    $calledListeners[] = $calledListener->getWrappedListener();
                }
            }
        }

        $notCalled = [];

        foreach ($allListeners as $eventName => $listeners) {
            foreach ($listeners as [$listener, $priority]) {
                if (!\in_array($listener, $calledListeners, true)) {
                    if (!$listener instanceof WrappedListener) {
                        $listener = new WrappedListener($listener, null, $this->stopwatch, $this, $priority);
                    }
                    $notCalled[] = $listener->getInfo($eventName);
                }
            }
        }

        uasort($notCalled, $this->sortNotCalledListeners(...));

        return $notCalled;
    }

    public function getOrphanedEvents(?Request $request = null): array
    {
        if ($request) {
            return $this->orphanedEvents[spl_object_hash($request)] ?? [];
        }

        if (!$this->orphanedEvents) {
            return [];
        }

        return array_merge(...array_values($this->orphanedEvents));
    }

    /**
     * @return void
     */
    public function reset()
    {
        $this->callStack = null;
        $this->orphanedEvents = [];
        $this->currentRequestHash = '';
    }

    /**
     * Proxies all method calls to the original event dispatcher.
     *
     * @param string $method    The method name
     * @param array  $arguments The method arguments
     */
    public function __call(string $method, array $arguments): mixed
    {
        return $this->dispatcher->{$method}(...$arguments);
    }

    /**
     * Called before dispatching the event.
     *
     * @return void
     */
    protected function beforeDispatch(string $eventName, object $event)
    {
    }

    /**
     * Called after dispatching the event.
     *
     * @return void
     */
    protected function afterDispatch(string $eventName, object $event)
    {
    }

    private function preProcess(string $eventName): void
    {
        if (!$this->dispatcher->hasListeners($eventName)) {
            $this->orphanedEvents[$this->currentRequestHash][] = $eventName;

            return;
        }

        foreach ($this->dispatcher->getListeners($eventName) as $listener) {
            $priority = $this->getListenerPriority($eventName, $listener);
            $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this);
            $this->wrappedListeners[$eventName][] = $wrappedListener;
            $this->dispatcher->removeListener($eventName, $listener);
            $this->dispatcher->addListener($eventName, $wrappedListener, $priority);
            $this->callStack[$wrappedListener] = [$eventName, $this->currentRequestHash];
        }
    }

    private function postProcess(string $eventName): void
    {
        unset($this->wrappedListeners[$eventName]);
        $skipped = false;
        foreach ($this->dispatcher->getListeners($eventName) as $listener) {
            if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch.
                continue;
            }
            // Unwrap listener
            $priority = $this->getListenerPriority($eventName, $listener);
            $this->dispatcher->removeListener($eventName, $listener);
            $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);

            if (null !== $this->logger) {
                $context = ['event' => $eventName, 'listener' => $listener->getPretty()];
            }

            if ($listener->wasCalled()) {
                $this->logger?->debug('Notified event "{event}" to listener "{listener}".', $context);
            } else {
                unset($this->callStack[$listener]);
            }

            if (null !== $this->logger && $skipped) {
                $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
            }

            if ($listener->stoppedPropagation()) {
                $this->logger?->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context);

                $skipped = true;
            }
        }
    }

    private function sortNotCalledListeners(array $a, array $b): int
    {
        if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
            return $cmp;
        }

        if (\is_int($a['priority']) && !\is_int($b['priority'])) {
            return 1;
        }

        if (!\is_int($a['priority']) && \is_int($b['priority'])) {
            return -1;
        }

        if ($a['priority'] === $b['priority']) {
            return 0;
        }

        if ($a['priority'] > $b['priority']) {
            return -1;
        }

        return 1;
    }

    private function getListenersWithPriority(): array
    {
        $result = [];

        $allListeners = new \ReflectionProperty(EventDispatcher::class, 'listeners');

        foreach ($allListeners->getValue($this->dispatcher) as $eventName => $listenersByPriority) {
            foreach ($listenersByPriority as $priority => $listeners) {
                foreach ($listeners as $listener) {
                    $result[$eventName][] = [$listener, $priority];
                }
            }
        }

        return $result;
    }

    private function getListenersWithoutPriority(): array
    {
        $result = [];

        foreach ($this->getListeners() as $eventName => $listeners) {
            foreach ($listeners as $listener) {
                $result[$eventName][] = [$listener, null];
            }
        }

        return $result;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher\Debug;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Caster\ClassStub;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 */
final class WrappedListener
{
    private string|array|object $listener;
    private ?\Closure $optimizedListener;
    private string $name;
    private bool $called = false;
    private bool $stoppedPropagation = false;
    private Stopwatch $stopwatch;
    private ?EventDispatcherInterface $dispatcher;
    private string $pretty;
    private string $callableRef;
    private ClassStub|string $stub;
    private ?int $priority = null;
    private static bool $hasClassStub;

    public function __construct(callable|array $listener, ?string $name, Stopwatch $stopwatch, ?EventDispatcherInterface $dispatcher = null, ?int $priority = null)
    {
        $this->listener = $listener;
        $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? $listener(...) : null);
        $this->stopwatch = $stopwatch;
        $this->dispatcher = $dispatcher;
        $this->priority = $priority;

        if (\is_array($listener)) {
            [$this->name, $this->callableRef] = $this->parseListener($listener);
            $this->pretty = $this->name.'::'.$listener[1];
            $this->callableRef .= '::'.$listener[1];
        } elseif ($listener instanceof \Closure) {
            $r = new \ReflectionFunction($listener);
            if (str_contains($r->name, '{closure')) {
                $this->pretty = $this->name = 'closure';
            } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
                $this->name = $class->name;
                $this->pretty = $this->name.'::'.$r->name;
            } else {
                $this->pretty = $this->name = $r->name;
            }
        } elseif (\is_string($listener)) {
            $this->pretty = $this->name = $listener;
        } else {
            $this->name = get_debug_type($listener);
            $this->pretty = $this->name.'::__invoke';
            $this->callableRef = $listener::class.'::__invoke';
        }

        if (null !== $name) {
            $this->name = $name;
        }

        self::$hasClassStub ??= class_exists(ClassStub::class);
    }

    public function getWrappedListener(): callable|array
    {
        return $this->listener;
    }

    public function wasCalled(): bool
    {
        return $this->called;
    }

    public function stoppedPropagation(): bool
    {
        return $this->stoppedPropagation;
    }

    public function getPretty(): string
    {
        return $this->pretty;
    }

    public function getInfo(string $eventName): array
    {
        $this->stub ??= self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->callableRef ?? $this->listener) : $this->pretty.'()';

        return [
            'event' => $eventName,
            'priority' => $this->priority ??= $this->dispatcher?->getListenerPriority($eventName, $this->listener),
            'pretty' => $this->pretty,
            'stub' => $this->stub,
        ];
    }

    public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void
    {
        $dispatcher = $this->dispatcher ?: $dispatcher;

        $this->called = true;
        $this->priority ??= $dispatcher->getListenerPriority($eventName, $this->listener);

        $e = $this->stopwatch->start($this->name, 'event_listener');

        try {
            ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);
        } finally {
            if ($e->isStarted()) {
                $e->stop();
            }
        }

        if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
            $this->stoppedPropagation = true;
        }
    }

    private function parseListener(array $listener): array
    {
        if ($listener[0] instanceof \Closure) {
            foreach ((new \ReflectionFunction($listener[0]))->getAttributes(\Closure::class) as $attribute) {
                if ($name = $attribute->getArguments()['name'] ?? false) {
                    return [$name, $attribute->getArguments()['class'] ?? $name];
                }
            }
        }

        if (\is_object($listener[0])) {
            return [get_debug_type($listener[0]), $listener[0]::class];
        }

        return [$listener[0], $listener[0]];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * This pass allows bundles to extend the list of event aliases.
 *
 * @author Alexander M. Turek <me@derrabus.de>
 */
class AddEventAliasesPass implements CompilerPassInterface
{
    private array $eventAliases;

    public function __construct(array $eventAliases)
    {
        $this->eventAliases = $eventAliases;
    }

    public function process(ContainerBuilder $container): void
    {
        $eventAliases = $container->hasParameter('event_dispatcher.event_aliases') ? $container->getParameter('event_dispatcher.event_aliases') : [];

        $container->setParameter(
            'event_dispatcher.event_aliases',
            array_merge($eventAliases, $this->eventAliases)
        );
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher\DependencyInjection;

use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\Event;

/**
 * Compiler pass to register tagged services for an event dispatcher.
 */
class RegisterListenersPass implements CompilerPassInterface
{
    private array $hotPathEvents = [];
    private array $noPreloadEvents = [];

    /**
     * @return $this
     */
    public function setHotPathEvents(array $hotPathEvents): static
    {
        $this->hotPathEvents = array_flip($hotPathEvents);

        return $this;
    }

    /**
     * @return $this
     */
    public function setNoPreloadEvents(array $noPreloadEvents): static
    {
        $this->noPreloadEvents = array_flip($noPreloadEvents);

        return $this;
    }

    /**
     * @return void
     */
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('event_dispatcher') && !$container->hasAlias('event_dispatcher')) {
            return;
        }

        $aliases = [];

        if ($container->hasParameter('event_dispatcher.event_aliases')) {
            $aliases = $container->getParameter('event_dispatcher.event_aliases');
        }

        $globalDispatcherDefinition = $container->findDefinition('event_dispatcher');

        foreach ($container->findTaggedServiceIds('kernel.event_listener', true) as $id => $events) {
            $noPreload = 0;

            foreach ($events as $event) {
                $priority = $event['priority'] ?? 0;

                if (!isset($event['event'])) {
                    if ($container->getDefinition($id)->hasTag('kernel.event_subscriber')) {
                        continue;
                    }

                    $event['method'] ??= '__invoke';
                    $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']);
                }

                $event['event'] = $aliases[$event['event']] ?? $event['event'];

                if (!isset($event['method'])) {
                    $event['method'] = 'on'.preg_replace_callback([
                        '/(?<=\b|_)[a-z]/i',
                        '/[^a-z0-9]/i',
                    ], fn ($matches) => strtoupper($matches[0]), $event['event']);
                    $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);

                    if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) {
                        if (!$r->hasMethod('__invoke')) {
                            throw new InvalidArgumentException(\sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id));
                        }

                        $event['method'] = '__invoke';
                    }
                }

                $dispatcherDefinition = $globalDispatcherDefinition;
                if (isset($event['dispatcher'])) {
                    $dispatcherDefinition = $container->findDefinition($event['dispatcher']);
                }

                $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);

                if (isset($this->hotPathEvents[$event['event']])) {
                    $container->getDefinition($id)->addTag('container.hot_path');
                } elseif (isset($this->noPreloadEvents[$event['event']])) {
                    ++$noPreload;
                }
            }

            if ($noPreload && \count($events) === $noPreload) {
                $container->getDefinition($id)->addTag('container.no_preload');
            }
        }

        $extractingDispatcher = new ExtractingEventDispatcher();

        foreach ($container->findTaggedServiceIds('kernel.event_subscriber', true) as $id => $tags) {
            $def = $container->getDefinition($id);

            // We must assume that the class value has been correctly filled, even if the service is created by a factory
            $class = $def->getClass();

            if (!$r = $container->getReflectionClass($class)) {
                throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
            }
            if (!$r->isSubclassOf(EventSubscriberInterface::class)) {
                throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class));
            }
            $class = $r->name;

            $dispatcherDefinitions = [];
            foreach ($tags as $attributes) {
                if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) {
                    continue;
                }

                $dispatcherDefinitions[$attributes['dispatcher']] = $container->findDefinition($attributes['dispatcher']);
            }

            if (!$dispatcherDefinitions) {
                $dispatcherDefinitions = [$globalDispatcherDefinition];
            }

            $noPreload = 0;
            ExtractingEventDispatcher::$aliases = $aliases;
            ExtractingEventDispatcher::$subscriber = $class;
            $extractingDispatcher->addSubscriber($extractingDispatcher);
            foreach ($extractingDispatcher->listeners as $args) {
                $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
                foreach ($dispatcherDefinitions as $dispatcherDefinition) {
                    $dispatcherDefinition->addMethodCall('addListener', $args);
                }

                if (isset($this->hotPathEvents[$args[0]])) {
                    $container->getDefinition($id)->addTag('container.hot_path');
                } elseif (isset($this->noPreloadEvents[$args[0]])) {
                    ++$noPreload;
                }
            }
            if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) {
                $container->getDefinition($id)->addTag('container.no_preload');
            }
            $extractingDispatcher->listeners = [];
            ExtractingEventDispatcher::$aliases = [];
        }
    }

    private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string
    {
        if (
            null === ($class = $container->getDefinition($id)->getClass())
            || !($r = $container->getReflectionClass($class, false))
            || !$r->hasMethod($method)
            || 1 > ($m = $r->getMethod($method))->getNumberOfParameters()
            || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
            || $type->isBuiltin()
            || Event::class === ($name = $type->getName())
        ) {
            throw new InvalidArgumentException(\sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id));
        }

        return $name;
    }
}

/**
 * @internal
 */
class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface
{
    public array $listeners = [];

    public static array $aliases = [];
    public static string $subscriber;

    public function addListener(string $eventName, callable|array $listener, int $priority = 0): void
    {
        $this->listeners[] = [$eventName, $listener[1], $priority];
    }

    public static function getSubscribedEvents(): array
    {
        $events = [];

        foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) {
            $events[self::$aliases[$eventName] ?? $eventName] = $params;
        }

        return $events;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Debug\WrappedListener;

/**
 * The EventDispatcherInterface is the central point of Symfony's event listener system.
 *
 * Listeners are registered on the manager and events are dispatched through the
 * manager.
 *
 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author Jonathan Wage <jonwage@gmail.com>
 * @author Roman Borschel <roman@code-factory.org>
 * @author Bernhard Schussek <bschussek@gmail.com>
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @author Jordan Alliot <jordan.alliot@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 */
class EventDispatcher implements EventDispatcherInterface
{
    private array $listeners = [];
    private array $sorted = [];
    private array $optimized;

    public function __construct()
    {
        if (__CLASS__ === static::class) {
            $this->optimized = [];
        }
    }

    public function dispatch(object $event, ?string $eventName = null): object
    {
        $eventName ??= $event::class;

        if (isset($this->optimized)) {
            $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
        } else {
            $listeners = $this->getListeners($eventName);
        }

        if ($listeners) {
            $this->callListeners($listeners, $eventName, $event);
        }

        return $event;
    }

    public function getListeners(?string $eventName = null): array
    {
        if (null !== $eventName) {
            if (empty($this->listeners[$eventName])) {
                return [];
            }

            if (!isset($this->sorted[$eventName])) {
                $this->sortListeners($eventName);
            }

            return $this->sorted[$eventName];
        }

        foreach ($this->listeners as $eventName => $eventListeners) {
            if (!isset($this->sorted[$eventName])) {
                $this->sortListeners($eventName);
            }
        }

        return array_filter($this->sorted);
    }

    public function getListenerPriority(string $eventName, callable|array $listener): ?int
    {
        if (empty($this->listeners[$eventName])) {
            return null;
        }

        if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
            $listener[0] = $listener[0]();
            $listener[1] ??= '__invoke';
        }

        foreach ($this->listeners[$eventName] as $priority => &$listeners) {
            foreach ($listeners as &$v) {
                if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
                    $v[0] = $v[0]();
                    $v[1] ??= '__invoke';
                }
                if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
                    return $priority;
                }
            }
        }

        return null;
    }

    public function hasListeners(?string $eventName = null): bool
    {
        if (null !== $eventName) {
            return !empty($this->listeners[$eventName]);
        }

        foreach ($this->listeners as $eventListeners) {
            if ($eventListeners) {
                return true;
            }
        }

        return false;
    }

    /**
     * @return void
     */
    public function addListener(string $eventName, callable|array $listener, int $priority = 0)
    {
        $this->listeners[$eventName][$priority][] = $listener;
        unset($this->sorted[$eventName], $this->optimized[$eventName]);
    }

    /**
     * @return void
     */
    public function removeListener(string $eventName, callable|array $listener)
    {
        if (empty($this->listeners[$eventName])) {
            return;
        }

        if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
            $listener[0] = $listener[0]();
            $listener[1] ??= '__invoke';
        }

        foreach ($this->listeners[$eventName] as $priority => &$listeners) {
            foreach ($listeners as $k => &$v) {
                if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
                    $v[0] = $v[0]();
                    $v[1] ??= '__invoke';
                }
                if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
                    unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
                }
            }

            if (!$listeners) {
                unset($this->listeners[$eventName][$priority]);
            }
        }
    }

    /**
     * @return void
     */
    public function addSubscriber(EventSubscriberInterface $subscriber)
    {
        foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
            if (\is_string($params)) {
                $this->addListener($eventName, [$subscriber, $params]);
            } elseif (\is_string($params[0])) {
                $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0);
            } else {
                foreach ($params as $listener) {
                    $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0);
                }
            }
        }
    }

    /**
     * @return void
     */
    public function removeSubscriber(EventSubscriberInterface $subscriber)
    {
        foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
            if (\is_array($params) && \is_array($params[0])) {
                foreach ($params as $listener) {
                    $this->removeListener($eventName, [$subscriber, $listener[0]]);
                }
            } else {
                $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
            }
        }
    }

    /**
     * Triggers the listeners of an event.
     *
     * This method can be overridden to add functionality that is executed
     * for each listener.
     *
     * @param callable[] $listeners The event listeners
     * @param string     $eventName The name of the event to dispatch
     * @param object     $event     The event object to pass to the event handlers/listeners
     *
     * @return void
     */
    protected function callListeners(iterable $listeners, string $eventName, object $event)
    {
        $stoppable = $event instanceof StoppableEventInterface;

        foreach ($listeners as $listener) {
            if ($stoppable && $event->isPropagationStopped()) {
                break;
            }
            $listener($event, $eventName, $this);
        }
    }

    /**
     * Sorts the internal list of listeners for the given event by priority.
     */
    private function sortListeners(string $eventName): void
    {
        krsort($this->listeners[$eventName]);
        $this->sorted[$eventName] = [];

        foreach ($this->listeners[$eventName] as &$listeners) {
            foreach ($listeners as &$listener) {
                if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
                    $listener[0] = $listener[0]();
                    $listener[1] ??= '__invoke';
                }
                $this->sorted[$eventName][] = $listener;
            }
        }
    }

    /**
     * Optimizes the internal list of listeners for the given event by priority.
     */
    private function optimizeListeners(string $eventName): array
    {
        krsort($this->listeners[$eventName]);
        $this->optimized[$eventName] = [];

        foreach ($this->listeners[$eventName] as &$listeners) {
            foreach ($listeners as &$listener) {
                $closure = &$this->optimized[$eventName][];
                if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
                    $closure = static function (...$args) use (&$listener, &$closure) {
                        if ($listener[0] instanceof \Closure) {
                            $listener[0] = $listener[0]();
                            $listener[1] ??= '__invoke';
                        }
                        ($closure = $listener(...))(...$args);
                    };
                } else {
                    $closure = $listener instanceof WrappedListener ? $listener : $listener(...);
                }
            }
        }

        return $this->optimized[$eventName];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher;

use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;

/**
 * The EventDispatcherInterface is the central point of Symfony's event listener system.
 * Listeners are registered on the manager and events are dispatched through the
 * manager.
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
interface EventDispatcherInterface extends ContractsEventDispatcherInterface
{
    /**
     * Adds an event listener that listens on the specified events.
     *
     * @param int $priority The higher this value, the earlier an event
     *                      listener will be triggered in the chain (defaults to 0)
     *
     * @return void
     */
    public function addListener(string $eventName, callable $listener, int $priority = 0);

    /**
     * Adds an event subscriber.
     *
     * The subscriber is asked for all the events it is
     * interested in and added as a listener for these events.
     *
     * @return void
     */
    public function addSubscriber(EventSubscriberInterface $subscriber);

    /**
     * Removes an event listener from the specified events.
     *
     * @return void
     */
    public function removeListener(string $eventName, callable $listener);

    /**
     * @return void
     */
    public function removeSubscriber(EventSubscriberInterface $subscriber);

    /**
     * Gets the listeners of a specific event or all listeners sorted by descending priority.
     *
     * @return array<callable[]|callable>
     */
    public function getListeners(?string $eventName = null): array;

    /**
     * Gets the listener priority for a specific event.
     *
     * Returns null if the event or the listener does not exist.
     */
    public function getListenerPriority(string $eventName, callable $listener): ?int;

    /**
     * Checks whether an event has any registered listeners.
     */
    public function hasListeners(?string $eventName = null): bool;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher;

/**
 * An EventSubscriber knows itself what events it is interested in.
 * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
 * {@link getSubscribedEvents} and registers the subscriber as a listener for all
 * returned events.
 *
 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author Jonathan Wage <jonwage@gmail.com>
 * @author Roman Borschel <roman@code-factory.org>
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
interface EventSubscriberInterface
{
    /**
     * Returns an array of event names this subscriber wants to listen to.
     *
     * The array keys are event names and the value can be:
     *
     *  * The method name to call (priority defaults to 0)
     *  * An array composed of the method name to call and the priority
     *  * An array of arrays composed of the method names to call and respective
     *    priorities, or 0 if unset
     *
     * For instance:
     *
     *  * ['eventName' => 'methodName']
     *  * ['eventName' => ['methodName', $priority]]
     *  * ['eventName' => [['methodName1', $priority], ['methodName2']]]
     *
     * The code must not depend on runtime state as it will only be called at compile time.
     * All logic depending on runtime state must be put into the individual methods handling the events.
     *
     * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
     */
    public static function getSubscribedEvents();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher;

use Symfony\Contracts\EventDispatcher\Event;

/**
 * Event encapsulation class.
 *
 * Encapsulates events thus decoupling the observer from the subject they encapsulate.
 *
 * @author Drak <drak@zikula.org>
 *
 * @implements \ArrayAccess<string, mixed>
 * @implements \IteratorAggregate<string, mixed>
 */
class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
{
    protected $subject;
    protected $arguments;

    /**
     * Encapsulate an event with $subject and $arguments.
     *
     * @param mixed $subject   The subject of the event, usually an object or a callable
     * @param array $arguments Arguments to store in the event
     */
    public function __construct(mixed $subject = null, array $arguments = [])
    {
        $this->subject = $subject;
        $this->arguments = $arguments;
    }

    /**
     * Getter for subject property.
     */
    public function getSubject(): mixed
    {
        return $this->subject;
    }

    /**
     * Get argument by key.
     *
     * @throws \InvalidArgumentException if key is not found
     */
    public function getArgument(string $key): mixed
    {
        if ($this->hasArgument($key)) {
            return $this->arguments[$key];
        }

        throw new \InvalidArgumentException(\sprintf('Argument "%s" not found.', $key));
    }

    /**
     * Add argument to event.
     *
     * @return $this
     */
    public function setArgument(string $key, mixed $value): static
    {
        $this->arguments[$key] = $value;

        return $this;
    }

    /**
     * Getter for all arguments.
     */
    public function getArguments(): array
    {
        return $this->arguments;
    }

    /**
     * Set args property.
     *
     * @return $this
     */
    public function setArguments(array $args = []): static
    {
        $this->arguments = $args;

        return $this;
    }

    /**
     * Has argument.
     */
    public function hasArgument(string $key): bool
    {
        return \array_key_exists($key, $this->arguments);
    }

    /**
     * ArrayAccess for argument getter.
     *
     * @param string $key Array key
     *
     * @throws \InvalidArgumentException if key does not exist in $this->args
     */
    public function offsetGet(mixed $key): mixed
    {
        return $this->getArgument($key);
    }

    /**
     * ArrayAccess for argument setter.
     *
     * @param string $key Array key to set
     */
    public function offsetSet(mixed $key, mixed $value): void
    {
        $this->setArgument($key, $value);
    }

    /**
     * ArrayAccess for unset argument.
     *
     * @param string $key Array key
     */
    public function offsetUnset(mixed $key): void
    {
        if ($this->hasArgument($key)) {
            unset($this->arguments[$key]);
        }
    }

    /**
     * ArrayAccess has argument.
     *
     * @param string $key Array key
     */
    public function offsetExists(mixed $key): bool
    {
        return $this->hasArgument($key);
    }

    /**
     * IteratorAggregate for iterating over the object like an array.
     *
     * @return \ArrayIterator<string, mixed>
     */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator($this->arguments);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\EventDispatcher;

/**
 * A read-only proxy for an event dispatcher.
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
class ImmutableEventDispatcher implements EventDispatcherInterface
{
    private EventDispatcherInterface $dispatcher;

    public function __construct(EventDispatcherInterface $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    public function dispatch(object $event, ?string $eventName = null): object
    {
        return $this->dispatcher->dispatch($event, $eventName);
    }

    /**
     * @return never
     */
    public function addListener(string $eventName, callable|array $listener, int $priority = 0)
    {
        throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
    }

    /**
     * @return never
     */
    public function addSubscriber(EventSubscriberInterface $subscriber)
    {
        throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
    }

    /**
     * @return never
     */
    public function removeListener(string $eventName, callable|array $listener)
    {
        throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
    }

    /**
     * @return never
     */
    public function removeSubscriber(EventSubscriberInterface $subscriber)
    {
        throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
    }

    public function getListeners(?string $eventName = null): array
    {
        return $this->dispatcher->getListeners($eventName);
    }

    public function getListenerPriority(string $eventName, callable|array $listener): ?int
    {
        return $this->dispatcher->getListenerPriority($eventName, $listener);
    }

    public function hasListeners(?string $eventName = null): bool
    {
        return $this->dispatcher->hasListeners($eventName);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;

/**
 * Event is the base class for classes containing event data.
 *
 * This class contains no event data. It is used by events that do not pass
 * state information to an event handler when an event is raised.
 *
 * You can call the method stopPropagation() to abort the execution of
 * further listeners in your event listener.
 *
 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author Jonathan Wage <jonwage@gmail.com>
 * @author Roman Borschel <roman@code-factory.org>
 * @author Bernhard Schussek <bschussek@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 */
class Event implements StoppableEventInterface
{
    private bool $propagationStopped = false;

    public function isPropagationStopped(): bool
    {
        return $this->propagationStopped;
    }

    /**
     * Stops the propagation of the event to further event listeners.
     *
     * If multiple event listeners are connected to the same event, no
     * further event listener will be triggered once any trigger calls
     * stopPropagation().
     */
    public function stopPropagation(): void
    {
        $this->propagationStopped = true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\EventDispatcher;

use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;

/**
 * Allows providing hooks on domain-specific lifecycles by dispatching events.
 */
interface EventDispatcherInterface extends PsrEventDispatcherInterface
{
    /**
     * Dispatches an event to all registered listeners.
     *
     * @template T of object
     *
     * @param T           $event     The event to pass to the event handlers/listeners
     * @param string|null $eventName The name of the event to dispatch. If not supplied,
     *                               the class of $event should be used instead.
     *
     * @return T The passed $event MUST be returned
     */
    public function dispatch(object $event, ?string $eventName = null): object;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * Exception interface for all exceptions thrown by the component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * Exception class thrown when a file couldn't be found.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Christian Gärtner <christiangaertner.film@googlemail.com>
 */
class FileNotFoundException extends IOException
{
    public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null)
    {
        if (null === $message) {
            if (null === $path) {
                $message = 'File could not be found.';
            } else {
                $message = \sprintf('File "%s" could not be found.', $path);
            }
        }

        parent::__construct($message, $code, $previous, $path);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * @author Christian Flothmann <christian.flothmann@sensiolabs.de>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * Exception class thrown when a filesystem operation failure happens.
 *
 * @author Romain Neutron <imprec@gmail.com>
 * @author Christian Gärtner <christiangaertner.film@googlemail.com>
 * @author Fabien Potencier <fabien@symfony.com>
 */
class IOException extends \RuntimeException implements IOExceptionInterface
{
    private ?string $path;

    public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null)
    {
        $this->path = $path;

        parent::__construct($message, $code, $previous);
    }

    public function getPath(): ?string
    {
        return $this->path;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * IOException interface for file and input/output stream related exceptions thrown by the component.
 *
 * @author Christian Gärtner <christiangaertner.film@googlemail.com>
 */
interface IOExceptionInterface extends ExceptionInterface
{
    /**
     * Returns the associated path for the exception.
     */
    public function getPath(): ?string;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * @author Théo Fidry <theo.fidry@gmail.com>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem;

use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\Filesystem\Exception\InvalidArgumentException;
use Symfony\Component\Filesystem\Exception\IOException;

/**
 * Provides basic utility to manipulate the file system.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Filesystem
{
    private static ?string $lastError = null;

    /**
     * Copies a file.
     *
     * If the target file is older than the origin file, it's always overwritten.
     * If the target file is newer, it is overwritten only when the
     * $overwriteNewerFiles option is set to true.
     *
     * @return void
     *
     * @throws FileNotFoundException When originFile doesn't exist
     * @throws IOException           When copy fails
     */
    public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false)
    {
        $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
        if ($originIsLocal && !is_file($originFile)) {
            throw new FileNotFoundException(\sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
        }

        $this->mkdir(\dirname($targetFile));

        $doCopy = true;
        if (!$overwriteNewerFiles && !parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) {
            $doCopy = filemtime($originFile) > filemtime($targetFile);
        }

        if ($doCopy) {
            // https://bugs.php.net/64634
            if (!$source = self::box('fopen', $originFile, 'r')) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile);
            }

            // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default
            if (!$target = self::box('fopen', $targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile);
            }

            $bytesCopied = stream_copy_to_stream($source, $target);
            fclose($source);
            fclose($target);
            unset($source, $target);

            if (!is_file($targetFile)) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
            }

            if ($originIsLocal) {
                // Like `cp`, preserve executable permission bits
                self::box('chmod', $targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));

                // Like `cp`, preserve the file modification time
                self::box('touch', $targetFile, filemtime($originFile));

                if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
                    throw new IOException(\sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
                }
            }
        }
    }

    /**
     * Creates a directory recursively.
     *
     * @return void
     *
     * @throws IOException On any directory creation failure
     */
    public function mkdir(string|iterable $dirs, int $mode = 0777)
    {
        foreach ($this->toIterable($dirs) as $dir) {
            if (is_dir($dir)) {
                continue;
            }

            if (!self::box('mkdir', $dir, $mode, true) && !is_dir($dir)) {
                throw new IOException(\sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir);
            }
        }
    }

    /**
     * Checks the existence of files or directories.
     */
    public function exists(string|iterable $files): bool
    {
        $maxPathLength = \PHP_MAXPATHLEN - 2;

        foreach ($this->toIterable($files) as $file) {
            if (\strlen($file) > $maxPathLength) {
                throw new IOException(\sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
            }

            if (!file_exists($file)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Sets access and modification time of file.
     *
     * @param int|null $time  The touch time as a Unix timestamp, if not supplied the current system time is used
     * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used
     *
     * @return void
     *
     * @throws IOException When touch fails
     */
    public function touch(string|iterable $files, ?int $time = null, ?int $atime = null)
    {
        foreach ($this->toIterable($files) as $file) {
            if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) {
                throw new IOException(\sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file);
            }
        }
    }

    /**
     * Removes files or directories.
     *
     * @return void
     *
     * @throws IOException When removal fails
     */
    public function remove(string|iterable $files)
    {
        if ($files instanceof \Traversable) {
            $files = iterator_to_array($files, false);
        } elseif (!\is_array($files)) {
            $files = [$files];
        }

        self::doRemove($files, false);
    }

    private static function doRemove(array $files, bool $isRecursive): void
    {
        $files = array_reverse($files);
        foreach ($files as $file) {
            if (is_link($file)) {
                // See https://bugs.php.net/52176
                if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
                    throw new IOException(\sprintf('Failed to remove symlink "%s": ', $file).self::$lastError);
                }
            } elseif (is_dir($file)) {
                if (!$isRecursive) {
                    $tmpName = \dirname(realpath($file)).'/.!'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-!'));

                    if (file_exists($tmpName)) {
                        try {
                            self::doRemove([$tmpName], true);
                        } catch (IOException) {
                        }
                    }

                    if (!file_exists($tmpName) && self::box('rename', $file, $tmpName)) {
                        $origFile = $file;
                        $file = $tmpName;
                    } else {
                        $origFile = null;
                    }
                }

                $filesystemIterator = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS);
                self::doRemove(iterator_to_array($filesystemIterator, true), true);

                if (!self::box('rmdir', $file) && file_exists($file) && !$isRecursive) {
                    $lastError = self::$lastError;

                    if (null !== $origFile && self::box('rename', $file, $origFile)) {
                        $file = $origFile;
                    }

                    throw new IOException(\sprintf('Failed to remove directory "%s": ', $file).$lastError);
                }
            } elseif (!self::box('unlink', $file) && ((self::$lastError && str_contains(self::$lastError, 'Permission denied')) || file_exists($file))) {
                throw new IOException(\sprintf('Failed to remove file "%s": ', $file).self::$lastError);
            }
        }
    }

    /**
     * Change mode for an array of files or directories.
     *
     * @param int  $mode      The new mode (octal)
     * @param int  $umask     The mode mask (octal)
     * @param bool $recursive Whether change the mod recursively or not
     *
     * @return void
     *
     * @throws IOException When the change fails
     */
    public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false)
    {
        foreach ($this->toIterable($files) as $file) {
            if (!self::box('chmod', $file, $mode & ~$umask)) {
                throw new IOException(\sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file);
            }
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
            }
        }
    }

    /**
     * Change the owner of an array of files or directories.
     *
     * This method always throws on Windows, as the underlying PHP function is not supported.
     *
     * @see https://php.net/chown
     *
     * @param string|int $user      A user name or number
     * @param bool       $recursive Whether change the owner recursively or not
     *
     * @return void
     *
     * @throws IOException When the change fails
     */
    public function chown(string|iterable $files, string|int $user, bool $recursive = false)
    {
        foreach ($this->toIterable($files) as $file) {
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chown(new \FilesystemIterator($file), $user, true);
            }
            if (is_link($file) && \function_exists('lchown')) {
                if (!self::box('lchown', $file, $user)) {
                    throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file);
                }
            } else {
                if (!self::box('chown', $file, $user)) {
                    throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file);
                }
            }
        }
    }

    /**
     * Change the group of an array of files or directories.
     *
     * This method always throws on Windows, as the underlying PHP function is not supported.
     *
     * @see https://php.net/chgrp
     *
     * @param string|int $group     A group name or number
     * @param bool       $recursive Whether change the group recursively or not
     *
     * @return void
     *
     * @throws IOException When the change fails
     */
    public function chgrp(string|iterable $files, string|int $group, bool $recursive = false)
    {
        foreach ($this->toIterable($files) as $file) {
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chgrp(new \FilesystemIterator($file), $group, true);
            }
            if (is_link($file) && \function_exists('lchgrp')) {
                if (!self::box('lchgrp', $file, $group)) {
                    throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file);
                }
            } else {
                if (!self::box('chgrp', $file, $group)) {
                    throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file);
                }
            }
        }
    }

    /**
     * Renames a file or a directory.
     *
     * @return void
     *
     * @throws IOException When target file or directory already exists
     * @throws IOException When origin cannot be renamed
     */
    public function rename(string $origin, string $target, bool $overwrite = false)
    {
        // we check that target does not exist
        if (!$overwrite && $this->isReadable($target)) {
            throw new IOException(\sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
        }

        if (!self::box('rename', $origin, $target)) {
            if (is_dir($origin)) {
                // See https://bugs.php.net/54097 & https://php.net/rename#113943
                $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]);
                $this->remove($origin);

                return;
            }
            throw new IOException(\sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target);
        }
    }

    /**
     * Tells whether a file exists and is readable.
     *
     * @throws IOException When windows path is longer than 258 characters
     */
    private function isReadable(string $filename): bool
    {
        $maxPathLength = \PHP_MAXPATHLEN - 2;

        if (\strlen($filename) > $maxPathLength) {
            throw new IOException(\sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
        }

        return is_readable($filename);
    }

    /**
     * Creates a symbolic link or copy a directory.
     *
     * @return void
     *
     * @throws IOException When symlink fails
     */
    public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false)
    {
        self::assertFunctionExists('symlink');

        if ('\\' === \DIRECTORY_SEPARATOR) {
            $originDir = strtr($originDir, '/', '\\');
            $targetDir = strtr($targetDir, '/', '\\');

            if ($copyOnWindows) {
                $this->mirror($originDir, $targetDir);

                return;
            }
        }

        $this->mkdir(\dirname($targetDir));

        if (is_link($targetDir)) {
            if (readlink($targetDir) === $originDir) {
                return;
            }
            $this->remove($targetDir);
        }

        if (!self::box('symlink', $originDir, $targetDir)) {
            $this->linkException($originDir, $targetDir, 'symbolic');
        }
    }

    /**
     * Creates a hard link, or several hard links to a file.
     *
     * @param string|string[] $targetFiles The target file(s)
     *
     * @return void
     *
     * @throws FileNotFoundException When original file is missing or not a file
     * @throws IOException           When link fails, including if link already exists
     */
    public function hardlink(string $originFile, string|iterable $targetFiles)
    {
        self::assertFunctionExists('link');

        if (!$this->exists($originFile)) {
            throw new FileNotFoundException(null, 0, null, $originFile);
        }

        if (!is_file($originFile)) {
            throw new FileNotFoundException(\sprintf('Origin file "%s" is not a file.', $originFile));
        }

        foreach ($this->toIterable($targetFiles) as $targetFile) {
            if (is_file($targetFile)) {
                if (fileinode($originFile) === fileinode($targetFile)) {
                    continue;
                }
                $this->remove($targetFile);
            }

            if (!self::box('link', $originFile, $targetFile)) {
                $this->linkException($originFile, $targetFile, 'hard');
            }
        }
    }

    /**
     * @param string $linkType Name of the link type, typically 'symbolic' or 'hard'
     */
    private function linkException(string $origin, string $target, string $linkType): never
    {
        if (self::$lastError) {
            if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) {
                throw new IOException(\sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
            }
        }
        throw new IOException(\sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target);
    }

    /**
     * Resolves links in paths.
     *
     * With $canonicalize = false (default)
     *      - if $path does not exist or is not a link, returns null
     *      - if $path is a link, returns the next direct target of the link without considering the existence of the target
     *
     * With $canonicalize = true
     *      - if $path does not exist, returns null
     *      - if $path exists, returns its absolute fully resolved final version
     */
    public function readlink(string $path, bool $canonicalize = false): ?string
    {
        if (!$canonicalize && !is_link($path)) {
            return null;
        }

        if ($canonicalize) {
            if (!$this->exists($path)) {
                return null;
            }

            return realpath($path);
        }

        return readlink($path);
    }

    /**
     * Given an existing path, convert it to a path relative to a given starting path.
     */
    public function makePathRelative(string $endPath, string $startPath): string
    {
        if (!$this->isAbsolutePath($startPath)) {
            throw new InvalidArgumentException(\sprintf('The start path "%s" is not absolute.', $startPath));
        }

        if (!$this->isAbsolutePath($endPath)) {
            throw new InvalidArgumentException(\sprintf('The end path "%s" is not absolute.', $endPath));
        }

        // Normalize separators on Windows
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $endPath = str_replace('\\', '/', $endPath);
            $startPath = str_replace('\\', '/', $startPath);
        }

        $splitDriveLetter = fn ($path) => (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0]))
            ? [substr($path, 2), strtoupper($path[0])]
            : [$path, null];

        $splitPath = function ($path) {
            $result = [];

            foreach (explode('/', trim($path, '/')) as $segment) {
                if ('..' === $segment) {
                    array_pop($result);
                } elseif ('.' !== $segment && '' !== $segment) {
                    $result[] = $segment;
                }
            }

            return $result;
        };

        [$endPath, $endDriveLetter] = $splitDriveLetter($endPath);
        [$startPath, $startDriveLetter] = $splitDriveLetter($startPath);

        $startPathArr = $splitPath($startPath);
        $endPathArr = $splitPath($endPath);

        if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
            // End path is on another drive, so no relative path exists
            return $endDriveLetter.':/'.($endPathArr ? implode('/', $endPathArr).'/' : '');
        }

        // Find for which directory the common path stops
        $index = 0;
        while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
            ++$index;
        }

        // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
        if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
            $depth = 0;
        } else {
            $depth = \count($startPathArr) - $index;
        }

        // Repeated "../" for each level need to reach the common path
        $traverser = str_repeat('../', $depth);

        $endPathRemainder = implode('/', \array_slice($endPathArr, $index));

        // Construct $endPath from traversing to the common path, then to the remaining $endPath
        $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');

        return '' === $relativePath ? './' : $relativePath;
    }

    /**
     * Mirrors a directory to another.
     *
     * Copies files and directories from the origin directory into the target directory. By default:
     *
     *  - existing files in the target directory will be overwritten, except if they are newer (see the `override` option)
     *  - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option)
     *
     * @param \Traversable|null $iterator Iterator that filters which files and directories to copy, if null a recursive iterator is created
     * @param array             $options  An array of boolean options
     *                                    Valid options are:
     *                                    - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false)
     *                                    - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false)
     *                                    - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
     *
     * @return void
     *
     * @throws IOException When file type is unknown
     */
    public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = [])
    {
        $targetDir = rtrim($targetDir, '/\\');
        $originDir = rtrim($originDir, '/\\');
        $originDirLen = \strlen($originDir);

        if (!$this->exists($originDir)) {
            throw new IOException(\sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir);
        }

        // Iterate in destination folder to remove obsolete entries
        if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
            $deleteIterator = $iterator;
            if (null === $deleteIterator) {
                $flags = \FilesystemIterator::SKIP_DOTS;
                $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
            }
            $targetDirLen = \strlen($targetDir);
            foreach ($deleteIterator as $file) {
                $origin = $originDir.substr($file->getPathname(), $targetDirLen);
                if (!$this->exists($origin)) {
                    $this->remove($file);
                }
            }
        }

        $copyOnWindows = $options['copy_on_windows'] ?? false;

        if (null === $iterator) {
            $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
            $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
        }

        $this->mkdir($targetDir);
        $filesCreatedWhileMirroring = [];

        foreach ($iterator as $file) {
            if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) {
                continue;
            }

            $target = $targetDir.substr($file->getPathname(), $originDirLen);
            $filesCreatedWhileMirroring[$target] = true;

            if (!$copyOnWindows && is_link($file)) {
                $this->symlink($file->getLinkTarget(), $target);
            } elseif (is_dir($file)) {
                $this->mkdir($target);
            } elseif (is_file($file)) {
                $this->copy($file, $target, $options['override'] ?? false);
            } else {
                throw new IOException(\sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
            }
        }
    }

    /**
     * Returns whether the file path is an absolute path.
     */
    public function isAbsolutePath(string $file): bool
    {
        return '' !== $file && (strspn($file, '/\\', 0, 1)
            || (\strlen($file) > 3 && ctype_alpha($file[0])
                && ':' === $file[1]
                && strspn($file, '/\\', 2, 1)
            )
            || null !== parse_url($file, \PHP_URL_SCHEME)
        );
    }

    /**
     * Creates a temporary file with support for custom stream wrappers.
     *
     * @param string $prefix The prefix of the generated temporary filename
     *                       Note: Windows uses only the first three characters of prefix
     * @param string $suffix The suffix of the generated temporary filename
     *
     * @return string The new temporary filename (with path), or throw an exception on failure
     */
    public function tempnam(string $dir, string $prefix, string $suffix = ''): string
    {
        [$scheme, $hierarchy] = $this->getSchemeAndHierarchy($dir);

        // If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem
        if ((null === $scheme || 'file' === $scheme || 'gs' === $scheme) && '' === $suffix) {
            // If tempnam failed or no scheme return the filename otherwise prepend the scheme
            if ($tmpFile = self::box('tempnam', $hierarchy, $prefix)) {
                if (null !== $scheme && 'gs' !== $scheme) {
                    return $scheme.'://'.$tmpFile;
                }

                return $tmpFile;
            }

            throw new IOException('A temporary file could not be created: '.self::$lastError);
        }

        // Loop until we create a valid temp file or have reached 10 attempts
        for ($i = 0; $i < 10; ++$i) {
            // Create a unique filename
            $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true).$suffix;

            // Use fopen instead of file_exists as some streams do not support stat
            // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability
            if (!$handle = self::box('fopen', $tmpFile, 'x+')) {
                continue;
            }

            // Close the file if it was successfully opened
            self::box('fclose', $handle);

            return $tmpFile;
        }

        throw new IOException('A temporary file could not be created: '.self::$lastError);
    }

    /**
     * Atomically dumps content into a file.
     *
     * @param string|resource $content The data to write into the file
     *
     * @return void
     *
     * @throws IOException if the file cannot be written to
     */
    public function dumpFile(string $filename, $content)
    {
        if (\is_array($content)) {
            throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__));
        }

        $dir = \dirname($filename);

        if (is_link($filename) && $linkTarget = $this->readlink($filename)) {
            $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content);

            return;
        }

        if (!is_dir($dir)) {
            $this->mkdir($dir);
        }

        // Will create a temp file with 0600 access rights
        // when the filesystem supports chmod.
        $tmpFile = $this->tempnam($dir, basename($filename));

        try {
            if (false === self::box('file_put_contents', $tmpFile, $content)) {
                throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename);
            }

            self::box('chmod', $tmpFile, self::box('fileperms', $filename) ?: 0666 & ~umask());

            $this->rename($tmpFile, $filename, true);
        } finally {
            if (file_exists($tmpFile)) {
                if ('\\' === \DIRECTORY_SEPARATOR && !is_writable($tmpFile)) {
                    self::box('chmod', $tmpFile, self::box('fileperms', $tmpFile) | 0200);
                }

                self::box('unlink', $tmpFile);
            }
        }
    }

    /**
     * Appends content to an existing file.
     *
     * @param string|resource $content The content to append
     * @param bool            $lock    Whether the file should be locked when writing to it
     *
     * @return void
     *
     * @throws IOException If the file is not writable
     */
    public function appendToFile(string $filename, $content/* , bool $lock = false */)
    {
        if (\is_array($content)) {
            throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__));
        }

        $dir = \dirname($filename);

        if (!is_dir($dir)) {
            $this->mkdir($dir);
        }

        $lock = \func_num_args() > 2 && func_get_arg(2);

        if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) {
            throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename);
        }
    }

    private function toIterable(string|iterable $files): iterable
    {
        return is_iterable($files) ? $files : [$files];
    }

    /**
     * Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> [file, tmp]).
     */
    private function getSchemeAndHierarchy(string $filename): array
    {
        $components = explode('://', $filename, 2);

        return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]];
    }

    private static function assertFunctionExists(string $func): void
    {
        if (!\function_exists($func)) {
            throw new IOException(\sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func));
        }
    }

    private static function box(string $func, mixed ...$args): mixed
    {
        self::assertFunctionExists($func);

        self::$lastError = null;
        set_error_handler(self::handleError(...));
        try {
            return $func(...$args);
        } finally {
            restore_error_handler();
        }
    }

    /**
     * @internal
     */
    public static function handleError(int $type, string $msg): void
    {
        self::$lastError = $msg;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem;

use Symfony\Component\Filesystem\Exception\InvalidArgumentException;
use Symfony\Component\Filesystem\Exception\RuntimeException;

/**
 * Contains utility methods for handling path strings.
 *
 * The methods in this class are able to deal with both UNIX and Windows paths
 * with both forward and backward slashes. All methods return normalized parts
 * containing only forward slashes and no excess "." and ".." segments.
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 * @author Thomas Schulz <mail@king2500.net>
 * @author Théo Fidry <theo.fidry@gmail.com>
 */
final class Path
{
    /**
     * The number of buffer entries that triggers a cleanup operation.
     */
    private const CLEANUP_THRESHOLD = 1250;

    /**
     * The buffer size after the cleanup operation.
     */
    private const CLEANUP_SIZE = 1000;

    /**
     * Buffers input/output of {@link canonicalize()}.
     *
     * @var array<string, string>
     */
    private static array $buffer = [];

    private static int $bufferSize = 0;

    /**
     * Canonicalizes the given path.
     *
     * During normalization, all slashes are replaced by forward slashes ("/").
     * Furthermore, all "." and ".." segments are removed as far as possible.
     * ".." segments at the beginning of relative paths are not removed.
     *
     * ```php
     * echo Path::canonicalize("\symfony\puli\..\css\style.css");
     * // => /symfony/css/style.css
     *
     * echo Path::canonicalize("../css/./style.css");
     * // => ../css/style.css
     * ```
     *
     * This method is able to deal with both UNIX and Windows paths.
     */
    public static function canonicalize(string $path): string
    {
        if ('' === $path) {
            return '';
        }

        // This method is called by many other methods in this class. Buffer
        // the canonicalized paths to make up for the severe performance
        // decrease.
        if (isset(self::$buffer[$path])) {
            return self::$buffer[$path];
        }

        // Replace "~" with user's home directory.
        if ('~' === $path[0]) {
            $path = self::getHomeDirectory().substr($path, 1);
        }

        $path = self::normalize($path);

        [$root, $pathWithoutRoot] = self::split($path);

        $canonicalParts = self::findCanonicalParts($root, $pathWithoutRoot);

        // Add the root directory again
        self::$buffer[$path] = $canonicalPath = $root.implode('/', $canonicalParts);
        ++self::$bufferSize;

        // Clean up regularly to prevent memory leaks
        if (self::$bufferSize > self::CLEANUP_THRESHOLD) {
            self::$buffer = \array_slice(self::$buffer, -self::CLEANUP_SIZE, null, true);
            self::$bufferSize = self::CLEANUP_SIZE;
        }

        return $canonicalPath;
    }

    /**
     * Normalizes the given path.
     *
     * During normalization, all slashes are replaced by forward slashes ("/").
     * Contrary to {@link canonicalize()}, this method does not remove invalid
     * or dot path segments. Consequently, it is much more efficient and should
     * be used whenever the given path is known to be a valid, absolute system
     * path.
     *
     * This method is able to deal with both UNIX and Windows paths.
     */
    public static function normalize(string $path): string
    {
        return str_replace('\\', '/', $path);
    }

    /**
     * Returns the directory part of the path.
     *
     * This method is similar to PHP's dirname(), but handles various cases
     * where dirname() returns a weird result:
     *
     *  - dirname() does not accept backslashes on UNIX
     *  - dirname("C:/symfony") returns "C:", not "C:/"
     *  - dirname("C:/") returns ".", not "C:/"
     *  - dirname("C:") returns ".", not "C:/"
     *  - dirname("symfony") returns ".", not ""
     *  - dirname() does not canonicalize the result
     *
     * This method fixes these shortcomings and behaves like dirname()
     * otherwise.
     *
     * The result is a canonical path.
     *
     * @return string The canonical directory part. Returns the root directory
     *                if the root directory is passed. Returns an empty string
     *                if a relative path is passed that contains no slashes.
     *                Returns an empty string if an empty string is passed.
     */
    public static function getDirectory(string $path): string
    {
        if ('' === $path) {
            return '';
        }

        $path = self::canonicalize($path);

        // Maintain scheme
        if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
            $scheme = substr($path, 0, $schemeSeparatorPosition + 3);
            $path = substr($path, $schemeSeparatorPosition + 3);
        } else {
            $scheme = '';
        }

        if (false === $dirSeparatorPosition = strrpos($path, '/')) {
            return '';
        }

        // Directory equals root directory "/"
        if (0 === $dirSeparatorPosition) {
            return $scheme.'/';
        }

        // Directory equals Windows root "C:/"
        if (2 === $dirSeparatorPosition && ctype_alpha($path[0]) && ':' === $path[1]) {
            return $scheme.substr($path, 0, 3);
        }

        return $scheme.substr($path, 0, $dirSeparatorPosition);
    }

    /**
     * Returns canonical path of the user's home directory.
     *
     * Supported operating systems:
     *
     *  - UNIX
     *  - Windows8 and upper
     *
     * If your operating system or environment isn't supported, an exception is thrown.
     *
     * The result is a canonical path.
     *
     * @throws RuntimeException If your operating system or environment isn't supported
     */
    public static function getHomeDirectory(): string
    {
        // For UNIX support
        if (getenv('HOME')) {
            return self::canonicalize(getenv('HOME'));
        }

        // For >= Windows8 support
        if (getenv('HOMEDRIVE') && getenv('HOMEPATH')) {
            return self::canonicalize(getenv('HOMEDRIVE').getenv('HOMEPATH'));
        }

        throw new RuntimeException("Cannot find the home directory path: Your environment or operating system isn't supported.");
    }

    /**
     * Returns the root directory of a path.
     *
     * The result is a canonical path.
     *
     * @return string The canonical root directory. Returns an empty string if
     *                the given path is relative or empty.
     */
    public static function getRoot(string $path): string
    {
        if ('' === $path) {
            return '';
        }

        // Maintain scheme
        if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
            $scheme = substr($path, 0, $schemeSeparatorPosition + 3);
            $path = substr($path, $schemeSeparatorPosition + 3);
        } else {
            $scheme = '';
        }

        $firstCharacter = $path[0];

        // UNIX root "/" or "\" (Windows style)
        if ('/' === $firstCharacter || '\\' === $firstCharacter) {
            return $scheme.'/';
        }

        $length = \strlen($path);

        // Windows root
        if ($length > 1 && ':' === $path[1] && ctype_alpha($firstCharacter)) {
            // Special case: "C:"
            if (2 === $length) {
                return $scheme.$path.'/';
            }

            // Normal case: "C:/ or "C:\"
            if ('/' === $path[2] || '\\' === $path[2]) {
                return $scheme.$firstCharacter.$path[1].'/';
            }
        }

        return '';
    }

    /**
     * Returns the file name without the extension from a file path.
     *
     * @param string|null $extension if specified, only that extension is cut
     *                               off (may contain leading dot)
     */
    public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string
    {
        if ('' === $path) {
            return '';
        }

        if (null !== $extension) {
            // remove extension and trailing dot
            return rtrim(basename($path, $extension), '.');
        }

        return pathinfo($path, \PATHINFO_FILENAME);
    }

    /**
     * Returns the extension from a file path (without leading dot).
     *
     * @param bool $forceLowerCase forces the extension to be lower-case
     */
    public static function getExtension(string $path, bool $forceLowerCase = false): string
    {
        if ('' === $path) {
            return '';
        }

        $extension = pathinfo($path, \PATHINFO_EXTENSION);

        if ($forceLowerCase) {
            $extension = self::toLower($extension);
        }

        return $extension;
    }

    /**
     * Returns whether the path has an (or the specified) extension.
     *
     * @param string               $path       the path string
     * @param string|string[]|null $extensions if null or not provided, checks if
     *                                         an extension exists, otherwise
     *                                         checks for the specified extension
     *                                         or array of extensions (with or
     *                                         without leading dot)
     * @param bool                 $ignoreCase whether to ignore case-sensitivity
     */
    public static function hasExtension(string $path, $extensions = null, bool $ignoreCase = false): bool
    {
        if ('' === $path) {
            return false;
        }

        $actualExtension = self::getExtension($path, $ignoreCase);

        // Only check if path has any extension
        if ([] === $extensions || null === $extensions) {
            return '' !== $actualExtension;
        }

        if (\is_string($extensions)) {
            $extensions = [$extensions];
        }

        foreach ($extensions as $key => $extension) {
            if ($ignoreCase) {
                $extension = self::toLower($extension);
            }

            // remove leading '.' in extensions array
            $extensions[$key] = ltrim($extension, '.');
        }

        return \in_array($actualExtension, $extensions, true);
    }

    /**
     * Changes the extension of a path string.
     *
     * @param string $path      The path string with filename.ext to change.
     * @param string $extension new extension (with or without leading dot)
     *
     * @return string the path string with new file extension
     */
    public static function changeExtension(string $path, string $extension): string
    {
        if ('' === $path) {
            return '';
        }

        $actualExtension = self::getExtension($path);
        $extension = ltrim($extension, '.');

        // No extension for paths
        if ('/' === substr($path, -1)) {
            return $path;
        }

        // No actual extension in path
        if (empty($actualExtension)) {
            return $path.('.' === substr($path, -1) ? '' : '.').$extension;
        }

        return substr($path, 0, -\strlen($actualExtension)).$extension;
    }

    public static function isAbsolute(string $path): bool
    {
        if ('' === $path) {
            return false;
        }

        // Strip scheme
        if (false !== ($schemeSeparatorPosition = strpos($path, '://')) && 1 !== $schemeSeparatorPosition) {
            $path = substr($path, $schemeSeparatorPosition + 3);
        }

        $firstCharacter = $path[0];

        // UNIX root "/" or "\" (Windows style)
        if ('/' === $firstCharacter || '\\' === $firstCharacter) {
            return true;
        }

        // Windows root
        if (\strlen($path) > 1 && ctype_alpha($firstCharacter) && ':' === $path[1]) {
            // Special case: "C:"
            if (2 === \strlen($path)) {
                return true;
            }

            // Normal case: "C:/ or "C:\"
            if ('/' === $path[2] || '\\' === $path[2]) {
                return true;
            }
        }

        return false;
    }

    public static function isRelative(string $path): bool
    {
        return !self::isAbsolute($path);
    }

    /**
     * Turns a relative path into an absolute path in canonical form.
     *
     * Usually, the relative path is appended to the given base path. Dot
     * segments ("." and "..") are removed/collapsed and all slashes turned
     * into forward slashes.
     *
     * ```php
     * echo Path::makeAbsolute("../style.css", "/symfony/puli/css");
     * // => /symfony/puli/style.css
     * ```
     *
     * If an absolute path is passed, that path is returned unless its root
     * directory is different than the one of the base path. In that case, an
     * exception is thrown.
     *
     * ```php
     * Path::makeAbsolute("/style.css", "/symfony/puli/css");
     * // => /style.css
     *
     * Path::makeAbsolute("C:/style.css", "C:/symfony/puli/css");
     * // => C:/style.css
     *
     * Path::makeAbsolute("C:/style.css", "/symfony/puli/css");
     * // InvalidArgumentException
     * ```
     *
     * If the base path is not an absolute path, an exception is thrown.
     *
     * The result is a canonical path.
     *
     * @param string $basePath an absolute base path
     *
     * @throws InvalidArgumentException if the base path is not absolute or if
     *                                  the given path is an absolute path with
     *                                  a different root than the base path
     */
    public static function makeAbsolute(string $path, string $basePath): string
    {
        if ('' === $basePath) {
            throw new InvalidArgumentException(\sprintf('The base path must be a non-empty string. Got: "%s".', $basePath));
        }

        if (!self::isAbsolute($basePath)) {
            throw new InvalidArgumentException(\sprintf('The base path "%s" is not an absolute path.', $basePath));
        }

        if (self::isAbsolute($path)) {
            return self::canonicalize($path);
        }

        if (false !== $schemeSeparatorPosition = strpos($basePath, '://')) {
            $scheme = substr($basePath, 0, $schemeSeparatorPosition + 3);
            $basePath = substr($basePath, $schemeSeparatorPosition + 3);
        } else {
            $scheme = '';
        }

        return $scheme.self::canonicalize(rtrim($basePath, '/\\').'/'.$path);
    }

    /**
     * Turns a path into a relative path.
     *
     * The relative path is created relative to the given base path:
     *
     * ```php
     * echo Path::makeRelative("/symfony/style.css", "/symfony/puli");
     * // => ../style.css
     * ```
     *
     * If a relative path is passed and the base path is absolute, the relative
     * path is returned unchanged:
     *
     * ```php
     * Path::makeRelative("style.css", "/symfony/puli/css");
     * // => style.css
     * ```
     *
     * If both paths are relative, the relative path is created with the
     * assumption that both paths are relative to the same directory:
     *
     * ```php
     * Path::makeRelative("style.css", "symfony/puli/css");
     * // => ../../../style.css
     * ```
     *
     * If both paths are absolute, their root directory must be the same,
     * otherwise an exception is thrown:
     *
     * ```php
     * Path::makeRelative("C:/symfony/style.css", "/symfony/puli");
     * // InvalidArgumentException
     * ```
     *
     * If the passed path is absolute, but the base path is not, an exception
     * is thrown as well:
     *
     * ```php
     * Path::makeRelative("/symfony/style.css", "symfony/puli");
     * // InvalidArgumentException
     * ```
     *
     * If the base path is not an absolute path, an exception is thrown.
     *
     * The result is a canonical path.
     *
     * @throws InvalidArgumentException if the base path is not absolute or if
     *                                  the given path has a different root
     *                                  than the base path
     */
    public static function makeRelative(string $path, string $basePath): string
    {
        $path = self::canonicalize($path);
        $basePath = self::canonicalize($basePath);

        [$root, $relativePath] = self::split($path);
        [$baseRoot, $relativeBasePath] = self::split($basePath);

        // If the base path is given as absolute path and the path is already
        // relative, consider it to be relative to the given absolute path
        // already
        if ('' === $root && '' !== $baseRoot) {
            // If base path is already in its root
            if ('' === $relativeBasePath) {
                $relativePath = ltrim($relativePath, './\\');
            }

            return $relativePath;
        }

        // If the passed path is absolute, but the base path is not, we
        // cannot generate a relative path
        if ('' !== $root && '' === $baseRoot) {
            throw new InvalidArgumentException(\sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath));
        }

        // Fail if the roots of the two paths are different
        if ($baseRoot && $root !== $baseRoot) {
            throw new InvalidArgumentException(\sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot));
        }

        if ('' === $relativeBasePath) {
            return $relativePath;
        }

        // Build a "../../" prefix with as many "../" parts as necessary
        $parts = explode('/', $relativePath);
        $baseParts = explode('/', $relativeBasePath);
        $dotDotPrefix = '';

        // Once we found a non-matching part in the prefix, we need to add
        // "../" parts for all remaining parts
        $match = true;

        foreach ($baseParts as $index => $basePart) {
            if ($match && isset($parts[$index]) && $basePart === $parts[$index]) {
                unset($parts[$index]);

                continue;
            }

            $match = false;
            $dotDotPrefix .= '../';
        }

        return rtrim($dotDotPrefix.implode('/', $parts), '/');
    }

    /**
     * Returns whether the given path is on the local filesystem.
     */
    public static function isLocal(string $path): bool
    {
        return '' !== $path && !str_contains($path, '://');
    }

    /**
     * Returns the longest common base path in canonical form of a set of paths or
     * `null` if the paths are on different Windows partitions.
     *
     * Dot segments ("." and "..") are removed/collapsed and all slashes turned
     * into forward slashes.
     *
     * ```php
     * $basePath = Path::getLongestCommonBasePath(
     *     '/symfony/css/style.css',
     *     '/symfony/css/..'
     * );
     * // => /symfony
     * ```
     *
     * The root is returned if no common base path can be found:
     *
     * ```php
     * $basePath = Path::getLongestCommonBasePath(
     *     '/symfony/css/style.css',
     *     '/puli/css/..'
     * );
     * // => /
     * ```
     *
     * If the paths are located on different Windows partitions, `null` is
     * returned.
     *
     * ```php
     * $basePath = Path::getLongestCommonBasePath(
     *     'C:/symfony/css/style.css',
     *     'D:/symfony/css/..'
     * );
     * // => null
     * ```
     */
    public static function getLongestCommonBasePath(string ...$paths): ?string
    {
        [$bpRoot, $basePath] = self::split(self::canonicalize(reset($paths)));

        for (next($paths); null !== key($paths) && '' !== $basePath; next($paths)) {
            [$root, $path] = self::split(self::canonicalize(current($paths)));

            // If we deal with different roots (e.g. C:/ vs. D:/), it's time
            // to quit
            if ($root !== $bpRoot) {
                return null;
            }

            // Make the base path shorter until it fits into path
            while (true) {
                if ('.' === $basePath) {
                    // No more base paths
                    $basePath = '';

                    // next path
                    continue 2;
                }

                // Prevent false positives for common prefixes
                // see isBasePath()
                if (str_starts_with($path.'/', $basePath.'/')) {
                    // next path
                    continue 2;
                }

                $basePath = \dirname($basePath);
            }
        }

        return $bpRoot.$basePath;
    }

    /**
     * Joins two or more path strings into a canonical path.
     */
    public static function join(string ...$paths): string
    {
        $finalPath = null;
        $wasScheme = false;

        foreach ($paths as $path) {
            if ('' === $path) {
                continue;
            }

            if (null === $finalPath) {
                // For first part we keep slashes, like '/top', 'C:\' or 'phar://'
                $finalPath = $path;
                $wasScheme = str_contains($path, '://');
                continue;
            }

            // Only add slash if previous part didn't end with '/' or '\'
            if (!\in_array(substr($finalPath, -1), ['/', '\\'])) {
                $finalPath .= '/';
            }

            // If first part included a scheme like 'phar://' we allow \current part to start with '/', otherwise trim
            $finalPath .= $wasScheme ? $path : ltrim($path, '/');
            $wasScheme = false;
        }

        if (null === $finalPath) {
            return '';
        }

        return self::canonicalize($finalPath);
    }

    /**
     * Returns whether a path is a base path of another path.
     *
     * Dot segments ("." and "..") are removed/collapsed and all slashes turned
     * into forward slashes.
     *
     * ```php
     * Path::isBasePath('/symfony', '/symfony/css');
     * // => true
     *
     * Path::isBasePath('/symfony', '/symfony');
     * // => true
     *
     * Path::isBasePath('/symfony', '/symfony/..');
     * // => false
     *
     * Path::isBasePath('/symfony', '/puli');
     * // => false
     * ```
     */
    public static function isBasePath(string $basePath, string $ofPath): bool
    {
        $basePath = self::canonicalize($basePath);
        $ofPath = self::canonicalize($ofPath);

        // Append slashes to prevent false positives when two paths have
        // a common prefix, for example /base/foo and /base/foobar.
        // Don't append a slash for the root "/", because then that root
        // won't be discovered as common prefix ("//" is not a prefix of
        // "/foobar/").
        return str_starts_with($ofPath.'/', rtrim($basePath, '/').'/');
    }

    /**
     * @return string[]
     */
    private static function findCanonicalParts(string $root, string $pathWithoutRoot): array
    {
        $parts = explode('/', $pathWithoutRoot);

        $canonicalParts = [];

        // Collapse "." and "..", if possible
        foreach ($parts as $part) {
            if ('.' === $part || '' === $part) {
                continue;
            }

            // Collapse ".." with the previous part, if one exists
            // Don't collapse ".." if the previous part is also ".."
            if ('..' === $part && \count($canonicalParts) > 0 && '..' !== $canonicalParts[\count($canonicalParts) - 1]) {
                array_pop($canonicalParts);

                continue;
            }

            // Only add ".." prefixes for relative paths
            if ('..' !== $part || '' === $root) {
                $canonicalParts[] = $part;
            }
        }

        return $canonicalParts;
    }

    /**
     * Splits a canonical path into its root directory and the remainder.
     *
     * If the path has no root directory, an empty root directory will be
     * returned.
     *
     * If the root directory is a Windows style partition, the resulting root
     * will always contain a trailing slash.
     *
     * list ($root, $path) = Path::split("C:/symfony")
     * // => ["C:/", "symfony"]
     *
     * list ($root, $path) = Path::split("C:")
     * // => ["C:/", ""]
     *
     * @return array{string, string} an array with the root directory and the remaining relative path
     */
    private static function split(string $path): array
    {
        if ('' === $path) {
            return ['', ''];
        }

        // Remember scheme as part of the root, if any
        if (false !== $schemeSeparatorPosition = strpos($path, '://')) {
            $root = substr($path, 0, $schemeSeparatorPosition + 3);
            $path = substr($path, $schemeSeparatorPosition + 3);
        } else {
            $root = '';
        }

        $length = \strlen($path);

        // Remove and remember root directory
        if (str_starts_with($path, '/')) {
            $root .= '/';
            $path = $length > 1 ? substr($path, 1) : '';
        } elseif ($length > 1 && ctype_alpha($path[0]) && ':' === $path[1]) {
            if (2 === $length) {
                // Windows special case: "C:"
                $root .= $path.'/';
                $path = '';
            } elseif ('/' === $path[2]) {
                // Windows normal case: "C:/"..
                $root .= substr($path, 0, 3);
                $path = $length > 3 ? substr($path, 3) : '';
            }
        }

        return [$root, $path];
    }

    private static function toLower(string $string): string
    {
        if (false !== $encoding = mb_detect_encoding($string, null, true)) {
            return mb_strtolower($string, $encoding);
        }

        return strtolower($string);
    }

    private function __construct()
    {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\AbstractAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

/**
 * Interface for finder engine implementations.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
 */
abstract class AbstractAdapter implements AdapterInterface
{
    protected $followLinks = false;
    protected $mode = 0;
    protected $minDepth = 0;
    protected $maxDepth = PHP_INT_MAX;
    protected $exclude = array();
    protected $names = array();
    protected $notNames = array();
    protected $contains = array();
    protected $notContains = array();
    protected $sizes = array();
    protected $dates = array();
    protected $filters = array();
    protected $sort = false;
    protected $paths = array();
    protected $notPaths = array();
    protected $ignoreUnreadableDirs = false;

    private static $areSupported = array();

    /**
     * {@inheritdoc}
     */
    public function isSupported()
    {
        $name = $this->getName();

        if (!array_key_exists($name, self::$areSupported)) {
            self::$areSupported[$name] = $this->canBeUsed();
        }

        return self::$areSupported[$name];
    }

    /**
     * {@inheritdoc}
     */
    public function setFollowLinks($followLinks)
    {
        $this->followLinks = $followLinks;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setMode($mode)
    {
        $this->mode = $mode;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setDepths(array $depths)
    {
        $this->minDepth = 0;
        $this->maxDepth = PHP_INT_MAX;

        foreach ($depths as $comparator) {
            switch ($comparator->getOperator()) {
                case '>':
                    $this->minDepth = $comparator->getTarget() + 1;
                    break;
                case '>=':
                    $this->minDepth = $comparator->getTarget();
                    break;
                case '<':
                    $this->maxDepth = $comparator->getTarget() - 1;
                    break;
                case '<=':
                    $this->maxDepth = $comparator->getTarget();
                    break;
                default:
                    $this->minDepth = $this->maxDepth = $comparator->getTarget();
            }
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setExclude(array $exclude)
    {
        $this->exclude = $exclude;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setNames(array $names)
    {
        $this->names = $names;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setNotNames(array $notNames)
    {
        $this->notNames = $notNames;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setContains(array $contains)
    {
        $this->contains = $contains;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setNotContains(array $notContains)
    {
        $this->notContains = $notContains;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setSizes(array $sizes)
    {
        $this->sizes = $sizes;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setDates(array $dates)
    {
        $this->dates = $dates;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setFilters(array $filters)
    {
        $this->filters = $filters;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setSort($sort)
    {
        $this->sort = $sort;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setPath(array $paths)
    {
        $this->paths = $paths;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setNotPath(array $notPaths)
    {
        $this->notPaths = $notPaths;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function ignoreUnreadableDirs($ignore = true)
    {
        $this->ignoreUnreadableDirs = (bool) $ignore;

        return $this;
    }

    /**
     * Returns whether the adapter is supported in the current environment.
     *
     * This method should be implemented in all adapters. Do not implement
     * isSupported in the adapters as the generic implementation provides a cache
     * layer.
     *
     * @see isSupported()
     *
     * @return bool Whether the adapter is supported
     */
    abstract protected function canBeUsed();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\AbstractFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Comparator\DateComparator;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Shell\Shell;

/**
 * Shell engine implementation using GNU find command.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
 */
abstract class AbstractFindAdapter extends AbstractAdapter
{
    protected $shell;

    public function __construct()
    {
        $this->shell = new Shell();
    }

    /**
     * {@inheritdoc}
     */
    public function searchInDirectory($dir)
    {
        // having "/../" in path make find fail
        $dir = realpath($dir);

        // searching directories containing or not containing strings leads to no result
        if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
            return new Iterator\FilePathsIterator(array(), $dir);
        }

        $command = Command::create();
        $find = $this->buildFindCommand($command, $dir);

        if ($this->followLinks) {
            $find->add('-follow');
        }

        $find->add('-mindepth')->add($this->minDepth + 1);

        if (PHP_INT_MAX !== $this->maxDepth) {
            $find->add('-maxdepth')->add($this->maxDepth + 1);
        }

        if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
            $find->add('-type d');
        } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
            $find->add('-type f');
        }

        $this->buildNamesFiltering($find, $this->names);
        $this->buildNamesFiltering($find, $this->notNames, true);
        $this->buildPathsFiltering($find, $dir, $this->paths);
        $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
        $this->buildSizesFiltering($find, $this->sizes);
        $this->buildDatesFiltering($find, $this->dates);

        $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
        $useSort = \is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');

        if ($useGrep && ($this->contains || $this->notContains)) {
            $grep = $command->ins('grep');
            $this->buildContentFiltering($grep, $this->contains);
            $this->buildContentFiltering($grep, $this->notContains, true);
        }

        if ($useSort) {
            $this->buildSorting($command, $this->sort);
        }

        $command->setErrorHandler(
            $this->ignoreUnreadableDirs
                // If directory is unreadable and finder is set to ignore it, `stderr` is ignored.
                ? function ($stderr) { }
                : function ($stderr) { throw new AccessDeniedException($stderr); }
        );

        $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
        $iterator = new Iterator\FilePathsIterator($paths, $dir);

        if ($this->exclude) {
            $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
        }

        if (!$useGrep && ($this->contains || $this->notContains)) {
            $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
        }

        if ($this->filters) {
            $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
        }

        if (!$useSort && $this->sort) {
            $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
            $iterator = $iteratorAggregate->getIterator();
        }

        return $iterator;
    }

    /**
     * {@inheritdoc}
     */
    protected function canBeUsed()
    {
        return $this->shell->testCommand('find');
    }

    /**
     * @param Command $command
     * @param string  $dir
     *
     * @return Command
     */
    protected function buildFindCommand(Command $command, $dir)
    {
        return $command
            ->ins('find')
            ->add('find ')
            ->arg($dir)
            ->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
    }

    /**
     * @param Command  $command
     * @param string[] $names
     * @param bool     $not
     */
    private function buildNamesFiltering(Command $command, array $names, $not = false)
    {
        if (0 === \count($names)) {
            return;
        }

        $command->add($not ? '-not' : null)->cmd('(');

        foreach ($names as $i => $name) {
            $expr = Expression::create($name);

            // Find does not support expandable globs ("*.{a,b}" syntax).
            if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
                $expr = Expression::create($expr->getGlob()->toRegex(false));
            }

            // Fixes 'not search' and 'full path matching' regex problems.
            // - Jokers '.' are replaced by [^/].
            // - We add '[^/]*' before and after regex (if no ^|$ flags are present).
            if ($expr->isRegex()) {
                $regex = $expr->getRegex();
                $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
                    ->setStartFlag(false)
                    ->setStartJoker(true)
                    ->replaceJokers('[^/]');
                if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
                    $regex->setEndJoker(false)->append('[^/]*');
                }
            }

            $command
                ->add($i > 0 ? '-or' : null)
                ->add($expr->isRegex()
                    ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
                    : ($expr->isCaseSensitive() ? '-name' : '-iname')
                )
                ->arg($expr->renderPattern());
        }

        $command->cmd(')');
    }

    /**
     * @param Command  $command
     * @param string   $dir
     * @param string[] $paths
     * @param bool     $not
     */
    private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
    {
        if (0 === \count($paths)) {
            return;
        }

        $command->add($not ? '-not' : null)->cmd('(');

        foreach ($paths as $i => $path) {
            $expr = Expression::create($path);

            // Find does not support expandable globs ("*.{a,b}" syntax).
            if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
                $expr = Expression::create($expr->getGlob()->toRegex(false));
            }

            // Fixes 'not search' regex problems.
            if ($expr->isRegex()) {
                $regex = $expr->getRegex();
                $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).\DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
            } else {
                $expr->prepend('*')->append('*');
            }

            $command
                ->add($i > 0 ? '-or' : null)
                ->add($expr->isRegex()
                    ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
                    : ($expr->isCaseSensitive() ? '-path' : '-ipath')
                )
                ->arg($expr->renderPattern());
        }

        $command->cmd(')');
    }

    /**
     * @param Command            $command
     * @param NumberComparator[] $sizes
     */
    private function buildSizesFiltering(Command $command, array $sizes)
    {
        foreach ($sizes as $i => $size) {
            $command->add($i > 0 ? '-and' : null);

            switch ($size->getOperator()) {
                case '<=':
                    $command->add('-size -'.($size->getTarget() + 1).'c');
                    break;
                case '>=':
                    $command->add('-size +'.($size->getTarget() - 1).'c');
                    break;
                case '>':
                    $command->add('-size +'.$size->getTarget().'c');
                    break;
                case '!=':
                    $command->add('-size -'.$size->getTarget().'c');
                    $command->add('-size +'.$size->getTarget().'c');
                    break;
                case '<':
                default:
                    $command->add('-size -'.$size->getTarget().'c');
            }
        }
    }

    /**
     * @param Command          $command
     * @param DateComparator[] $dates
     */
    private function buildDatesFiltering(Command $command, array $dates)
    {
        foreach ($dates as $i => $date) {
            $command->add($i > 0 ? '-and' : null);

            $mins = (int) round((time() - $date->getTarget()) / 60);

            if (0 > $mins) {
                // mtime is in the future
                $command->add(' -mmin -0');
                // we will have no result so we don't need to continue
                return;
            }

            switch ($date->getOperator()) {
                case '<=':
                    $command->add('-mmin +'.($mins - 1));
                    break;
                case '>=':
                    $command->add('-mmin -'.($mins + 1));
                    break;
                case '>':
                    $command->add('-mmin -'.$mins);
                    break;
                case '!=':
                    $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
                    break;
                case '<':
                default:
                    $command->add('-mmin +'.$mins);
            }
        }
    }

    /**
     * @param Command $command
     * @param string  $sort
     *
     * @throws \InvalidArgumentException
     */
    private function buildSorting(Command $command, $sort)
    {
        $this->buildFormatSorting($command, $sort);
    }

    /**
     * @param Command $command
     * @param string  $sort
     */
    abstract protected function buildFormatSorting(Command $command, $sort);

    /**
     * @param Command $command
     * @param array   $contains
     * @param bool    $not
     */
    abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
interface AdapterInterface
{
    /**
     * @param bool $followLinks
     *
     * @return $this
     */
    public function setFollowLinks($followLinks);

    /**
     * @param int $mode
     *
     * @return $this
     */
    public function setMode($mode);

    /**
     * @return $this
     */
    public function setExclude(array $exclude);

    /**
     * @return $this
     */
    public function setDepths(array $depths);

    /**
     * @return $this
     */
    public function setNames(array $names);

    /**
     * @return $this
     */
    public function setNotNames(array $notNames);

    /**
     * @return $this
     */
    public function setContains(array $contains);

    /**
     * @return $this
     */
    public function setNotContains(array $notContains);

    /**
     * @return $this
     */
    public function setSizes(array $sizes);

    /**
     * @return $this
     */
    public function setDates(array $dates);

    /**
     * @return $this
     */
    public function setFilters(array $filters);

    /**
     * @param \Closure|int $sort
     *
     * @return $this
     */
    public function setSort($sort);

    /**
     * @return $this
     */
    public function setPath(array $paths);

    /**
     * @return $this
     */
    public function setNotPath(array $notPaths);

    /**
     * @param bool $ignore
     *
     * @return $this
     */
    public function ignoreUnreadableDirs($ignore = true);

    /**
     * @param string $dir
     *
     * @return \Iterator Result iterator
     */
    public function searchInDirectory($dir);

    /**
     * Tests adapter support for current platform.
     *
     * @return bool
     */
    public function isSupported();

    /**
     * Returns adapter name.
     *
     * @return string
     */
    public function getName();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\BsdFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Shell\Shell;

/**
 * Shell engine implementation using BSD find command.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
 */
class BsdFindAdapter extends AbstractFindAdapter
{
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'bsd_find';
    }

    /**
     * {@inheritdoc}
     */
    protected function canBeUsed()
    {
        return \in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
    }

    /**
     * {@inheritdoc}
     */
    protected function buildFormatSorting(Command $command, $sort)
    {
        switch ($sort) {
            case SortableIterator::SORT_BY_NAME:
                $command->ins('sort')->add('| sort');

                return;
            case SortableIterator::SORT_BY_TYPE:
                $format = '%HT';
                break;
            case SortableIterator::SORT_BY_ACCESSED_TIME:
                $format = '%a';
                break;
            case SortableIterator::SORT_BY_CHANGED_TIME:
                $format = '%c';
                break;
            case SortableIterator::SORT_BY_MODIFIED_TIME:
                $format = '%m';
                break;
            default:
                throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
        }

        $command
            ->add('-print0 | xargs -0 stat -f')
            ->arg($format.'%t%N')
            ->add('| sort | cut -f 2');
    }

    /**
     * {@inheritdoc}
     */
    protected function buildFindCommand(Command $command, $dir)
    {
        parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);

        return $command;
    }

    /**
     * {@inheritdoc}
     */
    protected function buildContentFiltering(Command $command, array $contains, $not = false)
    {
        foreach ($contains as $contain) {
            $expr = Expression::create($contain);

            // todo: avoid forking process for each $pattern by using multiple -e options
            $command
                ->add('| grep -v \'^$\'')
                ->add('| xargs -I{} grep -I')
                ->add($expr->isCaseSensitive() ? null : '-i')
                ->add($not ? '-L' : '-l')
                ->add('-Ee')->arg($expr->renderPattern())
                ->add('{}')
            ;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\GnuFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Shell\Shell;

/**
 * Shell engine implementation using GNU find command.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
 */
class GnuFindAdapter extends AbstractFindAdapter
{
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'gnu_find';
    }

    /**
     * {@inheritdoc}
     */
    protected function buildFormatSorting(Command $command, $sort)
    {
        switch ($sort) {
            case SortableIterator::SORT_BY_NAME:
                $command->ins('sort')->add('| sort');

                return;
            case SortableIterator::SORT_BY_TYPE:
                $format = '%y';
                break;
            case SortableIterator::SORT_BY_ACCESSED_TIME:
                $format = '%A@';
                break;
            case SortableIterator::SORT_BY_CHANGED_TIME:
                $format = '%C@';
                break;
            case SortableIterator::SORT_BY_MODIFIED_TIME:
                $format = '%T@';
                break;
            default:
                throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
        }

        $command
            ->get('find')
            ->add('-printf')
            ->arg($format.' %h/%f\\n')
            ->add('| sort | cut')
            ->arg('-d ')
            ->arg('-f2-')
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function canBeUsed()
    {
        return Shell::TYPE_UNIX === $this->shell->getType() && parent::canBeUsed();
    }

    /**
     * {@inheritdoc}
     */
    protected function buildFindCommand(Command $command, $dir)
    {
        return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
    }

    /**
     * {@inheritdoc}
     */
    protected function buildContentFiltering(Command $command, array $contains, $not = false)
    {
        foreach ($contains as $contain) {
            $expr = Expression::create($contain);

            // todo: avoid forking process for each $pattern by using multiple -e options
            $command
                ->add('| xargs -I{} -r grep -I')
                ->add($expr->isCaseSensitive() ? null : '-i')
                ->add($not ? '-L' : '-l')
                ->add('-Ee')->arg($expr->renderPattern())
                ->add('{}')
            ;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\PhpAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Iterator;

/**
 * PHP finder engine implementation.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
 */
class PhpAdapter extends AbstractAdapter
{
    /**
     * {@inheritdoc}
     */
    public function searchInDirectory($dir)
    {
        $flags = \RecursiveDirectoryIterator::SKIP_DOTS;

        if ($this->followLinks) {
            $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
        }

        $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);

        if ($this->exclude) {
            $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
        }

        $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);

        if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
            $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
        }

        if ($this->mode) {
            $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
        }

        if ($this->names || $this->notNames) {
            $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
        }

        if ($this->contains || $this->notContains) {
            $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
        }

        if ($this->sizes) {
            $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
        }

        if ($this->dates) {
            $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
        }

        if ($this->filters) {
            $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
        }

        if ($this->paths || $this->notPaths) {
            $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
        }

        if ($this->sort) {
            $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
            $iterator = $iteratorAggregate->getIterator();
        }

        return $iterator;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'php';
    }

    /**
     * {@inheritdoc}
     */
    protected function canBeUsed()
    {
        return true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Comparator;

/**
 * Comparator.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Comparator
{
    private $target;
    private $operator = '==';

    /**
     * Gets the target value.
     *
     * @return string The target value
     */
    public function getTarget()
    {
        return $this->target;
    }

    /**
     * Sets the target value.
     *
     * @param string $target The target value
     */
    public function setTarget($target)
    {
        $this->target = $target;
    }

    /**
     * Gets the comparison operator.
     *
     * @return string The operator
     */
    public function getOperator()
    {
        return $this->operator;
    }

    /**
     * Sets the comparison operator.
     *
     * @param string $operator A valid operator
     *
     * @throws \InvalidArgumentException
     */
    public function setOperator($operator)
    {
        if (!$operator) {
            $operator = '==';
        }

        if (!\in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
            throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
        }

        $this->operator = $operator;
    }

    /**
     * Tests against the target.
     *
     * @param mixed $test A test value
     *
     * @return bool
     */
    public function test($test)
    {
        switch ($this->operator) {
            case '>':
                return $test > $this->target;
            case '>=':
                return $test >= $this->target;
            case '<':
                return $test < $this->target;
            case '<=':
                return $test <= $this->target;
            case '!=':
                return $test != $this->target;
        }

        return $test == $this->target;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Comparator;

/**
 * DateCompare compiles date comparisons.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DateComparator extends Comparator
{
    /**
     * @param string $test A comparison string
     *
     * @throws \InvalidArgumentException If the test is not understood
     */
    public function __construct($test)
    {
        if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
            throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
        }

        try {
            $date = new \DateTime($matches[2]);
            $target = $date->format('U');
        } catch (\Exception $e) {
            throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
        }

        $operator = isset($matches[1]) ? $matches[1] : '==';
        if ('since' === $operator || 'after' === $operator) {
            $operator = '>';
        }

        if ('until' === $operator || 'before' === $operator) {
            $operator = '<';
        }

        $this->setOperator($operator);
        $this->setTarget($target);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Comparator;

/**
 * NumberComparator compiles a simple comparison to an anonymous
 * subroutine, which you can call with a value to be tested again.
 *
 * Now this would be very pointless, if NumberCompare didn't understand
 * magnitudes.
 *
 * The target value may use magnitudes of kilobytes (k, ki),
 * megabytes (m, mi), or gigabytes (g, gi).  Those suffixed
 * with an i use the appropriate 2**n version in accordance with the
 * IEC standard: http://physics.nist.gov/cuu/Units/binary.html
 *
 * Based on the Perl Number::Compare module.
 *
 * @author    Fabien Potencier <fabien@symfony.com> PHP port
 * @author    Richard Clamp <richardc@unixbeard.net> Perl version
 * @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
 * @copyright 2002 Richard Clamp <richardc@unixbeard.net>
 *
 * @see http://physics.nist.gov/cuu/Units/binary.html
 */
class NumberComparator extends Comparator
{
    /**
     * @param string|int $test A comparison string or an integer
     *
     * @throws \InvalidArgumentException If the test is not understood
     */
    public function __construct($test)
    {
        if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
            throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
        }

        $target = $matches[2];
        if (!is_numeric($target)) {
            throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
        }
        if (isset($matches[3])) {
            // magnitude
            switch (strtolower($matches[3])) {
                case 'k':
                    $target *= 1000;
                    break;
                case 'ki':
                    $target *= 1024;
                    break;
                case 'm':
                    $target *= 1000000;
                    break;
                case 'mi':
                    $target *= 1024 * 1024;
                    break;
                case 'g':
                    $target *= 1000000000;
                    break;
                case 'gi':
                    $target *= 1024 * 1024 * 1024;
                    break;
            }
        }

        $this->setTarget($target);
        $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Exception;

/**
 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
 */
class AccessDeniedException extends \UnexpectedValueException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Adapter\AdapterInterface;

/**
 * Base exception for all adapter failures.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class AdapterFailureException extends \RuntimeException implements ExceptionInterface
{
    private $adapter;

    /**
     * @param AdapterInterface $adapter
     * @param string|null      $message
     * @param \Exception|null  $previous
     */
    public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
    {
        $this->adapter = $adapter;
        parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
    }

    /**
     * {@inheritdoc}
     */
    public function getAdapter()
    {
        return $this->adapter;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Exception;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
interface ExceptionInterface
{
    /**
     * @return \Symfony\Component\Finder\Adapter\AdapterInterface
     */
    public function getAdapter();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class OperationNotPermitedException extends AdapterFailureException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Shell\Command;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class ShellCommandFailureException extends AdapterFailureException
{
    private $command;

    public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
    {
        $this->command = $command;
        parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
    }

    /**
     * @return Command
     */
    public function getCommand()
    {
        return $this->command;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class Expression implements ValueInterface
{
    const TYPE_REGEX = 1;
    const TYPE_GLOB = 2;

    /**
     * @var ValueInterface
     */
    private $value;

    /**
     * @param string $expr
     *
     * @return self
     */
    public static function create($expr)
    {
        return new self($expr);
    }

    /**
     * @param string $expr
     */
    public function __construct($expr)
    {
        try {
            $this->value = Regex::create($expr);
        } catch (\InvalidArgumentException $e) {
            $this->value = new Glob($expr);
        }
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return $this->render();
    }

    /**
     * {@inheritdoc}
     */
    public function render()
    {
        return $this->value->render();
    }

    /**
     * {@inheritdoc}
     */
    public function renderPattern()
    {
        return $this->value->renderPattern();
    }

    /**
     * @return bool
     */
    public function isCaseSensitive()
    {
        return $this->value->isCaseSensitive();
    }

    /**
     * @return int
     */
    public function getType()
    {
        return $this->value->getType();
    }

    /**
     * {@inheritdoc}
     */
    public function prepend($expr)
    {
        $this->value->prepend($expr);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function append($expr)
    {
        $this->value->append($expr);

        return $this;
    }

    /**
     * @return bool
     */
    public function isRegex()
    {
        return self::TYPE_REGEX === $this->value->getType();
    }

    /**
     * @return bool
     */
    public function isGlob()
    {
        return self::TYPE_GLOB === $this->value->getType();
    }

    /**
     * @return Glob
     *
     * @throws \LogicException
     */
    public function getGlob()
    {
        if (self::TYPE_GLOB !== $this->value->getType()) {
            throw new \LogicException('Regex can\'t be transformed to glob.');
        }

        return $this->value;
    }

    /**
     * @return Regex
     */
    public function getRegex()
    {
        return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Glob as FinderGlob;

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class Glob implements ValueInterface
{
    private $pattern;

    /**
     * @param string $pattern
     */
    public function __construct($pattern)
    {
        $this->pattern = $pattern;
    }

    /**
     * {@inheritdoc}
     */
    public function render()
    {
        return $this->pattern;
    }

    /**
     * {@inheritdoc}
     */
    public function renderPattern()
    {
        return $this->pattern;
    }

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return Expression::TYPE_GLOB;
    }

    /**
     * {@inheritdoc}
     */
    public function isCaseSensitive()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function prepend($expr)
    {
        $this->pattern = $expr.$this->pattern;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function append($expr)
    {
        $this->pattern .= $expr;

        return $this;
    }

    /**
     * Tests if glob is expandable ("*.{a,b}" syntax).
     *
     * @return bool
     */
    public function isExpandable()
    {
        return false !== strpos($this->pattern, '{')
            && false !== strpos($this->pattern, '}');
    }

    /**
     * @param bool $strictLeadingDot
     * @param bool $strictWildcardSlash
     *
     * @return Regex
     */
    public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
    {
        $regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');

        return new Regex($regex);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
class Regex implements ValueInterface
{
    const START_FLAG = '^';
    const END_FLAG = '$';
    const BOUNDARY = '~';
    const JOKER = '.*';
    const ESCAPING = '\\';

    /**
     * @var string
     */
    private $pattern;

    /**
     * @var string
     */
    private $options;

    /**
     * @var bool
     */
    private $startFlag;

    /**
     * @var bool
     */
    private $endFlag;

    /**
     * @var bool
     */
    private $startJoker;

    /**
     * @var bool
     */
    private $endJoker;

    /**
     * @param string $expr
     *
     * @return self
     *
     * @throws \InvalidArgumentException
     */
    public static function create($expr)
    {
        if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
            $start = substr($m[1], 0, 1);
            $end = substr($m[1], -1);

            if (
                ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
                || ('{' === $start && '}' === $end)
                || ('(' === $start && ')' === $end)
            ) {
                return new self(substr($m[1], 1, -1), $m[2], $end);
            }
        }

        throw new \InvalidArgumentException('Given expression is not a regex.');
    }

    /**
     * @param string $pattern
     * @param string $options
     * @param string $delimiter
     */
    public function __construct($pattern, $options = '', $delimiter = null)
    {
        if (null !== $delimiter) {
            // removes delimiter escaping
            $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
        }

        $this->parsePattern($pattern);
        $this->options = $options;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return $this->render();
    }

    /**
     * {@inheritdoc}
     */
    public function render()
    {
        return self::BOUNDARY
            .$this->renderPattern()
            .self::BOUNDARY
            .$this->options;
    }

    /**
     * {@inheritdoc}
     */
    public function renderPattern()
    {
        return ($this->startFlag ? self::START_FLAG : '')
            .($this->startJoker ? self::JOKER : '')
            .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
            .($this->endJoker ? self::JOKER : '')
            .($this->endFlag ? self::END_FLAG : '');
    }

    /**
     * {@inheritdoc}
     */
    public function isCaseSensitive()
    {
        return !$this->hasOption('i');
    }

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return Expression::TYPE_REGEX;
    }

    /**
     * {@inheritdoc}
     */
    public function prepend($expr)
    {
        $this->pattern = $expr.$this->pattern;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function append($expr)
    {
        $this->pattern .= $expr;

        return $this;
    }

    /**
     * @param string $option
     *
     * @return bool
     */
    public function hasOption($option)
    {
        return false !== strpos($this->options, $option);
    }

    /**
     * @param string $option
     *
     * @return $this
     */
    public function addOption($option)
    {
        if (!$this->hasOption($option)) {
            $this->options .= $option;
        }

        return $this;
    }

    /**
     * @param string $option
     *
     * @return $this
     */
    public function removeOption($option)
    {
        $this->options = str_replace($option, '', $this->options);

        return $this;
    }

    /**
     * @param bool $startFlag
     *
     * @return $this
     */
    public function setStartFlag($startFlag)
    {
        $this->startFlag = $startFlag;

        return $this;
    }

    /**
     * @return bool
     */
    public function hasStartFlag()
    {
        return $this->startFlag;
    }

    /**
     * @param bool $endFlag
     *
     * @return $this
     */
    public function setEndFlag($endFlag)
    {
        $this->endFlag = (bool) $endFlag;

        return $this;
    }

    /**
     * @return bool
     */
    public function hasEndFlag()
    {
        return $this->endFlag;
    }

    /**
     * @param bool $startJoker
     *
     * @return $this
     */
    public function setStartJoker($startJoker)
    {
        $this->startJoker = $startJoker;

        return $this;
    }

    /**
     * @return bool
     */
    public function hasStartJoker()
    {
        return $this->startJoker;
    }

    /**
     * @param bool $endJoker
     *
     * @return $this
     */
    public function setEndJoker($endJoker)
    {
        $this->endJoker = (bool) $endJoker;

        return $this;
    }

    /**
     * @return bool
     */
    public function hasEndJoker()
    {
        return $this->endJoker;
    }

    /**
     * @return $this
     */
    public function replaceJokers($replacement)
    {
        $replace = function ($subject) use ($replacement) {
            $subject = $subject[0];
            $replace = 0 === substr_count($subject, '\\') % 2;

            return $replace ? str_replace('.', $replacement, $subject) : $subject;
        };

        $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);

        return $this;
    }

    /**
     * @param string $pattern
     */
    private function parsePattern($pattern)
    {
        if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
            $pattern = substr($pattern, 1);
        }

        if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
            $pattern = substr($pattern, 2);
        }

        if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
            $pattern = substr($pattern, 0, -1);
        }

        if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
            $pattern = substr($pattern, 0, -2);
        }

        $this->pattern = $pattern;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 */
interface ValueInterface
{
    /**
     * Renders string representation of expression.
     *
     * @return string
     */
    public function render();

    /**
     * Renders string representation of pattern.
     *
     * @return string
     */
    public function renderPattern();

    /**
     * Returns value case sensitivity.
     *
     * @return bool
     */
    public function isCaseSensitive();

    /**
     * Returns expression type.
     *
     * @return int
     */
    public function getType();

    /**
     * @param string $expr
     *
     * @return $this
     */
    public function prepend($expr);

    /**
     * @param string $expr
     *
     * @return $this
     */
    public function append($expr);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder;

use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Adapter\BsdFindAdapter;
use Symfony\Component\Finder\Adapter\GnuFindAdapter;
use Symfony\Component\Finder\Adapter\PhpAdapter;
use Symfony\Component\Finder\Comparator\DateComparator;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Exception\ExceptionInterface;
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
use Symfony\Component\Finder\Iterator\SortableIterator;

/**
 * Finder allows to build rules to find files and directories.
 *
 * It is a thin wrapper around several specialized iterator classes.
 *
 * All rules may be invoked several times.
 *
 * All methods return the current Finder object to allow easy chaining:
 *
 *     $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Finder implements \IteratorAggregate, \Countable
{
    const IGNORE_VCS_FILES = 1;
    const IGNORE_DOT_FILES = 2;

    private $mode = 0;
    private $names = array();
    private $notNames = array();
    private $exclude = array();
    private $filters = array();
    private $depths = array();
    private $sizes = array();
    private $followLinks = false;
    private $sort = false;
    private $ignore = 0;
    private $dirs = array();
    private $dates = array();
    private $iterators = array();
    private $contains = array();
    private $notContains = array();
    private $adapters = null;
    private $paths = array();
    private $notPaths = array();
    private $ignoreUnreadableDirs = false;

    private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');

    public function __construct()
    {
        $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
    }

    /**
     * Creates a new Finder.
     *
     * @return static
     */
    public static function create()
    {
        return new static();
    }

    /**
     * Registers a finder engine implementation.
     *
     * @param AdapterInterface $adapter  An adapter instance
     * @param int              $priority Highest is selected first
     *
     * @return $this
     *
     * @deprecated since 2.8, to be removed in 3.0.
     */
    public function addAdapter(AdapterInterface $adapter, $priority = 0)
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

        $this->initDefaultAdapters();

        $this->adapters[$adapter->getName()] = array(
            'adapter' => $adapter,
            'priority' => $priority,
            'selected' => false,
        );

        return $this->sortAdapters();
    }

    /**
     * Sets the selected adapter to the best one according to the current platform the code is run on.
     *
     * @return $this
     *
     * @deprecated since 2.8, to be removed in 3.0.
     */
    public function useBestAdapter()
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

        $this->initDefaultAdapters();

        $this->resetAdapterSelection();

        return $this->sortAdapters();
    }

    /**
     * Selects the adapter to use.
     *
     * @param string $name
     *
     * @return $this
     *
     * @throws \InvalidArgumentException
     *
     * @deprecated since 2.8, to be removed in 3.0.
     */
    public function setAdapter($name)
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

        $this->initDefaultAdapters();

        if (!isset($this->adapters[$name])) {
            throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
        }

        $this->resetAdapterSelection();
        $this->adapters[$name]['selected'] = true;

        return $this->sortAdapters();
    }

    /**
     * Removes all adapters registered in the finder.
     *
     * @return $this
     *
     * @deprecated since 2.8, to be removed in 3.0.
     */
    public function removeAdapters()
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

        $this->adapters = array();

        return $this;
    }

    /**
     * Returns registered adapters ordered by priority without extra information.
     *
     * @return AdapterInterface[]
     *
     * @deprecated since 2.8, to be removed in 3.0.
     */
    public function getAdapters()
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

        $this->initDefaultAdapters();

        return array_values(array_map(function (array $adapter) {
            return $adapter['adapter'];
        }, $this->adapters));
    }

    /**
     * Restricts the matching to directories only.
     *
     * @return $this
     */
    public function directories()
    {
        $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;

        return $this;
    }

    /**
     * Restricts the matching to files only.
     *
     * @return $this
     */
    public function files()
    {
        $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;

        return $this;
    }

    /**
     * Adds tests for the directory depth.
     *
     * Usage:
     *
     *     $finder->depth('> 1') // the Finder will start matching at level 1.
     *     $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
     *
     * @param string|int $level The depth level expression
     *
     * @return $this
     *
     * @see DepthRangeFilterIterator
     * @see NumberComparator
     */
    public function depth($level)
    {
        $this->depths[] = new Comparator\NumberComparator($level);

        return $this;
    }

    /**
     * Adds tests for file dates (last modified).
     *
     * The date must be something that strtotime() is able to parse:
     *
     *     $finder->date('since yesterday');
     *     $finder->date('until 2 days ago');
     *     $finder->date('> now - 2 hours');
     *     $finder->date('>= 2005-10-15');
     *
     * @param string $date A date range string
     *
     * @return $this
     *
     * @see strtotime
     * @see DateRangeFilterIterator
     * @see DateComparator
     */
    public function date($date)
    {
        $this->dates[] = new Comparator\DateComparator($date);

        return $this;
    }

    /**
     * Adds rules that files must match.
     *
     * You can use patterns (delimited with / sign), globs or simple strings.
     *
     *     $finder->name('*.php')
     *     $finder->name('/\.php$/') // same as above
     *     $finder->name('test.php')
     *
     * @param string $pattern A pattern (a regexp, a glob, or a string)
     *
     * @return $this
     *
     * @see FilenameFilterIterator
     */
    public function name($pattern)
    {
        $this->names[] = $pattern;

        return $this;
    }

    /**
     * Adds rules that files must not match.
     *
     * @param string $pattern A pattern (a regexp, a glob, or a string)
     *
     * @return $this
     *
     * @see FilenameFilterIterator
     */
    public function notName($pattern)
    {
        $this->notNames[] = $pattern;

        return $this;
    }

    /**
     * Adds tests that file contents must match.
     *
     * Strings or PCRE patterns can be used:
     *
     *     $finder->contains('Lorem ipsum')
     *     $finder->contains('/Lorem ipsum/i')
     *
     * @param string $pattern A pattern (string or regexp)
     *
     * @return $this
     *
     * @see FilecontentFilterIterator
     */
    public function contains($pattern)
    {
        $this->contains[] = $pattern;

        return $this;
    }

    /**
     * Adds tests that file contents must not match.
     *
     * Strings or PCRE patterns can be used:
     *
     *     $finder->notContains('Lorem ipsum')
     *     $finder->notContains('/Lorem ipsum/i')
     *
     * @param string $pattern A pattern (string or regexp)
     *
     * @return $this
     *
     * @see FilecontentFilterIterator
     */
    public function notContains($pattern)
    {
        $this->notContains[] = $pattern;

        return $this;
    }

    /**
     * Adds rules that filenames must match.
     *
     * You can use patterns (delimited with / sign) or simple strings.
     *
     *     $finder->path('some/special/dir')
     *     $finder->path('/some\/special\/dir/') // same as above
     *
     * Use only / as dirname separator.
     *
     * @param string $pattern A pattern (a regexp or a string)
     *
     * @return $this
     *
     * @see FilenameFilterIterator
     */
    public function path($pattern)
    {
        $this->paths[] = $pattern;

        return $this;
    }

    /**
     * Adds rules that filenames must not match.
     *
     * You can use patterns (delimited with / sign) or simple strings.
     *
     *     $finder->notPath('some/special/dir')
     *     $finder->notPath('/some\/special\/dir/') // same as above
     *
     * Use only / as dirname separator.
     *
     * @param string $pattern A pattern (a regexp or a string)
     *
     * @return $this
     *
     * @see FilenameFilterIterator
     */
    public function notPath($pattern)
    {
        $this->notPaths[] = $pattern;

        return $this;
    }

    /**
     * Adds tests for file sizes.
     *
     *     $finder->size('> 10K');
     *     $finder->size('<= 1Ki');
     *     $finder->size(4);
     *
     * @param string|int $size A size range string or an integer
     *
     * @return $this
     *
     * @see SizeRangeFilterIterator
     * @see NumberComparator
     */
    public function size($size)
    {
        $this->sizes[] = new Comparator\NumberComparator($size);

        return $this;
    }

    /**
     * Excludes directories.
     *
     * Directories passed as argument must be relative to the ones defined with the `in()` method. For example:
     *
     *     $finder->in(__DIR__)->exclude('ruby');
     *
     * @param string|array $dirs A directory path or an array of directories
     *
     * @return $this
     *
     * @see ExcludeDirectoryFilterIterator
     */
    public function exclude($dirs)
    {
        $this->exclude = array_merge($this->exclude, (array) $dirs);

        return $this;
    }

    /**
     * Excludes "hidden" directories and files (starting with a dot).
     *
     * This option is enabled by default.
     *
     * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
     *
     * @return $this
     *
     * @see ExcludeDirectoryFilterIterator
     */
    public function ignoreDotFiles($ignoreDotFiles)
    {
        if ($ignoreDotFiles) {
            $this->ignore |= static::IGNORE_DOT_FILES;
        } else {
            $this->ignore &= ~static::IGNORE_DOT_FILES;
        }

        return $this;
    }

    /**
     * Forces the finder to ignore version control directories.
     *
     * This option is enabled by default.
     *
     * @param bool $ignoreVCS Whether to exclude VCS files or not
     *
     * @return $this
     *
     * @see ExcludeDirectoryFilterIterator
     */
    public function ignoreVCS($ignoreVCS)
    {
        if ($ignoreVCS) {
            $this->ignore |= static::IGNORE_VCS_FILES;
        } else {
            $this->ignore &= ~static::IGNORE_VCS_FILES;
        }

        return $this;
    }

    /**
     * Adds VCS patterns.
     *
     * @see ignoreVCS()
     *
     * @param string|string[] $pattern VCS patterns to ignore
     */
    public static function addVCSPattern($pattern)
    {
        foreach ((array) $pattern as $p) {
            self::$vcsPatterns[] = $p;
        }

        self::$vcsPatterns = array_unique(self::$vcsPatterns);
    }

    /**
     * Sorts files and directories by an anonymous function.
     *
     * The anonymous function receives two \SplFileInfo instances to compare.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sort(\Closure $closure)
    {
        $this->sort = $closure;

        return $this;
    }

    /**
     * Sorts files and directories by name.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sortByName()
    {
        $this->sort = Iterator\SortableIterator::SORT_BY_NAME;

        return $this;
    }

    /**
     * Sorts files and directories by type (directories before files), then by name.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sortByType()
    {
        $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;

        return $this;
    }

    /**
     * Sorts files and directories by the last accessed time.
     *
     * This is the time that the file was last accessed, read or written to.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sortByAccessedTime()
    {
        $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;

        return $this;
    }

    /**
     * Sorts files and directories by the last inode changed time.
     *
     * This is the time that the inode information was last modified (permissions, owner, group or other metadata).
     *
     * On Windows, since inode is not available, changed time is actually the file creation time.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sortByChangedTime()
    {
        $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;

        return $this;
    }

    /**
     * Sorts files and directories by the last modified time.
     *
     * This is the last time the actual contents of the file were last modified.
     *
     * This can be slow as all the matching files and directories must be retrieved for comparison.
     *
     * @return $this
     *
     * @see SortableIterator
     */
    public function sortByModifiedTime()
    {
        $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;

        return $this;
    }

    /**
     * Filters the iterator with an anonymous function.
     *
     * The anonymous function receives a \SplFileInfo and must return false
     * to remove files.
     *
     * @return $this
     *
     * @see CustomFilterIterator
     */
    public function filter(\Closure $closure)
    {
        $this->filters[] = $closure;

        return $this;
    }

    /**
     * Forces the following of symlinks.
     *
     * @return $this
     */
    public function followLinks()
    {
        $this->followLinks = true;

        return $this;
    }

    /**
     * Tells finder to ignore unreadable directories.
     *
     * By default, scanning unreadable directories content throws an AccessDeniedException.
     *
     * @param bool $ignore
     *
     * @return $this
     */
    public function ignoreUnreadableDirs($ignore = true)
    {
        $this->ignoreUnreadableDirs = (bool) $ignore;

        return $this;
    }

    /**
     * Searches files and directories which match defined rules.
     *
     * @param string|array $dirs A directory path or an array of directories
     *
     * @return $this
     *
     * @throws \InvalidArgumentException if one of the directories does not exist
     */
    public function in($dirs)
    {
        $resolvedDirs = array();

        foreach ((array) $dirs as $dir) {
            if (is_dir($dir)) {
                $resolvedDirs[] = $this->normalizeDir($dir);
            } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
                $resolvedDirs = array_merge($resolvedDirs, array_map(array($this, 'normalizeDir'), $glob));
            } else {
                throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
            }
        }

        $this->dirs = array_merge($this->dirs, $resolvedDirs);

        return $this;
    }

    /**
     * Returns an Iterator for the current Finder configuration.
     *
     * This method implements the IteratorAggregate interface.
     *
     * @return \Iterator|SplFileInfo[] An iterator
     *
     * @throws \LogicException if the in() method has not been called
     */
    public function getIterator()
    {
        if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
            throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
        }

        if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
            return $this->searchInDirectory($this->dirs[0]);
        }

        $iterator = new \AppendIterator();
        foreach ($this->dirs as $dir) {
            $iterator->append($this->searchInDirectory($dir));
        }

        foreach ($this->iterators as $it) {
            $iterator->append($it);
        }

        return $iterator;
    }

    /**
     * Appends an existing set of files/directories to the finder.
     *
     * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
     *
     * @param iterable $iterator
     *
     * @return $this
     *
     * @throws \InvalidArgumentException when the given argument is not iterable
     */
    public function append($iterator)
    {
        if ($iterator instanceof \IteratorAggregate) {
            $this->iterators[] = $iterator->getIterator();
        } elseif ($iterator instanceof \Iterator) {
            $this->iterators[] = $iterator;
        } elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
            $it = new \ArrayIterator();
            foreach ($iterator as $file) {
                $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
            }
            $this->iterators[] = $it;
        } else {
            throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
        }

        return $this;
    }

    /**
     * Counts all the results collected by the iterators.
     *
     * @return int
     */
    public function count()
    {
        return iterator_count($this->getIterator());
    }

    /**
     * @return $this
     */
    private function sortAdapters()
    {
        uasort($this->adapters, function (array $a, array $b) {
            if ($a['selected'] || $b['selected']) {
                return $a['selected'] ? -1 : 1;
            }

            return $a['priority'] > $b['priority'] ? -1 : 1;
        });

        return $this;
    }

    /**
     * @param string $dir
     *
     * @return \Iterator
     */
    private function searchInDirectory($dir)
    {
        if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
            $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
        }

        if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
            $this->notPaths[] = '#(^|/)\..+(/|$)#';
        }

        if ($this->adapters) {
            foreach ($this->adapters as $adapter) {
                if ($adapter['adapter']->isSupported()) {
                    try {
                        return $this
                            ->buildAdapter($adapter['adapter'])
                            ->searchInDirectory($dir);
                    } catch (ExceptionInterface $e) {
                    }
                }
            }
        }

        $minDepth = 0;
        $maxDepth = PHP_INT_MAX;

        foreach ($this->depths as $comparator) {
            switch ($comparator->getOperator()) {
                case '>':
                    $minDepth = $comparator->getTarget() + 1;
                    break;
                case '>=':
                    $minDepth = $comparator->getTarget();
                    break;
                case '<':
                    $maxDepth = $comparator->getTarget() - 1;
                    break;
                case '<=':
                    $maxDepth = $comparator->getTarget();
                    break;
                default:
                    $minDepth = $maxDepth = $comparator->getTarget();
            }
        }

        $flags = \RecursiveDirectoryIterator::SKIP_DOTS;

        if ($this->followLinks) {
            $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
        }

        $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);

        if ($this->exclude) {
            $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
        }

        $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);

        if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
            $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
        }

        if ($this->mode) {
            $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
        }

        if ($this->names || $this->notNames) {
            $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
        }

        if ($this->contains || $this->notContains) {
            $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
        }

        if ($this->sizes) {
            $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
        }

        if ($this->dates) {
            $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
        }

        if ($this->filters) {
            $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
        }

        if ($this->paths || $this->notPaths) {
            $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
        }

        if ($this->sort) {
            $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
            $iterator = $iteratorAggregate->getIterator();
        }

        return $iterator;
    }

    /**
     * @return AdapterInterface
     */
    private function buildAdapter(AdapterInterface $adapter)
    {
        return $adapter
            ->setFollowLinks($this->followLinks)
            ->setDepths($this->depths)
            ->setMode($this->mode)
            ->setExclude($this->exclude)
            ->setNames($this->names)
            ->setNotNames($this->notNames)
            ->setContains($this->contains)
            ->setNotContains($this->notContains)
            ->setSizes($this->sizes)
            ->setDates($this->dates)
            ->setFilters($this->filters)
            ->setSort($this->sort)
            ->setPath($this->paths)
            ->setNotPath($this->notPaths)
            ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
    }

    /**
     * Unselects all adapters.
     */
    private function resetAdapterSelection()
    {
        $this->adapters = array_map(function (array $properties) {
            $properties['selected'] = false;

            return $properties;
        }, $this->adapters);
    }

    private function initDefaultAdapters()
    {
        if (null === $this->adapters) {
            $this->adapters = array();
            $this
                ->addAdapter(new GnuFindAdapter())
                ->addAdapter(new BsdFindAdapter())
                ->addAdapter(new PhpAdapter(), -50)
                ->setAdapter('php')
            ;
        }
    }

    /**
     * Normalizes given directory names by removing trailing slashes.
     *
     * @param string $dir
     *
     * @return string
     */
    private function normalizeDir($dir)
    {
        return rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder;

/**
 * Glob matches globbing patterns against text.
 *
 *     if match_glob("foo.*", "foo.bar") echo "matched\n";
 *
 *     // prints foo.bar and foo.baz
 *     $regex = glob_to_regex("foo.*");
 *     for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
 *     {
 *         if (/$regex/) echo "matched: $car\n";
 *     }
 *
 * Glob implements glob(3) style matching that can be used to match
 * against text, rather than fetching names from a filesystem.
 *
 * Based on the Perl Text::Glob module.
 *
 * @author Fabien Potencier <fabien@symfony.com> PHP port
 * @author     Richard Clamp <richardc@unixbeard.net> Perl version
 * @copyright  2004-2005 Fabien Potencier <fabien@symfony.com>
 * @copyright  2002 Richard Clamp <richardc@unixbeard.net>
 */
class Glob
{
    /**
     * Returns a regexp which is the equivalent of the glob pattern.
     *
     * @param string $glob                The glob pattern
     * @param bool   $strictLeadingDot
     * @param bool   $strictWildcardSlash
     * @param string $delimiter           Optional delimiter
     *
     * @return string regex The regexp
     */
    public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
    {
        $firstByte = true;
        $escaping = false;
        $inCurlies = 0;
        $regex = '';
        $sizeGlob = \strlen($glob);
        for ($i = 0; $i < $sizeGlob; ++$i) {
            $car = $glob[$i];
            if ($firstByte) {
                if ($strictLeadingDot && '.' !== $car) {
                    $regex .= '(?=[^\.])';
                }

                $firstByte = false;
            }

            if ('/' === $car) {
                $firstByte = true;
            }

            if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
                $regex .= "\\$car";
            } elseif ('*' === $car) {
                $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
            } elseif ('?' === $car) {
                $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
            } elseif ('{' === $car) {
                $regex .= $escaping ? '\\{' : '(';
                if (!$escaping) {
                    ++$inCurlies;
                }
            } elseif ('}' === $car && $inCurlies) {
                $regex .= $escaping ? '}' : ')';
                if (!$escaping) {
                    --$inCurlies;
                }
            } elseif (',' === $car && $inCurlies) {
                $regex .= $escaping ? ',' : '|';
            } elseif ('\\' === $car) {
                if ($escaping) {
                    $regex .= '\\\\';
                    $escaping = false;
                } else {
                    $escaping = true;
                }

                continue;
            } else {
                $regex .= $car;
            }
            $escaping = false;
        }

        return $delimiter.'^'.$regex.'$'.$delimiter;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * CustomFilterIterator filters files by applying anonymous functions.
 *
 * The anonymous function receives a \SplFileInfo and must return false
 * to remove files.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class CustomFilterIterator extends FilterIterator
{
    private $filters = array();

    /**
     * @param \Iterator  $iterator The Iterator to filter
     * @param callable[] $filters  An array of PHP callbacks
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(\Iterator $iterator, array $filters)
    {
        foreach ($filters as $filter) {
            if (!\is_callable($filter)) {
                throw new \InvalidArgumentException('Invalid PHP callback.');
            }
        }
        $this->filters = $filters;

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        $fileinfo = $this->current();

        foreach ($this->filters as $filter) {
            if (false === \call_user_func($filter, $fileinfo)) {
                return false;
            }
        }

        return true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Comparator\DateComparator;

/**
 * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DateRangeFilterIterator extends FilterIterator
{
    private $comparators = array();

    /**
     * @param \Iterator        $iterator    The Iterator to filter
     * @param DateComparator[] $comparators An array of DateComparator instances
     */
    public function __construct(\Iterator $iterator, array $comparators)
    {
        $this->comparators = $comparators;

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        $fileinfo = $this->current();

        if (!file_exists($fileinfo->getPathname())) {
            return false;
        }

        $filedate = $fileinfo->getMTime();
        foreach ($this->comparators as $compare) {
            if (!$compare->test($filedate)) {
                return false;
            }
        }

        return true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * DepthRangeFilterIterator limits the directory depth.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DepthRangeFilterIterator extends FilterIterator
{
    private $minDepth = 0;

    /**
     * @param \RecursiveIteratorIterator $iterator The Iterator to filter
     * @param int                        $minDepth The min depth
     * @param int                        $maxDepth The max depth
     */
    public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
    {
        $this->minDepth = $minDepth;
        $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        return $this->getInnerIterator()->getDepth() >= $this->minDepth;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * ExcludeDirectoryFilterIterator filters out directories.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
{
    private $iterator;
    private $isRecursive;
    private $excludedDirs = array();
    private $excludedPattern;

    /**
     * @param \Iterator $iterator    The Iterator to filter
     * @param array     $directories An array of directories to exclude
     */
    public function __construct(\Iterator $iterator, array $directories)
    {
        $this->iterator = $iterator;
        $this->isRecursive = $iterator instanceof \RecursiveIterator;
        $patterns = array();
        foreach ($directories as $directory) {
            $directory = rtrim($directory, '/');
            if (!$this->isRecursive || false !== strpos($directory, '/')) {
                $patterns[] = preg_quote($directory, '#');
            } else {
                $this->excludedDirs[$directory] = true;
            }
        }
        if ($patterns) {
            $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
        }

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool True if the value should be kept, false otherwise
     */
    public function accept()
    {
        if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
            return false;
        }

        if ($this->excludedPattern) {
            $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
            $path = str_replace('\\', '/', $path);

            return !preg_match($this->excludedPattern, $path);
        }

        return true;
    }

    public function hasChildren()
    {
        return $this->isRecursive && $this->iterator->hasChildren();
    }

    public function getChildren()
    {
        $children = new self($this->iterator->getChildren(), array());
        $children->excludedDirs = $this->excludedDirs;
        $children->excludedPattern = $this->excludedPattern;

        return $children;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
 *
 * @author Fabien Potencier  <fabien@symfony.com>
 * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
 */
class FilecontentFilterIterator extends MultiplePcreFilterIterator
{
    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        if (!$this->matchRegexps && !$this->noMatchRegexps) {
            return true;
        }

        $fileinfo = $this->current();

        if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
            return false;
        }

        $content = $fileinfo->getContents();
        if (!$content) {
            return false;
        }

        return $this->isAccepted($content);
    }

    /**
     * Converts string to regexp if necessary.
     *
     * @param string $str Pattern: string or regexp
     *
     * @return string regexp corresponding to a given string or regexp
     */
    protected function toRegex($str)
    {
        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Glob;

/**
 * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FilenameFilterIterator extends MultiplePcreFilterIterator
{
    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        return $this->isAccepted($this->current()->getFilename());
    }

    /**
     * Converts glob to regexp.
     *
     * PCRE patterns are left unchanged.
     * Glob strings are transformed with Glob::toRegex().
     *
     * @param string $str Pattern: glob or regexp
     *
     * @return string regexp corresponding to a given glob or regexp
     */
    protected function toRegex($str)
    {
        return $this->isRegex($str) ? $str : Glob::toRegex($str);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

@trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\SplFileInfo;

/**
 * Iterate over shell command result.
 *
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class FilePathsIterator extends \ArrayIterator
{
    /**
     * @var string
     */
    private $baseDir;

    /**
     * @var int
     */
    private $baseDirLength;

    /**
     * @var string
     */
    private $subPath;

    /**
     * @var string
     */
    private $subPathname;

    /**
     * @var SplFileInfo
     */
    private $current;

    /**
     * @param array  $paths   List of paths returned by shell command
     * @param string $baseDir Base dir for relative path building
     */
    public function __construct(array $paths, $baseDir)
    {
        $this->baseDir = $baseDir;
        $this->baseDirLength = \strlen($baseDir);

        parent::__construct($paths);
    }

    /**
     * @param string $name
     * @param array  $arguments
     *
     * @return mixed
     */
    public function __call($name, array $arguments)
    {
        return \call_user_func_array(array($this->current(), $name), $arguments);
    }

    /**
     * Return an instance of SplFileInfo with support for relative paths.
     *
     * @return SplFileInfo File information
     */
    public function current()
    {
        return $this->current;
    }

    /**
     * @return string
     */
    public function key()
    {
        return $this->current->getPathname();
    }

    public function next()
    {
        parent::next();
        $this->buildProperties();
    }

    public function rewind()
    {
        parent::rewind();
        $this->buildProperties();
    }

    /**
     * @return string
     */
    public function getSubPath()
    {
        return $this->subPath;
    }

    /**
     * @return string
     */
    public function getSubPathname()
    {
        return $this->subPathname;
    }

    private function buildProperties()
    {
        $absolutePath = parent::current();

        if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
            $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
            $dir = \dirname($this->subPathname);
            $this->subPath = '.' === $dir ? '' : $dir;
        } else {
            $this->subPath = $this->subPathname = '';
        }

        $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * FileTypeFilterIterator only keeps files, directories, or both.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FileTypeFilterIterator extends FilterIterator
{
    const ONLY_FILES = 1;
    const ONLY_DIRECTORIES = 2;

    private $mode;

    /**
     * @param \Iterator $iterator The Iterator to filter
     * @param int       $mode     The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
     */
    public function __construct(\Iterator $iterator, $mode)
    {
        $this->mode = $mode;

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        $fileinfo = $this->current();
        if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
            return false;
        } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
            return false;
        }

        return true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * This iterator just overrides the rewind method in order to correct a PHP bug,
 * which existed before version 5.5.23/5.6.7.
 *
 * @see https://bugs.php.net/68557
 *
 * @author Alex Bogomazov
 */
abstract class FilterIterator extends \FilterIterator
{
    /**
     * This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after
     * rewind in some cases.
     *
     * @see FilterIterator::rewind()
     */
    public function rewind()
    {
        if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) {
            parent::rewind();

            return;
        }

        $iterator = $this;
        while ($iterator instanceof \OuterIterator) {
            $innerIterator = $iterator->getInnerIterator();

            if ($innerIterator instanceof RecursiveDirectoryIterator) {
                // this condition is necessary for iterators to work properly with non-local filesystems like ftp
                if ($innerIterator->isRewindable()) {
                    $innerIterator->next();
                    $innerIterator->rewind();
                }
            } elseif ($innerIterator instanceof \FilesystemIterator) {
                $innerIterator->next();
                $innerIterator->rewind();
            }

            $iterator = $innerIterator;
        }

        parent::rewind();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class MultiplePcreFilterIterator extends FilterIterator
{
    protected $matchRegexps = array();
    protected $noMatchRegexps = array();

    /**
     * @param \Iterator $iterator        The Iterator to filter
     * @param array     $matchPatterns   An array of patterns that need to match
     * @param array     $noMatchPatterns An array of patterns that need to not match
     */
    public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
    {
        foreach ($matchPatterns as $pattern) {
            $this->matchRegexps[] = $this->toRegex($pattern);
        }

        foreach ($noMatchPatterns as $pattern) {
            $this->noMatchRegexps[] = $this->toRegex($pattern);
        }

        parent::__construct($iterator);
    }

    /**
     * Checks whether the string is accepted by the regex filters.
     *
     * If there is no regexps defined in the class, this method will accept the string.
     * Such case can be handled by child classes before calling the method if they want to
     * apply a different behavior.
     *
     * @param string $string The string to be matched against filters
     *
     * @return bool
     */
    protected function isAccepted($string)
    {
        // should at least not match one rule to exclude
        foreach ($this->noMatchRegexps as $regex) {
            if (preg_match($regex, $string)) {
                return false;
            }
        }

        // should at least match one rule
        if ($this->matchRegexps) {
            foreach ($this->matchRegexps as $regex) {
                if (preg_match($regex, $string)) {
                    return true;
                }
            }

            return false;
        }

        // If there is no match rules, the file is accepted
        return true;
    }

    /**
     * Checks whether the string is a regex.
     *
     * @param string $str
     *
     * @return bool Whether the given string is a regex
     */
    protected function isRegex($str)
    {
        if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
            $start = substr($m[1], 0, 1);
            $end = substr($m[1], -1);

            if ($start === $end) {
                return !preg_match('/[*?[:alnum:] \\\\]/', $start);
            }

            foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
                if ($start === $delimiters[0] && $end === $delimiters[1]) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Converts string into regexp.
     *
     * @param string $str Pattern
     *
     * @return string regexp corresponding to a given string
     */
    abstract protected function toRegex($str);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * PathFilterIterator filters files by path patterns (e.g. some/special/dir).
 *
 * @author Fabien Potencier  <fabien@symfony.com>
 * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
 */
class PathFilterIterator extends MultiplePcreFilterIterator
{
    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        $filename = $this->current()->getRelativePathname();

        if ('\\' === \DIRECTORY_SEPARATOR) {
            $filename = str_replace('\\', '/', $filename);
        }

        return $this->isAccepted($filename);
    }

    /**
     * Converts strings to regexp.
     *
     * PCRE patterns are left unchanged.
     *
     * Default conversion:
     *     'lorem/ipsum/dolor' ==>  'lorem\/ipsum\/dolor/'
     *
     * Use only / as directory separator (on Windows also).
     *
     * @param string $str Pattern: regexp or dirname
     *
     * @return string regexp corresponding to a given string or regexp
     */
    protected function toRegex($str)
    {
        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Extends the \RecursiveDirectoryIterator to support relative paths.
 *
 * @author Victor Berchet <victor@suumit.com>
 */
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
    /**
     * @var bool
     */
    private $ignoreUnreadableDirs;

    /**
     * @var bool
     */
    private $rewindable;

    // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
    private $rootPath;
    private $subPath;
    private $directorySeparator = '/';

    /**
     * @param string $path
     * @param int    $flags
     * @param bool   $ignoreUnreadableDirs
     *
     * @throws \RuntimeException
     */
    public function __construct($path, $flags, $ignoreUnreadableDirs = false)
    {
        if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
            throw new \RuntimeException('This iterator only support returning current as fileinfo.');
        }

        parent::__construct($path, $flags);
        $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
        $this->rootPath = (string) $path;
        if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
            $this->directorySeparator = \DIRECTORY_SEPARATOR;
        }
    }

    /**
     * Return an instance of SplFileInfo with support for relative paths.
     *
     * @return SplFileInfo File information
     */
    public function current()
    {
        // the logic here avoids redoing the same work in all iterations

        if (null === $subPathname = $this->subPath) {
            $subPathname = $this->subPath = (string) $this->getSubPath();
        }
        if ('' !== $subPathname) {
            $subPathname .= $this->directorySeparator;
        }
        $subPathname .= $this->getFilename();

        return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
    }

    /**
     * @return \RecursiveIterator
     *
     * @throws AccessDeniedException
     */
    public function getChildren()
    {
        try {
            $children = parent::getChildren();

            if ($children instanceof self) {
                // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
                $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;

                // performance optimization to avoid redoing the same work in all children
                $children->rewindable = &$this->rewindable;
                $children->rootPath = $this->rootPath;
            }

            return $children;
        } catch (\UnexpectedValueException $e) {
            if ($this->ignoreUnreadableDirs) {
                // If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
                return new \RecursiveArrayIterator(array());
            } else {
                throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
            }
        }
    }

    /**
     * Do nothing for non rewindable stream.
     */
    public function rewind()
    {
        if (false === $this->isRewindable()) {
            return;
        }

        // @see https://bugs.php.net/68557
        if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) {
            parent::next();
        }

        parent::rewind();
    }

    /**
     * Checks if the stream is rewindable.
     *
     * @return bool true when the stream is rewindable, false otherwise
     */
    public function isRewindable()
    {
        if (null !== $this->rewindable) {
            return $this->rewindable;
        }

        // workaround for an HHVM bug, should be removed when https://github.com/facebook/hhvm/issues/7281 is fixed
        if ('' === $this->getPath()) {
            return $this->rewindable = false;
        }

        if (false !== $stream = @opendir($this->getPath())) {
            $infos = stream_get_meta_data($stream);
            closedir($stream);

            if ($infos['seekable']) {
                return $this->rewindable = true;
            }
        }

        return $this->rewindable = false;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Comparator\NumberComparator;

/**
 * SizeRangeFilterIterator filters out files that are not in the given size range.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SizeRangeFilterIterator extends FilterIterator
{
    private $comparators = array();

    /**
     * @param \Iterator          $iterator    The Iterator to filter
     * @param NumberComparator[] $comparators An array of NumberComparator instances
     */
    public function __construct(\Iterator $iterator, array $comparators)
    {
        $this->comparators = $comparators;

        parent::__construct($iterator);
    }

    /**
     * Filters the iterator values.
     *
     * @return bool true if the value should be kept, false otherwise
     */
    public function accept()
    {
        $fileinfo = $this->current();
        if (!$fileinfo->isFile()) {
            return true;
        }

        $filesize = $fileinfo->getSize();
        foreach ($this->comparators as $compare) {
            if (!$compare->test($filesize)) {
                return false;
            }
        }

        return true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Iterator;

/**
 * SortableIterator applies a sort on a given Iterator.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SortableIterator implements \IteratorAggregate
{
    const SORT_BY_NAME = 1;
    const SORT_BY_TYPE = 2;
    const SORT_BY_ACCESSED_TIME = 3;
    const SORT_BY_CHANGED_TIME = 4;
    const SORT_BY_MODIFIED_TIME = 5;

    private $iterator;
    private $sort;

    /**
     * @param \Traversable $iterator The Iterator to filter
     * @param int|callable $sort     The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(\Traversable $iterator, $sort)
    {
        $this->iterator = $iterator;

        if (self::SORT_BY_NAME === $sort) {
            $this->sort = function ($a, $b) {
                return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
            };
        } elseif (self::SORT_BY_TYPE === $sort) {
            $this->sort = function ($a, $b) {
                if ($a->isDir() && $b->isFile()) {
                    return -1;
                } elseif ($a->isFile() && $b->isDir()) {
                    return 1;
                }

                return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname());
            };
        } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
            $this->sort = function ($a, $b) {
                return $a->getATime() - $b->getATime();
            };
        } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
            $this->sort = function ($a, $b) {
                return $a->getCTime() - $b->getCTime();
            };
        } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
            $this->sort = function ($a, $b) {
                return $a->getMTime() - $b->getMTime();
            };
        } elseif (\is_callable($sort)) {
            $this->sort = $sort;
        } else {
            throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
        }
    }

    public function getIterator()
    {
        $array = iterator_to_array($this->iterator, true);
        uasort($array, $this->sort);

        return new \ArrayIterator($array);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Shell;

@trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class Command
{
    private $parent;
    private $bits = array();
    private $labels = array();

    /**
     * @var \Closure|null
     */
    private $errorHandler;

    public function __construct(Command $parent = null)
    {
        $this->parent = $parent;
    }

    /**
     * Returns command as string.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->join();
    }

    /**
     * Creates a new Command instance.
     *
     * @return self
     */
    public static function create(Command $parent = null)
    {
        return new self($parent);
    }

    /**
     * Escapes special chars from input.
     *
     * @param string $input A string to escape
     *
     * @return string The escaped string
     */
    public static function escape($input)
    {
        return escapeshellcmd($input);
    }

    /**
     * Quotes input.
     *
     * @param string $input An argument string
     *
     * @return string The quoted string
     */
    public static function quote($input)
    {
        return escapeshellarg($input);
    }

    /**
     * Appends a string or a Command instance.
     *
     * @param string|Command $bit
     *
     * @return $this
     */
    public function add($bit)
    {
        $this->bits[] = $bit;

        return $this;
    }

    /**
     * Prepends a string or a command instance.
     *
     * @param string|Command $bit
     *
     * @return $this
     */
    public function top($bit)
    {
        array_unshift($this->bits, $bit);

        foreach ($this->labels as $label => $index) {
            ++$this->labels[$label];
        }

        return $this;
    }

    /**
     * Appends an argument, will be quoted.
     *
     * @param string $arg
     *
     * @return $this
     */
    public function arg($arg)
    {
        $this->bits[] = self::quote($arg);

        return $this;
    }

    /**
     * Appends escaped special command chars.
     *
     * @param string $esc
     *
     * @return $this
     */
    public function cmd($esc)
    {
        $this->bits[] = self::escape($esc);

        return $this;
    }

    /**
     * Inserts a labeled command to feed later.
     *
     * @param string $label The unique label
     *
     * @return self|string
     *
     * @throws \RuntimeException If label already exists
     */
    public function ins($label)
    {
        if (isset($this->labels[$label])) {
            throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
        }

        $this->bits[] = self::create($this);
        $this->labels[$label] = \count($this->bits) - 1;

        return $this->bits[$this->labels[$label]];
    }

    /**
     * Retrieves a previously labeled command.
     *
     * @param string $label
     *
     * @return self|string
     *
     * @throws \RuntimeException
     */
    public function get($label)
    {
        if (!isset($this->labels[$label])) {
            throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
        }

        return $this->bits[$this->labels[$label]];
    }

    /**
     * Returns parent command (if any).
     *
     * @return self
     *
     * @throws \RuntimeException If command has no parent
     */
    public function end()
    {
        if (null === $this->parent) {
            throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
        }

        return $this->parent;
    }

    /**
     * Counts bits stored in command.
     *
     * @return int The bits count
     */
    public function length()
    {
        return \count($this->bits);
    }

    /**
     * @return $this
     */
    public function setErrorHandler(\Closure $errorHandler)
    {
        $this->errorHandler = $errorHandler;

        return $this;
    }

    /**
     * @return \Closure|null
     */
    public function getErrorHandler()
    {
        return $this->errorHandler;
    }

    /**
     * Executes current command.
     *
     * @return array The command result
     *
     * @throws \RuntimeException
     */
    public function execute()
    {
        if (null === $errorHandler = $this->errorHandler) {
            exec($this->join(), $output);
        } else {
            $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
            $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);

            if ($error = stream_get_contents($pipes[2])) {
                $errorHandler($error);
            }

            proc_close($process);
        }

        return $output ?: array();
    }

    /**
     * Joins bits.
     *
     * @return string
     */
    public function join()
    {
        return implode(' ', array_filter(
            array_map(function ($bit) {
                return $bit instanceof Command ? $bit->join() : ($bit ?: null);
            }, $this->bits),
            function ($bit) { return null !== $bit; }
        ));
    }

    /**
     * Insert a string or a Command instance before the bit at given position $index (index starts from 0).
     *
     * @param string|Command $bit
     * @param int            $index
     *
     * @return $this
     */
    public function addAtIndex($bit, $index)
    {
        array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);

        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder\Shell;

@trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

/**
 * @author Jean-François Simon <contact@jfsimon.fr>
 *
 * @deprecated since 2.8, to be removed in 3.0.
 */
class Shell
{
    const TYPE_UNIX = 1;
    const TYPE_DARWIN = 2;
    const TYPE_CYGWIN = 3;
    const TYPE_WINDOWS = 4;
    const TYPE_BSD = 5;

    /**
     * @var string|null
     */
    private $type;

    /**
     * Returns guessed OS type.
     *
     * @return int
     */
    public function getType()
    {
        if (null === $this->type) {
            $this->type = $this->guessType();
        }

        return $this->type;
    }

    /**
     * Tests if a command is available.
     *
     * @param string $command
     *
     * @return bool
     */
    public function testCommand($command)
    {
        if (!\function_exists('exec')) {
            return false;
        }

        // todo: find a better way (command could not be available)
        $testCommand = 'which ';
        if (self::TYPE_WINDOWS === $this->type) {
            $testCommand = 'where ';
        }

        $command = escapeshellcmd($command);

        exec($testCommand.$command, $output, $code);

        return 0 === $code && \count($output) > 0;
    }

    /**
     * Guesses OS type.
     *
     * @return int
     */
    private function guessType()
    {
        $os = strtolower(PHP_OS);

        if (false !== strpos($os, 'cygwin')) {
            return self::TYPE_CYGWIN;
        }

        if (false !== strpos($os, 'darwin')) {
            return self::TYPE_DARWIN;
        }

        if (false !== strpos($os, 'bsd')) {
            return self::TYPE_BSD;
        }

        if (0 === strpos($os, 'win')) {
            return self::TYPE_WINDOWS;
        }

        return self::TYPE_UNIX;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Finder;

/**
 * Extends \SplFileInfo to support relative paths.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SplFileInfo extends \SplFileInfo
{
    private $relativePath;
    private $relativePathname;

    /**
     * @param string $file             The file name
     * @param string $relativePath     The relative path
     * @param string $relativePathname The relative path name
     */
    public function __construct($file, $relativePath, $relativePathname)
    {
        parent::__construct($file);
        $this->relativePath = $relativePath;
        $this->relativePathname = $relativePathname;
    }

    /**
     * Returns the relative path.
     *
     * This path does not contain the file name.
     *
     * @return string the relative path
     */
    public function getRelativePath()
    {
        return $this->relativePath;
    }

    /**
     * Returns the relative path name.
     *
     * This path contains the file name.
     *
     * @return string the relative path name
     */
    public function getRelativePathname()
    {
        return $this->relativePathname;
    }

    /**
     * Returns the contents of the file.
     *
     * @return string the contents of the file
     *
     * @throws \RuntimeException
     */
    public function getContents()
    {
        set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
        $content = file_get_contents($this->getPathname());
        restore_error_handler();
        if (false === $content) {
            throw new \RuntimeException($error);
        }

        return $content;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

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); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

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); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Ctype;

/**
 * Ctype implementation through regex.
 *
 * @internal
 *
 * @author Gert de Pagter <BackEndTea@gmail.com>
 */
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);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Iconv as p;

if (extension_loaded('iconv')) {
    return;
}

if (\PHP_VERSION_ID >= 80000) {
    return require __DIR__.'/bootstrap80.php';
}

if (!defined('ICONV_IMPL')) {
    define('ICONV_IMPL', 'Symfony');
}
if (!defined('ICONV_VERSION')) {
    define('ICONV_VERSION', '1.0');
}
if (!defined('ICONV_MIME_DECODE_STRICT')) {
    define('ICONV_MIME_DECODE_STRICT', 1);
}
if (!defined('ICONV_MIME_DECODE_CONTINUE_ON_ERROR')) {
    define('ICONV_MIME_DECODE_CONTINUE_ON_ERROR', 2);
}

if (!function_exists('iconv')) {
    function iconv($from_encoding, $to_encoding, $string) { return p\Iconv::iconv($from_encoding, $to_encoding, $string); }
}
if (!function_exists('iconv_get_encoding')) {
    function iconv_get_encoding($type = 'all') { return p\Iconv::iconv_get_encoding($type); }
}
if (!function_exists('iconv_set_encoding')) {
    function iconv_set_encoding($type, $encoding) { return p\Iconv::iconv_set_encoding($type, $encoding); }
}
if (!function_exists('iconv_mime_encode')) {
    function iconv_mime_encode($field_name, $field_value, $options = []) { return p\Iconv::iconv_mime_encode($field_name, $field_value, $options); }
}
if (!function_exists('iconv_mime_decode_headers')) {
    function iconv_mime_decode_headers($headers, $mode = 0, $encoding = null) { return p\Iconv::iconv_mime_decode_headers($headers, $mode, $encoding); }
}

if (extension_loaded('mbstring')) {
    if (!function_exists('iconv_strlen')) {
        function iconv_strlen($string, $encoding = null) { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strlen($string, $encoding); }
    }
    if (!function_exists('iconv_strpos')) {
        function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null) { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strpos($haystack, $needle, $offset, $encoding); }
    }
    if (!function_exists('iconv_strrpos')) {
        function iconv_strrpos($haystack, $needle, $encoding = null) { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strrpos($haystack, $needle, 0, $encoding); }
    }
    if (!function_exists('iconv_substr')) {
        function iconv_substr($string, $offset, $length = 2147483647, $encoding = null) { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_substr($string, $offset, $length, $encoding); }
    }
    if (!function_exists('iconv_mime_decode')) {
        function iconv_mime_decode($string, $mode = 0, $encoding = null) { $currentMbEncoding = mb_internal_encoding(); null === $encoding && $encoding = p\Iconv::$internalEncoding; mb_internal_encoding($encoding); $decoded = mb_decode_mimeheader($string); mb_internal_encoding($currentMbEncoding); return $decoded; }
    }
} else {
    if (!function_exists('iconv_strlen')) {
        function iconv_strlen($string, $encoding = null) { return p\Iconv::iconv_strlen($string, $encoding); }
    }

    if (!function_exists('iconv_strpos')) {
        function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Iconv::iconv_strpos($haystack, $needle, $offset, $encoding); }
    }
    if (!function_exists('iconv_strrpos')) {
        function iconv_strrpos($haystack, $needle, $encoding = null) { return p\Iconv::iconv_strrpos($haystack, $needle, $encoding); }
    }
    if (!function_exists('iconv_substr')) {
        function iconv_substr($string, $offset, $length = 2147483647, $encoding = null) { return p\Iconv::iconv_substr($string, $offset, $length, $encoding); }
    }
    if (!function_exists('iconv_mime_decode')) {
        function iconv_mime_decode($string, $mode = 0, $encoding = null) { return p\Iconv::iconv_mime_decode($string, $mode, $encoding); }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Iconv as p;

if (!defined('ICONV_IMPL')) {
    define('ICONV_IMPL', 'Symfony');
}
if (!defined('ICONV_VERSION')) {
    define('ICONV_VERSION', '1.0');
}
if (!defined('ICONV_MIME_DECODE_STRICT')) {
    define('ICONV_MIME_DECODE_STRICT', 1);
}
if (!defined('ICONV_MIME_DECODE_CONTINUE_ON_ERROR')) {
    define('ICONV_MIME_DECODE_CONTINUE_ON_ERROR', 2);
}

if (!function_exists('iconv')) {
    function iconv(?string $from_encoding, ?string $to_encoding, ?string $string): string|false { return p\Iconv::iconv((string) $from_encoding, (string) $to_encoding, (string) $string); }
}
if (!function_exists('iconv_get_encoding')) {
    function iconv_get_encoding(?string $type = 'all'): array|string|false { return p\Iconv::iconv_get_encoding((string) $type); }
}
if (!function_exists('iconv_set_encoding')) {
    function iconv_set_encoding(?string $type, ?string $encoding): bool { return p\Iconv::iconv_set_encoding((string) $type, (string) $encoding); }
}
if (!function_exists('iconv_mime_encode')) {
    function iconv_mime_encode(?string $field_name, ?string $field_value, ?array $options = []): string|false { return p\Iconv::iconv_mime_encode((string) $field_name, (string) $field_value, (array) $options); }
}
if (!function_exists('iconv_mime_decode_headers')) {
    function iconv_mime_decode_headers(?string $headers, ?int $mode = 0, ?string $encoding = null): array|false { return p\Iconv::iconv_mime_decode_headers((string) $headers, (int) $mode, $encoding); }
}

if (extension_loaded('mbstring')) {
    if (!function_exists('iconv_strlen')) {
        function iconv_strlen(?string $string, ?string $encoding = null): int|false { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strlen((string) $string, $encoding); }
    }
    if (!function_exists('iconv_strpos')) {
        function iconv_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
    }
    if (!function_exists('iconv_strrpos')) {
        function iconv_strrpos(?string $haystack, ?string $needle, ?string $encoding = null): int|false { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_strrpos((string) $haystack, (string) $needle, 0, $encoding); }
    }
    if (!function_exists('iconv_substr')) {
        function iconv_substr(?string $string, ?int $offset, ?int $length = null, ?string $encoding = null): string|false { null === $encoding && $encoding = p\Iconv::$internalEncoding; return mb_substr((string) $string, (int) $offset, $length, $encoding); }
    }
    if (!function_exists('iconv_mime_decode')) {
        function iconv_mime_decode($string, $mode = 0, $encoding = null) { $currentMbEncoding = mb_internal_encoding(); null === $encoding && $encoding = p\Iconv::$internalEncoding; mb_internal_encoding($encoding); $decoded = mb_decode_mimeheader($string); mb_internal_encoding($currentMbEncoding); return $decoded; }
    }
} else {
    if (!function_exists('iconv_strlen')) {
        function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::iconv_strlen((string) $string, $encoding); }
    }

    if (!function_exists('iconv_strpos')) {
        function iconv_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Iconv::iconv_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
    }
    if (!function_exists('iconv_strrpos')) {
        function iconv_strrpos(?string $haystack, ?string $needle, ?string $encoding = null): int|false { return p\Iconv::iconv_strrpos((string) $haystack, (string) $needle, $encoding); }
    }
    if (!function_exists('iconv_substr')) {
        function iconv_substr(?string $string, ?int $offset, ?int $length = null, ?string $encoding = null): string|false { return p\Iconv::iconv_substr((string) $string, (string) $offset, $length, $encoding); }
    }
    if (!function_exists('iconv_mime_decode')) {
        function iconv_mime_decode(?string $string, ?int $mode = 0, ?string $encoding = null): string|false { return p\Iconv::iconv_mime_decode((string) $string, (int) $mode, $encoding); }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Iconv;

/**
 * iconv implementation in pure PHP, UTF-8 centric.
 *
 * Implemented:
 * - iconv              - Convert string to requested character encoding
 * - iconv_mime_decode  - Decodes a MIME header field
 * - iconv_mime_decode_headers - Decodes multiple MIME header fields at once
 * - iconv_get_encoding - Retrieve internal configuration variables of iconv extension
 * - iconv_set_encoding - Set current setting for character encoding conversion
 * - iconv_mime_encode  - Composes a MIME header field
 * - iconv_strlen       - Returns the character count of string
 * - iconv_strpos       - Finds position of first occurrence of a needle within a haystack
 * - iconv_strrpos      - Finds the last occurrence of a needle within a haystack
 * - iconv_substr       - Cut out part of a string
 *
 * Charsets available for conversion are defined by files
 * in the charset/ directory and by Iconv::$alias below.
 * You're welcome to send back any addition you make.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
final class Iconv
{
    public const ERROR_ILLEGAL_CHARACTER = 'iconv(): Detected an illegal character in input string';
    public const ERROR_WRONG_CHARSET = 'iconv(): Wrong charset, conversion from `%s\' to `%s\' is not allowed';

    public static $inputEncoding = 'utf-8';
    public static $outputEncoding = 'utf-8';
    public static $internalEncoding = 'utf-8';

    private static $alias = [
        'utf8' => 'utf-8',
        'ascii' => 'us-ascii',
        'tis-620' => 'iso-8859-11',
        'cp1250' => 'windows-1250',
        'cp1251' => 'windows-1251',
        'cp1252' => 'windows-1252',
        'cp1253' => 'windows-1253',
        'cp1254' => 'windows-1254',
        'cp1255' => 'windows-1255',
        'cp1256' => 'windows-1256',
        'cp1257' => 'windows-1257',
        'cp1258' => 'windows-1258',
        'shift-jis' => 'cp932',
        'shift_jis' => 'cp932',
        'latin1' => 'iso-8859-1',
        'latin2' => 'iso-8859-2',
        'latin3' => 'iso-8859-3',
        'latin4' => 'iso-8859-4',
        'latin5' => 'iso-8859-9',
        'latin6' => 'iso-8859-10',
        'latin7' => 'iso-8859-13',
        'latin8' => 'iso-8859-14',
        'latin9' => 'iso-8859-15',
        'latin10' => 'iso-8859-16',
        'iso8859-1' => 'iso-8859-1',
        'iso8859-2' => 'iso-8859-2',
        'iso8859-3' => 'iso-8859-3',
        'iso8859-4' => 'iso-8859-4',
        'iso8859-5' => 'iso-8859-5',
        'iso8859-6' => 'iso-8859-6',
        'iso8859-7' => 'iso-8859-7',
        'iso8859-8' => 'iso-8859-8',
        'iso8859-9' => 'iso-8859-9',
        'iso8859-10' => 'iso-8859-10',
        'iso8859-11' => 'iso-8859-11',
        'iso8859-12' => 'iso-8859-12',
        'iso8859-13' => 'iso-8859-13',
        'iso8859-14' => 'iso-8859-14',
        'iso8859-15' => 'iso-8859-15',
        'iso8859-16' => 'iso-8859-16',
        'iso_8859-1' => 'iso-8859-1',
        'iso_8859-2' => 'iso-8859-2',
        'iso_8859-3' => 'iso-8859-3',
        'iso_8859-4' => 'iso-8859-4',
        'iso_8859-5' => 'iso-8859-5',
        'iso_8859-6' => 'iso-8859-6',
        'iso_8859-7' => 'iso-8859-7',
        'iso_8859-8' => 'iso-8859-8',
        'iso_8859-9' => 'iso-8859-9',
        'iso_8859-10' => 'iso-8859-10',
        'iso_8859-11' => 'iso-8859-11',
        'iso_8859-12' => 'iso-8859-12',
        'iso_8859-13' => 'iso-8859-13',
        'iso_8859-14' => 'iso-8859-14',
        'iso_8859-15' => 'iso-8859-15',
        'iso_8859-16' => 'iso-8859-16',
        'iso88591' => 'iso-8859-1',
        'iso88592' => 'iso-8859-2',
        'iso88593' => 'iso-8859-3',
        'iso88594' => 'iso-8859-4',
        'iso88595' => 'iso-8859-5',
        'iso88596' => 'iso-8859-6',
        'iso88597' => 'iso-8859-7',
        'iso88598' => 'iso-8859-8',
        'iso88599' => 'iso-8859-9',
        'iso885910' => 'iso-8859-10',
        'iso885911' => 'iso-8859-11',
        'iso885912' => 'iso-8859-12',
        'iso885913' => 'iso-8859-13',
        'iso885914' => 'iso-8859-14',
        'iso885915' => 'iso-8859-15',
        'iso885916' => 'iso-8859-16',
    ];
    private static $translitMap = [];
    private static $convertMap = [];
    private static $errorHandler;
    private static $lastError;

    private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
    private static $isValidUtf8;

    public static function iconv($inCharset, $outCharset, $str)
    {
        $str = (string) $str;
        if ('' === $str) {
            return '';
        }

        // Prepare for //IGNORE and //TRANSLIT

        $translit = $ignore = '';

        $outCharset = strtolower($outCharset);
        $inCharset = strtolower($inCharset);

        if ('' === $outCharset) {
            $outCharset = 'iso-8859-1';
        }
        if ('' === $inCharset) {
            $inCharset = 'iso-8859-1';
        }

        do {
            $loop = false;

            if ('//translit' === substr($outCharset, -10)) {
                $loop = $translit = true;
                $outCharset = substr($outCharset, 0, -10);
            }

            if ('//ignore' === substr($outCharset, -8)) {
                $loop = $ignore = true;
                $outCharset = substr($outCharset, 0, -8);
            }
        } while ($loop);

        do {
            $loop = false;

            if ('//translit' === substr($inCharset, -10)) {
                $loop = true;
                $inCharset = substr($inCharset, 0, -10);
            }

            if ('//ignore' === substr($inCharset, -8)) {
                $loop = true;
                $inCharset = substr($inCharset, 0, -8);
            }
        } while ($loop);

        if (isset(self::$alias[$inCharset])) {
            $inCharset = self::$alias[$inCharset];
        }
        if (isset(self::$alias[$outCharset])) {
            $outCharset = self::$alias[$outCharset];
        }

        // Load charset maps

        if (('utf-8' !== $inCharset && !self::loadMap('from.', $inCharset, $inMap))
          || ('utf-8' !== $outCharset && !self::loadMap('to.', $outCharset, $outMap))) {
            trigger_error(sprintf(self::ERROR_WRONG_CHARSET, $inCharset, $outCharset));

            return false;
        }

        if ('utf-8' !== $inCharset) {
            // Convert input to UTF-8
            $result = '';
            if (self::mapToUtf8($result, $inMap, $str, $ignore)) {
                $str = $result;
            } else {
                $str = false;
            }
            self::$isValidUtf8 = true;
        } else {
            self::$isValidUtf8 = preg_match('//u', $str);

            if (!self::$isValidUtf8 && !$ignore) {
                trigger_error(self::ERROR_ILLEGAL_CHARACTER);

                return false;
            }

            if ('utf-8' === $outCharset) {
                // UTF-8 validation
                $str = self::utf8ToUtf8($str, $ignore);
            }
        }

        if ('utf-8' !== $outCharset && false !== $str) {
            // Convert output to UTF-8
            $result = '';
            if (self::mapFromUtf8($result, $outMap, $str, $ignore, $translit)) {
                return $result;
            }

            return false;
        }

        return $str;
    }

    public static function iconv_mime_decode_headers($str, $mode = 0, $charset = null)
    {
        if (null === $charset) {
            $charset = self::$internalEncoding;
        }

        if (false !== strpos($str, "\r")) {
            $str = strtr(str_replace("\r\n", "\n", $str), "\r", "\n");
        }
        $str = explode("\n\n", $str, 2);

        $headers = [];

        $str = preg_split('/\n(?![ \t])/', $str[0]);
        foreach ($str as $str) {
            $str = self::iconv_mime_decode($str, $mode, $charset);
            if (false === $str) {
                return false;
            }
            $str = explode(':', $str, 2);

            if (2 === \count($str)) {
                if (isset($headers[$str[0]])) {
                    if (!\is_array($headers[$str[0]])) {
                        $headers[$str[0]] = [$headers[$str[0]]];
                    }
                    $headers[$str[0]][] = ltrim($str[1]);
                } else {
                    $headers[$str[0]] = ltrim($str[1]);
                }
            }
        }

        return $headers;
    }

    public static function iconv_mime_decode($str, $mode = 0, $charset = null)
    {
        if (null === $charset) {
            $charset = self::$internalEncoding;
        }
        if (\ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode) {
            $charset .= '//IGNORE';
        }

        if (false !== strpos($str, "\r")) {
            $str = strtr(str_replace("\r\n", "\n", $str), "\r", "\n");
        }
        $str = preg_split('/\n(?![ \t])/', rtrim($str), 2);
        $str = preg_replace('/[ \t]*\n[ \t]+/', ' ', rtrim($str[0]));
        $str = preg_split('/=\?([^?]+)\?([bqBQ])\?(.*?)\?=/', $str, -1, \PREG_SPLIT_DELIM_CAPTURE);

        $result = self::iconv('utf-8', $charset, $str[0]);
        if (false === $result) {
            return false;
        }

        $i = 1;
        $len = \count($str);

        while ($i < $len) {
            $c = strtolower($str[$i]);
            if ((\ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode)
              && 'utf-8' !== $c
              && !isset(self::$alias[$c])
              && !self::loadMap('from.', $c, $d)) {
                $d = false;
            } elseif ('B' === strtoupper($str[$i + 1])) {
                $d = base64_decode($str[$i + 2]);
            } else {
                $d = rawurldecode(strtr(str_replace('%', '%25', $str[$i + 2]), '=_', '% '));
            }

            if (false !== $d) {
                if ('' !== $d) {
                    if ('' === $d = self::iconv($c, $charset, $d)) {
                        $str[$i + 3] = substr($str[$i + 3], 1);
                    } else {
                        $result .= $d;
                    }
                }
                $d = self::iconv('utf-8', $charset, $str[$i + 3]);
                if ('' !== trim($d)) {
                    $result .= $d;
                }
            } elseif (\ICONV_MIME_DECODE_CONTINUE_ON_ERROR & $mode) {
                $result .= "=?{$str[$i]}?{$str[$i + 1]}?{$str[$i + 2]}?={$str[$i + 3]}";
            } else {
                $result = false;
                break;
            }

            $i += 4;
        }

        return $result;
    }

    public static function iconv_get_encoding($type = 'all')
    {
        switch ($type) {
            case 'input_encoding': return self::$inputEncoding;
            case 'output_encoding': return self::$outputEncoding;
            case 'internal_encoding': return self::$internalEncoding;
        }

        return [
            'input_encoding' => self::$inputEncoding,
            'output_encoding' => self::$outputEncoding,
            'internal_encoding' => self::$internalEncoding,
        ];
    }

    public static function iconv_set_encoding($type, $charset)
    {
        switch ($type) {
            case 'input_encoding': self::$inputEncoding = $charset; break;
            case 'output_encoding': self::$outputEncoding = $charset; break;
            case 'internal_encoding': self::$internalEncoding = $charset; break;
            default: return false;
        }

        return true;
    }

    public static function iconv_mime_encode($fieldName, $fieldValue, $pref = null)
    {
        if (!\is_array($pref)) {
            $pref = [];
        }

        $pref += [
            'scheme' => 'B',
            'input-charset' => self::$internalEncoding,
            'output-charset' => self::$internalEncoding,
            'line-length' => 76,
            'line-break-chars' => "\r\n",
        ];

        if (preg_match('/[\x80-\xFF]/', $fieldName)) {
            $fieldName = '';
        }

        $scheme = strtoupper(substr($pref['scheme'], 0, 1));
        $in = strtolower($pref['input-charset']);
        $out = strtolower($pref['output-charset']);

        if ('utf-8' !== $in && false === $fieldValue = self::iconv($in, 'utf-8', $fieldValue)) {
            return false;
        }

        preg_match_all('/./us', $fieldValue, $chars);

        $chars = $chars[0] ?? [];

        $lineBreak = (int) $pref['line-length'];
        $lineStart = "=?{$pref['output-charset']}?{$scheme}?";
        $lineLength = \strlen($fieldName) + 2 + \strlen($lineStart) + 2;
        $lineOffset = \strlen($lineStart) + 3;
        $lineData = '';

        $fieldValue = [];

        $Q = 'Q' === $scheme;

        foreach ($chars as $c) {
            if ('utf-8' !== $out && false === $c = self::iconv('utf-8', $out, $c)) {
                return false;
            }

            $o = $Q
                ? $c = preg_replace_callback(
                    '/[=_\?\x00-\x1F\x80-\xFF]/',
                    [__CLASS__, 'qpByteCallback'],
                    $c
                )
                : base64_encode($lineData.$c);

            if (isset($o[$lineBreak - $lineLength])) {
                if (!$Q) {
                    $lineData = base64_encode($lineData);
                }
                $fieldValue[] = $lineStart.$lineData.'?=';
                $lineLength = $lineOffset;
                $lineData = '';
            }

            $lineData .= $c;
            $Q && $lineLength += \strlen($c);
        }

        if ('' !== $lineData) {
            if (!$Q) {
                $lineData = base64_encode($lineData);
            }
            $fieldValue[] = $lineStart.$lineData.'?=';
        }

        return $fieldName.': '.implode($pref['line-break-chars'].' ', $fieldValue);
    }

    public static function iconv_strlen($s, $encoding = null)
    {
        if (null === $encoding) {
            $encoding = self::$internalEncoding;
        }
        if (0 !== stripos($encoding, 'utf-8') && false === $s = self::iconv($encoding, 'utf-8', $s)) {
            return false;
        }

        $ulenMask = self::$ulenMask;

        $i = 0;
        $j = 0;
        $len = \strlen($s);

        while ($i < $len) {
            $u = $s[$i] & "\xF0";
            $i += $ulenMask[$u] ?? 1;
            ++$j;
        }

        return $j;
    }

    public static function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        if (null === $encoding) {
            $encoding = self::$internalEncoding;
        }

        if (0 !== stripos($encoding, 'utf-8')) {
            if (false === $haystack = self::iconv($encoding, 'utf-8', $haystack)) {
                return false;
            }
            if (false === $needle = self::iconv($encoding, 'utf-8', $needle)) {
                return false;
            }
        }

        if ($offset = (int) $offset) {
            $haystack = self::iconv_substr($haystack, $offset, 2147483647, 'utf-8');
        }
        $pos = strpos($haystack, $needle);

        return false === $pos ? false : ($offset + ($pos ? self::iconv_strlen(substr($haystack, 0, $pos), 'utf-8') : 0));
    }

    public static function iconv_strrpos($haystack, $needle, $encoding = null)
    {
        if (null === $encoding) {
            $encoding = self::$internalEncoding;
        }

        if (0 !== stripos($encoding, 'utf-8')) {
            if (false === $haystack = self::iconv($encoding, 'utf-8', $haystack)) {
                return false;
            }
            if (false === $needle = self::iconv($encoding, 'utf-8', $needle)) {
                return false;
            }
        }

        $pos = isset($needle[0]) ? strrpos($haystack, $needle) : false;

        return false === $pos ? false : self::iconv_strlen($pos ? substr($haystack, 0, $pos) : $haystack, 'utf-8');
    }

    public static function iconv_substr($s, $start, $length = 2147483647, $encoding = null)
    {
        if (null === $encoding) {
            $encoding = self::$internalEncoding;
        }
        if (0 !== stripos($encoding, 'utf-8')) {
            $encoding = null;
        } elseif (false === $s = self::iconv($encoding, 'utf-8', $s)) {
            return false;
        }

        $s = (string) $s;
        $slen = self::iconv_strlen($s, 'utf-8');
        $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;
        }

        $rx = $slen - $start;

        if (0 > $length) {
            $length += $rx;
        }
        if (0 === $length) {
            return '';
        }
        if (0 > $length) {
            return \PHP_VERSION_ID >= 80000 ? '' : false;
        }

        if ($length > $rx) {
            $length = $rx;
        }

        $rx = '/^'.($start ? self::pregOffset($start) : '').'('.self::pregOffset($length).')/u';

        $s = preg_match($rx, $s, $s) ? $s[1] : '';

        if (null === $encoding) {
            return $s;
        }

        return self::iconv('utf-8', $encoding, $s);
    }

    private static function loadMap($type, $charset, &$map)
    {
        if (!isset(self::$convertMap[$type.$charset])) {
            if (false === $map = self::getData($type.$charset)) {
                if ('to.' === $type && self::loadMap('from.', $charset, $map)) {
                    $map = array_flip($map);
                } else {
                    return false;
                }
            }

            self::$convertMap[$type.$charset] = $map;
        } else {
            $map = self::$convertMap[$type.$charset];
        }

        return true;
    }

    private static function utf8ToUtf8($str, $ignore)
    {
        $ulenMask = self::$ulenMask;
        $valid = self::$isValidUtf8;

        $u = $str;
        $i = $j = 0;
        $len = \strlen($str);

        while ($i < $len) {
            if ($str[$i] < "\x80") {
                $u[$j++] = $str[$i++];
            } else {
                $ulen = $str[$i] & "\xF0";
                $ulen = $ulenMask[$ulen] ?? 1;
                $uchr = substr($str, $i, $ulen);

                if (1 === $ulen || !($valid || preg_match('/^.$/us', $uchr))) {
                    if ($ignore) {
                        ++$i;
                        continue;
                    }

                    trigger_error(self::ERROR_ILLEGAL_CHARACTER);

                    return false;
                }

                $i += $ulen;

                $u[$j++] = $uchr[0];

                isset($uchr[1]) && 0 !== ($u[$j++] = $uchr[1])
                    && isset($uchr[2]) && 0 !== ($u[$j++] = $uchr[2])
                    && isset($uchr[3]) && 0 !== ($u[$j++] = $uchr[3]);
            }
        }

        return substr($u, 0, $j);
    }

    private static function mapToUtf8(&$result, array $map, $str, $ignore)
    {
        $len = \strlen($str);
        for ($i = 0; $i < $len; ++$i) {
            if (isset($str[$i + 1], $map[$str[$i].$str[$i + 1]])) {
                $result .= $map[$str[$i].$str[++$i]];
            } elseif (isset($map[$str[$i]])) {
                $result .= $map[$str[$i]];
            } elseif (!$ignore) {
                trigger_error(self::ERROR_ILLEGAL_CHARACTER);

                return false;
            }
        }

        return true;
    }

    private static function mapFromUtf8(&$result, array $map, $str, $ignore, $translit)
    {
        $ulenMask = self::$ulenMask;
        $valid = self::$isValidUtf8;

        if ($translit && !self::$translitMap) {
            self::$translitMap = self::getData('translit');
        }

        $i = 0;
        $len = \strlen($str);

        while ($i < $len) {
            if ($str[$i] < "\x80") {
                $uchr = $str[$i++];
            } else {
                $ulen = $str[$i] & "\xF0";
                $ulen = $ulenMask[$ulen] ?? 1;
                $uchr = substr($str, $i, $ulen);

                if ($ignore && (1 === $ulen || !($valid || preg_match('/^.$/us', $uchr)))) {
                    ++$i;
                    continue;
                }

                $i += $ulen;
            }

            if (isset($map[$uchr])) {
                $result .= $map[$uchr];
            } elseif ($translit) {
                if (isset(self::$translitMap[$uchr])) {
                    $uchr = self::$translitMap[$uchr];
                } elseif ($uchr >= "\xC3\x80") {
                    $uchr = \Normalizer::normalize($uchr, \Normalizer::NFD);

                    if ($uchr[0] < "\x80") {
                        $uchr = $uchr[0];
                    } elseif ($ignore) {
                        continue;
                    } else {
                        return false;
                    }
                } elseif ($ignore) {
                    continue;
                } else {
                    return false;
                }

                $str = $uchr.substr($str, $i);
                $len = \strlen($str);
                $i = 0;
            } elseif (!$ignore) {
                return false;
            }
        }

        return true;
    }

    private static function qpByteCallback(array $m)
    {
        return '='.strtoupper(dechex(\ord($m[0])));
    }

    private static function pregOffset($offset)
    {
        $rx = [];
        $offset = (int) $offset;

        while ($offset > 65535) {
            $rx[] = '.{65535}';
            $offset -= 65535;
        }

        return implode('', $rx).'.{'.$offset.'}';
    }

    private static function getData($file)
    {
        if (file_exists($file = __DIR__.'/Resources/charset/'.$file.'.php')) {
            return require $file;
        }

        return false;
    }
}
<?php

static $data = array (
  '@' => '　',
  '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' => '卵',
  '[' => '吝',
  '\\' => '吭',
  ']' => '吞',
  '^' => '吾',
  '_' => '否',
  '`' => '呎',
  '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' => '述',
  '{' => '迦',
  '|' => '迢',
  '}' => '迪',
  '~' => '迥',
  '' => '迭',
  '' => '迫',
  '' => '迤',
  '' => '迨',
  '' => '郊',
  '' => '郎',
  '' => '郁',
  '' => '郃',
  '' => '酋',
  '' => '酊',
  '' => '重',
  '' => '閂',
  '' => '限',
  '' => '陋',
  '' => '陌',
  '' => '降',
  '' => '面',
  '' => '革',
  '' => '韋',
  '' => '韭',
  '' => '音',
  '' => '頁',
  '' => '風',
  '' => '飛',
  '' => '食',
  '' => '首',
  '' => '香',
  '' => '乘',
  '' => '亳',
  '' => '倌',
  '' => '倍',
  '' => '倣',
  '' => '俯',
  '' => '倦',
  '' => '倥',
  '' => '俸',
  '' => '倩',
  '' => '倖',
  '' => '倆',
  '' => '值',
  '' => '借',
  '' => '倚',
  '' => '倒',
  '' => '們',
  '' => '俺',
  '' => '倀',
  '' => '倔',
  '' => '倨',
  '' => '俱',
  '' => '倡',
  '' => '個',
  '' => '候',
  '' => '倘',
  '' => '俳',
  '' => '修',
  '' => '倭',
  '' => '倪',
  '' => '俾',
  '' => '倫',
  '' => '倉',
  '' => '兼',
  '' => '冤',
  '' => '冥',
  '' => '冢',
  '' => '凍',
  '' => '凌',
  '' => '准',
  '' => '凋',
  '' => '剖',
  '' => '剜',
  '' => '剔',
  '' => '剛',
  '' => '剝',
  '' => '匪',
  '' => '卿',
  '' => '原',
  '' => '厝',
  '' => '叟',
  '' => '哨',
  '' => '唐',
  '' => '唁',
  '' => '唷',
  '' => '哼',
  '' => '哥',
  '' => '哲',
  '' => '唆',
  '' => '哺',
  '' => '唔',
  '' => '哩',
  '' => '哭',
  '' => '員',
  '' => '唉',
  '' => '哮',
  '' => '哪',
  '@' => '哦',
  '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' => '廁',
  '[' => '廂',
  '\\' => '廄',
  ']' => '弼',
  '^' => '彭',
  '_' => '復',
  '`' => '循',
  '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' => '漠',
  '{' => '漬',
  '|' => '漏',
  '}' => '漂',
  '~' => '漢',
  '' => '滿',
  '' => '滯',
  '' => '漆',
  '' => '漱',
  '' => '漸',
  '' => '漲',
  '' => '漣',
  '' => '漕',
  '' => '漫',
  '' => '漯',
  '' => '澈',
  '' => '漪',
  '' => '滬',
  '' => '漁',
  '' => '滲',
  '' => '滌',
  '' => '滷',
  '' => '熔',
  '' => '熙',
  '' => '煽',
  '' => '熊',
  '' => '熄',
  '' => '熒',
  '' => '爾',
  '' => '犒',
  '' => '犖',
  '' => '獄',
  '' => '獐',
  '' => '瑤',
  '' => '瑣',
  '' => '瑪',
  '' => '瑰',
  '' => '瑭',
  '' => '甄',
  '' => '疑',
  '' => '瘧',
  '' => '瘍',
  '' => '瘋',
  '' => '瘉',
  '' => '瘓',
  '' => '盡',
  '' => '監',
  '' => '瞄',
  '' => '睽',
  '' => '睿',
  '' => '睡',
  '' => '磁',
  '' => '碟',
  '' => '碧',
  '' => '碳',
  '' => '碩',
  '' => '碣',
  '' => '禎',
  '' => '福',
  '' => '禍',
  '' => '種',
  '' => '稱',
  '' => '窪',
  '' => '窩',
  '' => '竭',
  '' => '端',
  '' => '管',
  '' => '箕',
  '' => '箋',
  '' => '筵',
  '' => '算',
  '' => '箝',
  '' => '箔',
  '' => '箏',
  '' => '箸',
  '' => '箇',
  '' => '箄',
  '' => '粹',
  '' => '粽',
  '' => '精',
  '' => '綻',
  '' => '綰',
  '' => '綜',
  '' => '綽',
  '' => '綾',
  '' => '綠',
  '' => '緊',
  '' => '綴',
  '' => '網',
  '' => '綱',
  '' => '綺',
  '' => '綢',
  '' => '綿',
  '' => '綵',
  '' => '綸',
  '' => '維',
  '' => '緒',
  '' => '緇',
  '' => '綬',
  '@' => '罰',
  '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' => '績',
  '[' => '繆',
  '\\' => '縷',
  ']' => '縲',
  '^' => '繃',
  '_' => '縫',
  '`' => '總',
  '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' => 'モ',
  '{' => 'ャ',
  '|' => 'ヤ',
  '}' => 'ュ',
  '~' => 'ユ',
  'ǡ' => 'ョ',
  'Ǣ' => 'ヨ',
  'ǣ' => 'ラ',
  'Ǥ' => 'リ',
  'ǥ' => 'ル',
  'Ǧ' => 'レ',
  'ǧ' => 'ロ',
  'Ǩ' => 'ヮ',
  'ǩ' => 'ワ',
  'Ǫ' => 'ヰ',
  'ǫ' => 'ヱ',
  'Ǭ' => 'ヲ',
  'ǭ' => 'ン',
  'Ǯ' => 'ヴ',
  'ǯ' => 'ヵ',
  'ǰ' => 'ヶ',
  'Ǳ' => 'Д',
  'ǲ' => 'Е',
  'ǳ' => 'Ё',
  'Ǵ' => 'Ж',
  'ǵ' => 'З',
  'Ƕ' => 'И',
  'Ƿ' => 'Й',
  'Ǹ' => 'К',
  'ǹ' => 'Л',
  'Ǻ' => 'М',
  'ǻ' => 'У',
  'Ǽ' => 'Ф',
  'ǽ' => 'Х',
  'Ǿ' => 'Ц',
  'ǿ' => 'Ч',
  '' => 'Ш',
  '' => 'Щ',
  '' => 'Ъ',
  '' => 'Ы',
  '' => 'Ь',
  '' => 'Э',
  '' => 'Ю',
  '' => 'Я',
  '' => 'а',
  '' => 'б',
  '' => 'в',
  '' => 'г',
  '' => 'д',
  '' => 'е',
  '' => 'ё',
  '' => 'ж',
  '' => 'з',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ф',
  '' => 'х',
  '' => 'ц',
  '' => 'ч',
  '' => 'ш',
  '' => 'щ',
  '' => 'ъ',
  '' => 'ы',
  '' => 'ь',
  '' => 'э',
  '' => 'ю',
  '' => 'я',
  '' => '①',
  '' => '②',
  '' => '③',
  '' => '④',
  '' => '⑤',
  '' => '⑥',
  '' => '⑦',
  '' => '⑧',
  '' => '⑨',
  '' => '⑩',
  '' => '⑴',
  '' => '⑵',
  '' => '⑶',
  '' => '⑷',
  '' => '⑸',
  '' => '⑹',
  '' => '⑺',
  '' => '⑻',
  '' => '⑼',
  '' => '⑽',
  '@' => '乂',
  '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' => '柌',
  '[' => '枮',
  '\\' => '柦',
  ']' => '柛',
  '^' => '柺',
  '_' => '柉',
  '`' => '柊',
  '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' => '掮',
  '{' => '捼',
  '|' => '掤',
  '}' => '挻',
  '~' => '掟',
  'ա' => '捸',
  'բ' => '掅',
  'գ' => '掁',
  'դ' => '掑',
  'ե' => '掍',
  'զ' => '捰',
  'է' => '敓',
  'ը' => '旍',
  'թ' => '晥',
  'ժ' => '晡',
  'ի' => '晛',
  'լ' => '晙',
  'խ' => '晜',
  'ծ' => '晢',
  'կ' => '朘',
  'հ' => '桹',
  'ձ' => '梇',
  'ղ' => '梐',
  'ճ' => '梜',
  'մ' => '桭',
  'յ' => '桮',
  'ն' => '梮',
  'շ' => '梫',
  'ո' => '楖',
  'չ' => '桯',
  'պ' => '梣',
  'ջ' => '梬',
  'ռ' => '梩',
  'ս' => '桵',
  'վ' => '桴',
  'տ' => '梲',
  '' => '梏',
  '' => '桷',
  '' => '梒',
  '' => '桼',
  '' => '桫',
  '' => '桲',
  '' => '梪',
  '' => '梀',
  '' => '桱',
  '' => '桾',
  '' => '梛',
  '' => '梖',
  '' => '梋',
  '' => '梠',
  '' => '梉',
  '' => '梤',
  '' => '桸',
  '' => '桻',
  '' => '梑',
  '' => '梌',
  '' => '梊',
  '' => '桽',
  '' => '欶',
  '' => '欳',
  '' => '欷',
  '' => '欸',
  '' => '殑',
  '' => '殏',
  '' => '殍',
  '' => '殎',
  '' => '殌',
  '' => '氪',
  '' => '淀',
  '' => '涫',
  '' => '涴',
  '' => '涳',
  '' => '湴',
  '' => '涬',
  '' => '淩',
  '' => '淢',
  '' => '涷',
  '' => '淶',
  '' => '淔',
  '' => '渀',
  '' => '淈',
  '' => '淠',
  '' => '淟',
  '' => '淖',
  '' => '涾',
  '' => '淥',
  '' => '淜',
  '' => '淝',
  '' => '淛',
  '' => '淴',
  '' => '淊',
  '' => '涽',
  '' => '淭',
  '' => '淰',
  '' => '涺',
  '' => '淕',
  '' => '淂',
  '' => '淏',
  '' => '淉',
  '@' => '淐',
  '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' => '鄇',
  '[' => '鄅',
  '\\' => '鄃',
  ']' => '酡',
  '^' => '酤',
  '_' => '酟',
  '`' => '酢',
  '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' => '漘',
  '{' => '漻',
  '|' => '漒',
  '}' => '滭',
  '~' => '漊',
  '' => '漶',
  '' => '潳',
  '' => '滹',
  '' => '滮',
  '' => '漭',
  '' => '潀',
  '' => '漰',
  '' => '漼',
  '' => '漵',
  '' => '滫',
  '' => '漇',
  '' => '漎',
  '' => '潃',
  '' => '漅',
  '' => '滽',
  '' => '滶',
  '' => '漹',
  '' => '漜',
  '' => '滼',
  '' => '漺',
  '' => '漟',
  '' => '漍',
  '' => '漞',
  '' => '漈',
  '' => '漡',
  '' => '熇',
  '' => '熐',
  '' => '熉',
  '' => '熀',
  '' => '熅',
  '' => '熂',
  '' => '熏',
  '' => '煻',
  '' => '熆',
  '' => '熁',
  '' => '熗',
  '' => '牄',
  '' => '牓',
  '' => '犗',
  '' => '犕',
  '' => '犓',
  '' => '獃',
  '' => '獍',
  '' => '獑',
  '' => '獌',
  '' => '瑢',
  '' => '瑳',
  '' => '瑱',
  '' => '瑵',
  '' => '瑲',
  '' => '瑧',
  '' => '瑮',
  '' => '甀',
  '' => '甂',
  '' => '甃',
  '' => '畽',
  '' => '疐',
  '' => '瘖',
  '' => '瘈',
  '' => '瘌',
  '' => '瘕',
  '' => '瘑',
  '' => '瘊',
  '' => '瘔',
  '' => '皸',
  '' => '瞁',
  '' => '睼',
  '' => '瞅',
  '' => '瞂',
  '' => '睮',
  '' => '瞀',
  '' => '睯',
  '' => '睾',
  '' => '瞃',
  '' => '碲',
  '' => '碪',
  '' => '碴',
  '' => '碭',
  '' => '碨',
  '' => '硾',
  '' => '碫',
  '' => '碞',
  '' => '碥',
  '' => '碠',
  '' => '碬',
  '' => '碢',
  '' => '碤',
  '' => '禘',
  '' => '禊',
  '' => '禋',
  '' => '禖',
  '' => '禕',
  '' => '禔',
  '' => '禓',
  '@' => '禗',
  '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' => '嬚',
  '[' => '嬠',
  '\\' => '嬞',
  ']' => '寯',
  '^' => '嶬',
  '_' => '嶱',
  '`' => '嶩',
  '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' => '鴮',
  '{' => '鴯',
  '|' => '鴱',
  '}' => '鴸',
  '~' => '鴰',
  '' => '鵅',
  '' => '鵂',
  '' => '鵃',
  '' => '鴾',
  '' => '鴷',
  '' => '鵀',
  '' => '鴽',
  '' => '翵',
  '' => '鴭',
  '' => '麊',
  '' => '麉',
  '' => '麍',
  '' => '麰',
  '' => '黈',
  '' => '黚',
  '' => '黻',
  '' => '黿',
  '' => '鼤',
  '' => '鼣',
  '' => '鼢',
  '' => '齔',
  '' => '龠',
  '' => '儱',
  '' => '儭',
  '' => '儮',
  '' => '嚘',
  '' => '嚜',
  '' => '嚗',
  '' => '嚚',
  '' => '嚝',
  '' => '嚙',
  '' => '奰',
  '' => '嬼',
  '' => '屩',
  '' => '屪',
  '' => '巀',
  '' => '幭',
  '' => '幮',
  '' => '懘',
  '' => '懟',
  '' => '懭',
  '' => '懮',
  '' => '懱',
  '' => '懪',
  '' => '懰',
  '' => '懫',
  '' => '懖',
  '' => '懩',
  '' => '擿',
  '' => '攄',
  '' => '擽',
  '' => '擸',
  '' => '攁',
  '' => '攃',
  '' => '擼',
  '' => '斔',
  '' => '旛',
  '' => '曚',
  '' => '曛',
  '' => '曘',
  '' => '櫅',
  '' => '檹',
  '' => '檽',
  '' => '櫡',
  '' => '櫆',
  '' => '檺',
  '' => '檶',
  '' => '檷',
  '' => '櫇',
  '' => '檴',
  '' => '檭',
  '' => '歞',
  '' => '毉',
  '' => '氋',
  '' => '瀇',
  '' => '瀌',
  '' => '瀍',
  '' => '瀁',
  '' => '瀅',
  '' => '瀔',
  '' => '瀎',
  '' => '濿',
  '' => '瀀',
  '' => '濻',
  '' => '瀦',
  '' => '濼',
  '' => '濷',
  '' => '瀊',
  '' => '爁',
  '' => '燿',
  '' => '燹',
  '' => '爃',
  '' => '燽',
  '' => '獶',
  '@' => '璸',
  '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' => '酆',
  '[' => '酄',
  '\\' => '酅',
  ']' => '醹',
  '^' => '鐿',
  '_' => '鐻',
  '`' => '鐶',
  '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' => '鱵',
  '{' => '鸔',
  '|' => '鸓',
  '}' => '黶',
  '~' => '鼊',
  '' => '龤',
  '' => '灨',
  '' => '灥',
  '' => '糷',
  '' => '虪',
  '' => '蠾',
  '' => '蠽',
  '' => '蠿',
  '' => '讞',
  '' => '貜',
  '' => '躩',
  '' => '軉',
  '' => '靋',
  '' => '顳',
  '' => '顴',
  '' => '飌',
  '' => '饡',
  '' => '馫',
  '' => '驤',
  '' => '驦',
  '' => '驧',
  '' => '鬤',
  '' => '鸕',
  '' => '鸗',
  '' => '齈',
  '' => '戇',
  '' => '欞',
  '' => '爧',
  '' => '虌',
  '' => '躨',
  '' => '钂',
  '' => '钀',
  '' => '钁',
  '' => '驩',
  '' => '驨',
  '' => '鬮',
  '' => '鸙',
  '' => '爩',
  '' => '虋',
  '' => '讟',
  '' => '钃',
  '' => '鱹',
  '' => '麷',
  '' => '癵',
  '' => '驫',
  '' => '鱺',
  '' => '鸝',
  '' => '灩',
  '' => '灪',
  '' => '麤',
  '' => '齾',
  '' => '齉',
  '' => '龘',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '	',
  '' => '',
  '' => '',
  '' => '',
  '	' => '',
  '
' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => '',
  '!' => '',
  '"' => '',
  '#' => '',
  '$' => '',
  '%' => '
',
  '&' => '',
  '\'' => '',
  '(' => '',
  ')' => '',
  '*' => '',
  '+' => '',
  ',' => '',
  '-' => '',
  '.' => '',
  '/' => '',
  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' => '!',
  '[' => '$',
  '\\' => '*',
  ']' => ')',
  '^' => ';',
  '_' => '¬',
  '`' => '-',
  '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',
  '' => '³',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ù',
  '' => 'Ú',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '۰',
  '' => '۱',
  '' => '۲',
  '' => '۳',
  '' => '۴',
  '' => '۵',
  '' => '۶',
  '' => '۷',
  '' => '۸',
  '' => '۹',
  '' => '،',
  '' => '؛',
  '' => '­',
  '' => '؟',
  '' => 'ﺁ',
  '' => 'ﺍ',
  '' => 'ﺎ',
  '' => 'ﺎ',
  '' => 'ﺏ',
  '' => 'ﺑ',
  '' => 'ﭖ',
  '' => 'ﭘ',
  '' => 'ﺓ',
  '' => 'ﺕ',
  '' => 'ﺗ',
  '' => 'ﭦ',
  '' => 'ﭨ',
  '' => 'ﺙ',
  '' => 'ﺛ',
  '' => 'ﺝ',
  '' => 'ﺟ',
  '' => 'ﭺ',
  '' => 'ﭼ',
  '' => 'ﺡ',
  '' => 'ﺣ',
  '' => 'ﺥ',
  '' => 'ﺧ',
  '' => 'ﺩ',
  '' => 'ﮄ',
  '' => 'ﺫ',
  '' => 'ﺭ',
  '' => 'ﮌ',
  '' => 'ﺯ',
  '' => 'ﮊ',
  '' => 'ﺱ',
  '' => 'ﺳ',
  '' => 'ﺵ',
  '' => 'ﺷ',
  '' => 'ﺹ',
  '' => 'ﺻ',
  '' => 'ﺽ',
  '' => 'ﺿ',
  '' => 'ﻁ',
  '' => 'ﻅ',
  '' => 'ﻉ',
  '' => 'ﻊ',
  '' => 'ﻋ',
  '' => 'ﻌ',
  '' => 'ﻍ',
  '' => 'ﻎ',
  '' => 'ﻏ',
  '' => 'ﻐ',
  '' => 'ﻑ',
  '' => 'ﻓ',
  '' => 'ﻕ',
  '' => 'ﻗ',
  '' => 'ﻙ',
  '' => 'ﻛ',
  '' => 'ﮒ',
  '' => 'ﮔ',
  '' => 'ﻝ',
  '' => 'ﻟ',
  '' => 'ﻠ',
  '' => 'ﻡ',
  '' => 'ﻣ',
  '' => 'ﮞ',
  '' => 'ﻥ',
  '' => 'ﻧ',
  '' => 'ﺅ',
  '' => 'ﻭ',
  '' => 'ﮦ',
  '' => 'ﮨ',
  '' => 'ﮩ',
  '' => 'ﮪ',
  '' => 'ﺀ',
  '' => 'ﺉ',
  '' => 'ﺊ',
  '' => 'ﺋ',
  '' => 'ﻱ',
  '' => 'ﻲ',
  '' => 'ﻳ',
  '' => 'ﮰ',
  '' => 'ﮮ',
  '' => 'ﹼ',
  '' => 'ﹽ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '	',
  '' => '',
  '' => '',
  '' => '',
  '	' => '',
  '
' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => '',
  '!' => '',
  '"' => '',
  '#' => '',
  '$' => '',
  '%' => '
',
  '&' => '',
  '\'' => '',
  '(' => '',
  ')' => '',
  '*' => '',
  '+' => '',
  ',' => '',
  '-' => '',
  '.' => '',
  '/' => '',
  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' => 'Ğ',
  '[' => 'İ',
  '\\' => '*',
  ']' => ')',
  '^' => ';',
  '_' => '^',
  '`' => '-',
  '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',
  '' => '³',
  '' => 'Û',
  '' => '"',
  '' => 'Ù',
  '' => 'Ú',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '	',
  '' => '',
  '' => '',
  '' => '',
  '	' => '',
  '
' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => '',
  '!' => '',
  '"' => '',
  '#' => '',
  '$' => '',
  '%' => '
',
  '&' => '',
  '\'' => '',
  '(' => '',
  ')' => '',
  '*' => '',
  '+' => '',
  ',' => '',
  '-' => '',
  '.' => '',
  '/' => '',
  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' => '!',
  '[' => '$',
  '\\' => '*',
  ']' => ')',
  '^' => ';',
  '_' => '¬',
  '`' => '-',
  'a' => '/',
  'b' => 'ע',
  'c' => 'ף',
  'd' => 'פ',
  'e' => 'ץ',
  'f' => 'צ',
  'g' => 'ק',
  'h' => 'ר',
  'i' => 'ש',
  'j' => '¦',
  'k' => ',',
  'l' => '%',
  'm' => '_',
  'n' => '>',
  'o' => '?',
  'q' => 'ת',
  't' => ' ',
  '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',
  '' => '³',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'à',
  '' => 'å',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'ï',
  '' => 'î',
  '' => 'ì',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ô',
  '' => 'ö',
  '' => 'ò',
  '' => 'û',
  '' => 'ù',
  '' => 'ÿ',
  '' => 'Ö',
  '' => 'Ü',
  '' => '¢',
  '' => '£',
  '' => '¥',
  '' => '₧',
  '' => 'ƒ',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'ª',
  '' => 'º',
  '' => '¿',
  '' => '⌐',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '	',
  '' => '',
  '' => '',
  '' => '',
  '	' => '',
  '
' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => '',
  '!' => '',
  '"' => '',
  '#' => '',
  '$' => '',
  '%' => '
',
  '&' => '',
  '\'' => '',
  '(' => '',
  ')' => '',
  '*' => '',
  '+' => '',
  ',' => '',
  '-' => '',
  '.' => '',
  '/' => '',
  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' => ']',
  '[' => '$',
  '\\' => '*',
  ']' => ')',
  '^' => ';',
  '_' => '^',
  '`' => '-',
  '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',
  '' => '³',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ù',
  '' => 'Ú',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Α',
  '' => 'Β',
  '' => 'Γ',
  '' => 'Δ',
  '' => 'Ε',
  '' => 'Ζ',
  '' => 'Η',
  '' => 'Θ',
  '' => 'Ι',
  '' => 'Κ',
  '' => 'Λ',
  '' => 'Μ',
  '' => 'Ν',
  '' => 'Ξ',
  '' => 'Ο',
  '' => 'Π',
  '' => 'Ρ',
  '' => 'Σ',
  '' => 'Τ',
  '' => 'Υ',
  '' => 'Φ',
  '' => 'Χ',
  '' => 'Ψ',
  '' => 'Ω',
  '' => 'α',
  '' => 'β',
  '' => 'γ',
  '' => 'δ',
  '' => 'ε',
  '' => 'ζ',
  '' => 'η',
  '' => 'θ',
  '' => 'ι',
  '' => 'κ',
  '' => 'λ',
  '' => 'μ',
  '' => 'ν',
  '' => 'ξ',
  '' => 'ο',
  '' => 'π',
  '' => 'ρ',
  '' => 'σ',
  '' => 'ς',
  '' => 'τ',
  '' => 'υ',
  '' => 'φ',
  '' => 'χ',
  '' => 'ψ',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'ω',
  '' => 'ά',
  '' => 'έ',
  '' => 'ή',
  '' => 'ϊ',
  '' => 'ί',
  '' => 'ό',
  '' => 'ύ',
  '' => 'ϋ',
  '' => 'ώ',
  '' => 'Ά',
  '' => 'Έ',
  '' => 'Ή',
  '' => 'Ί',
  '' => 'Ό',
  '' => 'Ύ',
  '' => 'Ώ',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => 'Ϊ',
  '' => 'Ϋ',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ć',
  '' => 'ü',
  '' => 'é',
  '' => 'ā',
  '' => 'ä',
  '' => 'ģ',
  '' => 'å',
  '' => 'ć',
  '' => 'ł',
  '' => 'ē',
  '' => 'Ŗ',
  '' => 'ŗ',
  '' => 'ī',
  '' => 'Ź',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ō',
  '' => 'ö',
  '' => 'Ģ',
  '' => '¢',
  '' => 'Ś',
  '' => 'ś',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'ø',
  '' => '£',
  '' => 'Ø',
  '' => '×',
  '' => '¤',
  '' => 'Ā',
  '' => 'Ī',
  '' => 'ó',
  '' => 'Ż',
  '' => 'ż',
  '' => 'ź',
  '' => '”',
  '' => '¦',
  '' => '©',
  '' => '®',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => 'Ł',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'Ą',
  '' => 'Č',
  '' => 'Ę',
  '' => 'Ė',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => 'Į',
  '' => 'Š',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'Ų',
  '' => 'Ū',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => 'Ž',
  '' => 'ą',
  '' => 'č',
  '' => 'ę',
  '' => 'ė',
  '' => 'į',
  '' => 'š',
  '' => 'ų',
  '' => 'ū',
  '' => 'ž',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'Ó',
  '' => 'ß',
  '' => 'Ō',
  '' => 'Ń',
  '' => 'õ',
  '' => 'Õ',
  '' => 'µ',
  '' => 'ń',
  '' => 'Ķ',
  '' => 'ķ',
  '' => 'Ļ',
  '' => 'ļ',
  '' => 'ņ',
  '' => 'Ē',
  '' => 'Ņ',
  '' => '’',
  '' => '­',
  '' => '±',
  '' => '“',
  '' => '¾',
  '' => '¶',
  '' => '§',
  '' => '÷',
  '' => '„',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '¹',
  '' => '³',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'à',
  '' => 'å',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'ï',
  '' => 'î',
  '' => 'ì',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ô',
  '' => 'ö',
  '' => 'ò',
  '' => 'û',
  '' => 'ù',
  '' => 'ÿ',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'ø',
  '' => '£',
  '' => 'Ø',
  '' => '×',
  '' => 'ƒ',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'ª',
  '' => 'º',
  '' => '¿',
  '' => '®',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'Á',
  '' => 'Â',
  '' => 'À',
  '' => '©',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '¢',
  '' => '¥',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'ã',
  '' => 'Ã',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '¤',
  '' => 'ð',
  '' => 'Ð',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'È',
  '' => 'ı',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '¦',
  '' => 'Ì',
  '' => '▀',
  '' => 'Ó',
  '' => 'ß',
  '' => 'Ô',
  '' => 'Ò',
  '' => 'õ',
  '' => 'Õ',
  '' => 'µ',
  '' => 'þ',
  '' => 'Þ',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ù',
  '' => 'ý',
  '' => 'Ý',
  '' => '¯',
  '' => '´',
  '' => '­',
  '' => '±',
  '' => '‗',
  '' => '¾',
  '' => '¶',
  '' => '§',
  '' => '÷',
  '' => '¸',
  '' => '°',
  '' => '¨',
  '' => '·',
  '' => '¹',
  '' => '³',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'ů',
  '' => 'ć',
  '' => 'ç',
  '' => 'ł',
  '' => 'ë',
  '' => 'Ő',
  '' => 'ő',
  '' => 'î',
  '' => 'Ź',
  '' => 'Ä',
  '' => 'Ć',
  '' => 'É',
  '' => 'Ĺ',
  '' => 'ĺ',
  '' => 'ô',
  '' => 'ö',
  '' => 'Ľ',
  '' => 'ľ',
  '' => 'Ś',
  '' => 'ś',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'Ť',
  '' => 'ť',
  '' => 'Ł',
  '' => '×',
  '' => 'č',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'Ą',
  '' => 'ą',
  '' => 'Ž',
  '' => 'ž',
  '' => 'Ę',
  '' => 'ę',
  '' => '¬',
  '' => 'ź',
  '' => 'Č',
  '' => 'ş',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ě',
  '' => 'Ş',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => 'Ż',
  '' => 'ż',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'Ă',
  '' => 'ă',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '¤',
  '' => 'đ',
  '' => 'Đ',
  '' => 'Ď',
  '' => 'Ë',
  '' => 'ď',
  '' => 'Ň',
  '' => 'Í',
  '' => 'Î',
  '' => 'ě',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => 'Ţ',
  '' => 'Ů',
  '' => '▀',
  '' => 'Ó',
  '' => 'ß',
  '' => 'Ô',
  '' => 'Ń',
  '' => 'ń',
  '' => 'ň',
  '' => 'Š',
  '' => 'š',
  '' => 'Ŕ',
  '' => 'Ú',
  '' => 'ŕ',
  '' => 'Ű',
  '' => 'ý',
  '' => 'Ý',
  '' => 'ţ',
  '' => '´',
  '' => '­',
  '' => '˝',
  '' => '˛',
  '' => 'ˇ',
  '' => '˘',
  '' => '§',
  '' => '÷',
  '' => '¸',
  '' => '°',
  '' => '¨',
  '' => '˙',
  '' => 'ű',
  '' => 'Ř',
  '' => 'ř',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'ђ',
  '' => 'Ђ',
  '' => 'ѓ',
  '' => 'Ѓ',
  '' => 'ё',
  '' => 'Ё',
  '' => 'є',
  '' => 'Є',
  '' => 'ѕ',
  '' => 'Ѕ',
  '' => 'і',
  '' => 'І',
  '' => 'ї',
  '' => 'Ї',
  '' => 'ј',
  '' => 'Ј',
  '' => 'љ',
  '' => 'Љ',
  '' => 'њ',
  '' => 'Њ',
  '' => 'ћ',
  '' => 'Ћ',
  '' => 'ќ',
  '' => 'Ќ',
  '' => 'ў',
  '' => 'Ў',
  '' => 'џ',
  '' => 'Џ',
  '' => 'ю',
  '' => 'Ю',
  '' => 'ъ',
  '' => 'Ъ',
  '' => 'а',
  '' => 'А',
  '' => 'б',
  '' => 'Б',
  '' => 'ц',
  '' => 'Ц',
  '' => 'д',
  '' => 'Д',
  '' => 'е',
  '' => 'Е',
  '' => 'ф',
  '' => 'Ф',
  '' => 'г',
  '' => 'Г',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'х',
  '' => 'Х',
  '' => 'и',
  '' => 'И',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => 'й',
  '' => 'Й',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'к',
  '' => 'К',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '¤',
  '' => 'л',
  '' => 'Л',
  '' => 'м',
  '' => 'М',
  '' => 'н',
  '' => 'Н',
  '' => 'о',
  '' => 'О',
  '' => 'п',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => 'П',
  '' => 'я',
  '' => '▀',
  '' => 'Я',
  '' => 'р',
  '' => 'Р',
  '' => 'с',
  '' => 'С',
  '' => 'т',
  '' => 'Т',
  '' => 'у',
  '' => 'У',
  '' => 'ж',
  '' => 'Ж',
  '' => 'в',
  '' => 'В',
  '' => 'ь',
  '' => 'Ь',
  '' => '№',
  '' => '­',
  '' => 'ы',
  '' => 'Ы',
  '' => 'з',
  '' => 'З',
  '' => 'ш',
  '' => 'Ш',
  '' => 'э',
  '' => 'Э',
  '' => 'щ',
  '' => 'Щ',
  '' => 'ч',
  '' => 'Ч',
  '' => '§',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'א',
  '' => 'ב',
  '' => 'ג',
  '' => 'ד',
  '' => 'ה',
  '' => 'ו',
  '' => 'ז',
  '' => 'ח',
  '' => 'ט',
  '' => 'י',
  '' => 'ך',
  '' => 'כ',
  '' => 'ל',
  '' => 'ם',
  '' => 'מ',
  '' => 'ן',
  '' => 'נ',
  '' => 'ס',
  '' => 'ע',
  '' => 'ף',
  '' => 'פ',
  '' => 'ץ',
  '' => 'צ',
  '' => 'ק',
  '' => 'ר',
  '' => 'ש',
  '' => 'ת',
  '' => '£',
  '' => '×',
  '' => '®',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '©',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '¢',
  '' => '¥',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '¤',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '¦',
  '' => '▀',
  '' => 'µ',
  '' => '¯',
  '' => '´',
  '' => '­',
  '' => '±',
  '' => '‗',
  '' => '¾',
  '' => '¶',
  '' => '§',
  '' => '÷',
  '' => '¸',
  '' => '°',
  '' => '¨',
  '' => '·',
  '' => '¹',
  '' => '³',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'à',
  '' => 'å',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'ï',
  '' => 'î',
  '' => 'ı',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ô',
  '' => 'ö',
  '' => 'ò',
  '' => 'û',
  '' => 'ù',
  '' => 'İ',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'ø',
  '' => '£',
  '' => 'Ø',
  '' => 'Ş',
  '' => 'ş',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'Ğ',
  '' => 'ğ',
  '' => '¿',
  '' => '®',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'Á',
  '' => 'Â',
  '' => 'À',
  '' => '©',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '¢',
  '' => '¥',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'ã',
  '' => 'Ã',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '¤',
  '' => 'º',
  '' => 'ª',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'È',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '¦',
  '' => 'Ì',
  '' => '▀',
  '' => 'Ó',
  '' => 'ß',
  '' => 'Ô',
  '' => 'Ò',
  '' => 'õ',
  '' => 'Õ',
  '' => 'µ',
  '' => '×',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ù',
  '' => 'ì',
  '' => 'ÿ',
  '' => '¯',
  '' => '´',
  '' => '­',
  '' => '±',
  '' => '¾',
  '' => '¶',
  '' => '§',
  '' => '÷',
  '' => '¸',
  '' => '°',
  '' => '¨',
  '' => '·',
  '' => '¹',
  '' => '³',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ã',
  '' => 'à',
  '' => 'Á',
  '' => 'ç',
  '' => 'ê',
  '' => 'Ê',
  '' => 'è',
  '' => 'Í',
  '' => 'Ô',
  '' => 'ì',
  '' => 'Ã',
  '' => 'Â',
  '' => 'É',
  '' => 'À',
  '' => 'È',
  '' => 'ô',
  '' => 'õ',
  '' => 'ò',
  '' => 'Ú',
  '' => 'ù',
  '' => 'Ì',
  '' => 'Õ',
  '' => 'Ü',
  '' => '¢',
  '' => '£',
  '' => 'Ù',
  '' => '₧',
  '' => 'Ó',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'ª',
  '' => 'º',
  '' => '¿',
  '' => 'Ò',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'à',
  '' => 'å',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'Ð',
  '' => 'ð',
  '' => 'Þ',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ô',
  '' => 'ö',
  '' => 'þ',
  '' => 'û',
  '' => 'Ý',
  '' => 'ý',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'ø',
  '' => '£',
  '' => 'Ø',
  '' => '₧',
  '' => 'ƒ',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'Á',
  '' => 'Í',
  '' => 'Ó',
  '' => 'Ú',
  '' => '¿',
  '' => '⌐',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'א',
  '' => 'ב',
  '' => 'ג',
  '' => 'ד',
  '' => 'ה',
  '' => 'ו',
  '' => 'ז',
  '' => 'ח',
  '' => 'ט',
  '' => 'י',
  '' => 'ך',
  '' => 'כ',
  '' => 'ל',
  '' => 'ם',
  '' => 'מ',
  '' => 'ן',
  '' => 'נ',
  '' => 'ס',
  '' => 'ע',
  '' => 'ף',
  '' => 'פ',
  '' => 'ץ',
  '' => 'צ',
  '' => 'ק',
  '' => 'ר',
  '' => 'ש',
  '' => 'ת',
  '' => '¢',
  '' => '£',
  '' => '¥',
  '' => '₧',
  '' => 'ƒ',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'ª',
  '' => 'º',
  '' => '¿',
  '' => '⌐',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'Â',
  '' => 'à',
  '' => '¶',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'ï',
  '' => 'î',
  '' => '‗',
  '' => 'À',
  '' => '§',
  '' => 'É',
  '' => 'È',
  '' => 'Ê',
  '' => 'ô',
  '' => 'Ë',
  '' => 'Ï',
  '' => 'û',
  '' => 'ù',
  '' => '¤',
  '' => 'Ô',
  '' => 'Ü',
  '' => '¢',
  '' => '£',
  '' => 'Ù',
  '' => 'Û',
  '' => 'ƒ',
  '' => '¦',
  '' => '´',
  '' => 'ó',
  '' => 'ú',
  '' => '¨',
  '' => '¸',
  '' => '³',
  '' => '¯',
  '' => 'Î',
  '' => '⌐',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¾',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '٪',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '°',
  '' => '·',
  '' => '∙',
  '' => '√',
  '' => '▒',
  '' => '─',
  '' => '│',
  '' => '┼',
  '' => '┤',
  '' => '┬',
  '' => '├',
  '' => '┴',
  '' => '┐',
  '' => '┌',
  '' => '└',
  '' => '┘',
  '' => 'β',
  '' => '∞',
  '' => 'φ',
  '' => '±',
  '' => '½',
  '' => '¼',
  '' => '≈',
  '' => '«',
  '' => '»',
  '' => 'ﻷ',
  '' => 'ﻸ',
  '' => 'ﻻ',
  '' => 'ﻼ',
  '' => ' ',
  '' => '­',
  '' => 'ﺂ',
  '' => '£',
  '' => '¤',
  '' => 'ﺄ',
  '' => 'ﺎ',
  '' => 'ﺏ',
  '' => 'ﺕ',
  '' => 'ﺙ',
  '' => '،',
  '' => 'ﺝ',
  '' => 'ﺡ',
  '' => 'ﺥ',
  '' => '٠',
  '' => '١',
  '' => '٢',
  '' => '٣',
  '' => '٤',
  '' => '٥',
  '' => '٦',
  '' => '٧',
  '' => '٨',
  '' => '٩',
  '' => 'ﻑ',
  '' => '؛',
  '' => 'ﺱ',
  '' => 'ﺵ',
  '' => 'ﺹ',
  '' => '؟',
  '' => '¢',
  '' => 'ﺀ',
  '' => 'ﺁ',
  '' => 'ﺃ',
  '' => 'ﺅ',
  '' => 'ﻊ',
  '' => 'ﺋ',
  '' => 'ﺍ',
  '' => 'ﺑ',
  '' => 'ﺓ',
  '' => 'ﺗ',
  '' => 'ﺛ',
  '' => 'ﺟ',
  '' => 'ﺣ',
  '' => 'ﺧ',
  '' => 'ﺩ',
  '' => 'ﺫ',
  '' => 'ﺭ',
  '' => 'ﺯ',
  '' => 'ﺳ',
  '' => 'ﺷ',
  '' => 'ﺻ',
  '' => 'ﺿ',
  '' => 'ﻁ',
  '' => 'ﻅ',
  '' => 'ﻋ',
  '' => 'ﻏ',
  '' => '¦',
  '' => '¬',
  '' => '÷',
  '' => '×',
  '' => 'ﻉ',
  '' => 'ـ',
  '' => 'ﻓ',
  '' => 'ﻗ',
  '' => 'ﻛ',
  '' => 'ﻟ',
  '' => 'ﻣ',
  '' => 'ﻧ',
  '' => 'ﻫ',
  '' => 'ﻭ',
  '' => 'ﻯ',
  '' => 'ﻳ',
  '' => 'ﺽ',
  '' => 'ﻌ',
  '' => 'ﻎ',
  '' => 'ﻍ',
  '' => 'ﻡ',
  '' => 'ﹽ',
  '' => 'ّ',
  '' => 'ﻥ',
  '' => 'ﻩ',
  '' => 'ﻬ',
  '' => 'ﻰ',
  '' => 'ﻲ',
  '' => 'ﻐ',
  '' => 'ﻕ',
  '' => 'ﻵ',
  '' => 'ﻶ',
  '' => 'ﻝ',
  '' => 'ﻙ',
  '' => 'ﻱ',
  '' => '■',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ç',
  '' => 'ü',
  '' => 'é',
  '' => 'â',
  '' => 'ä',
  '' => 'à',
  '' => 'å',
  '' => 'ç',
  '' => 'ê',
  '' => 'ë',
  '' => 'è',
  '' => 'ï',
  '' => 'î',
  '' => 'ì',
  '' => 'Ä',
  '' => 'Å',
  '' => 'É',
  '' => 'æ',
  '' => 'Æ',
  '' => 'ô',
  '' => 'ö',
  '' => 'ò',
  '' => 'û',
  '' => 'ù',
  '' => 'ÿ',
  '' => 'Ö',
  '' => 'Ü',
  '' => 'ø',
  '' => '£',
  '' => 'Ø',
  '' => '₧',
  '' => 'ƒ',
  '' => 'á',
  '' => 'í',
  '' => 'ó',
  '' => 'ú',
  '' => 'ñ',
  '' => 'Ñ',
  '' => 'ª',
  '' => 'º',
  '' => '¿',
  '' => '⌐',
  '' => '¬',
  '' => '½',
  '' => '¼',
  '' => '¡',
  '' => '«',
  '' => '¤',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'α',
  '' => 'ß',
  '' => 'Γ',
  '' => 'π',
  '' => 'Σ',
  '' => 'σ',
  '' => 'µ',
  '' => 'τ',
  '' => 'Φ',
  '' => 'Θ',
  '' => 'Ω',
  '' => 'δ',
  '' => '∞',
  '' => 'φ',
  '' => 'ε',
  '' => '∩',
  '' => '≡',
  '' => '±',
  '' => '≥',
  '' => '≤',
  '' => '⌠',
  '' => '⌡',
  '' => '÷',
  '' => '≈',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => 'ⁿ',
  '' => '²',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'А',
  '' => 'Б',
  '' => 'В',
  '' => 'Г',
  '' => 'Д',
  '' => 'Е',
  '' => 'Ж',
  '' => 'З',
  '' => 'И',
  '' => 'Й',
  '' => 'К',
  '' => 'Л',
  '' => 'М',
  '' => 'Н',
  '' => 'О',
  '' => 'П',
  '' => 'Р',
  '' => 'С',
  '' => 'Т',
  '' => 'У',
  '' => 'Ф',
  '' => 'Х',
  '' => 'Ц',
  '' => 'Ч',
  '' => 'Ш',
  '' => 'Щ',
  '' => 'Ъ',
  '' => 'Ы',
  '' => 'Ь',
  '' => 'Э',
  '' => 'Ю',
  '' => 'Я',
  '' => 'а',
  '' => 'б',
  '' => 'в',
  '' => 'г',
  '' => 'д',
  '' => 'е',
  '' => 'ж',
  '' => 'з',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => '╡',
  '' => '╢',
  '' => '╖',
  '' => '╕',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => '╜',
  '' => '╛',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => '╞',
  '' => '╟',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => '╧',
  '' => '╨',
  '' => '╤',
  '' => '╥',
  '' => '╙',
  '' => '╘',
  '' => '╒',
  '' => '╓',
  '' => '╫',
  '' => '╪',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => '▌',
  '' => '▐',
  '' => '▀',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ф',
  '' => 'х',
  '' => 'ц',
  '' => 'ч',
  '' => 'ш',
  '' => 'щ',
  '' => 'ъ',
  '' => 'ы',
  '' => 'ь',
  '' => 'э',
  '' => 'ю',
  '' => 'я',
  '' => 'Ё',
  '' => 'ё',
  '' => 'Є',
  '' => 'є',
  '' => 'Ї',
  '' => 'ї',
  '' => 'Ў',
  '' => 'ў',
  '' => '°',
  '' => '∙',
  '' => '·',
  '' => '√',
  '' => '№',
  '' => '¤',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ά',
  '' => '·',
  '' => '¬',
  '' => '¦',
  '' => '‘',
  '' => '’',
  '' => 'Έ',
  '' => '―',
  '' => 'Ή',
  '' => 'Ί',
  '' => 'Ϊ',
  '' => 'Ό',
  '' => 'Ύ',
  '' => 'Ϋ',
  '' => '©',
  '' => 'Ώ',
  '' => '²',
  '' => '³',
  '' => 'ά',
  '' => '£',
  '' => 'έ',
  '' => 'ή',
  '' => 'ί',
  '' => 'ϊ',
  '' => 'ΐ',
  '' => 'ό',
  '' => 'ύ',
  '' => 'Α',
  '' => 'Β',
  '' => 'Γ',
  '' => 'Δ',
  '' => 'Ε',
  '' => 'Ζ',
  '' => 'Η',
  '' => '½',
  '' => 'Θ',
  '' => 'Ι',
  '' => '«',
  '' => '»',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '│',
  '' => '┤',
  '' => 'Κ',
  '' => 'Λ',
  '' => 'Μ',
  '' => 'Ν',
  '' => '╣',
  '' => '║',
  '' => '╗',
  '' => '╝',
  '' => 'Ξ',
  '' => 'Ο',
  '' => '┐',
  '' => '└',
  '' => '┴',
  '' => '┬',
  '' => '├',
  '' => '─',
  '' => '┼',
  '' => 'Π',
  '' => 'Ρ',
  '' => '╚',
  '' => '╔',
  '' => '╩',
  '' => '╦',
  '' => '╠',
  '' => '═',
  '' => '╬',
  '' => 'Σ',
  '' => 'Τ',
  '' => 'Υ',
  '' => 'Φ',
  '' => 'Χ',
  '' => 'Ψ',
  '' => 'Ω',
  '' => 'α',
  '' => 'β',
  '' => 'γ',
  '' => '┘',
  '' => '┌',
  '' => '█',
  '' => '▄',
  '' => 'δ',
  '' => 'ε',
  '' => '▀',
  '' => 'ζ',
  '' => 'η',
  '' => 'θ',
  '' => 'ι',
  '' => 'κ',
  '' => 'λ',
  '' => 'μ',
  '' => 'ν',
  '' => 'ξ',
  '' => 'ο',
  '' => 'π',
  '' => 'ρ',
  '' => 'σ',
  '' => 'ς',
  '' => 'τ',
  '' => '΄',
  '' => '­',
  '' => '±',
  '' => 'υ',
  '' => 'φ',
  '' => 'χ',
  '' => '§',
  '' => 'ψ',
  '' => '΅',
  '' => '°',
  '' => '¨',
  '' => 'ω',
  '' => 'ϋ',
  '' => 'ΰ',
  '' => 'ώ',
  '' => '■',
  '' => ' ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '…',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => ' ',
  '' => 'ก',
  '' => 'ข',
  '' => 'ฃ',
  '' => 'ค',
  '' => 'ฅ',
  '' => 'ฆ',
  '' => 'ง',
  '' => 'จ',
  '' => 'ฉ',
  '' => 'ช',
  '' => 'ซ',
  '' => 'ฌ',
  '' => 'ญ',
  '' => 'ฎ',
  '' => 'ฏ',
  '' => 'ฐ',
  '' => 'ฑ',
  '' => 'ฒ',
  '' => 'ณ',
  '' => 'ด',
  '' => 'ต',
  '' => 'ถ',
  '' => 'ท',
  '' => 'ธ',
  '' => 'น',
  '' => 'บ',
  '' => 'ป',
  '' => 'ผ',
  '' => 'ฝ',
  '' => 'พ',
  '' => 'ฟ',
  '' => 'ภ',
  '' => 'ม',
  '' => 'ย',
  '' => 'ร',
  '' => 'ฤ',
  '' => 'ล',
  '' => 'ฦ',
  '' => 'ว',
  '' => 'ศ',
  '' => 'ษ',
  '' => 'ส',
  '' => 'ห',
  '' => 'ฬ',
  '' => 'อ',
  '' => 'ฮ',
  '' => 'ฯ',
  '' => 'ะ',
  '' => 'ั',
  '' => 'า',
  '' => 'ำ',
  '' => 'ิ',
  '' => 'ี',
  '' => 'ึ',
  '' => 'ื',
  '' => 'ุ',
  '' => 'ู',
  '' => 'ฺ',
  '' => '฿',
  '' => 'เ',
  '' => 'แ',
  '' => 'โ',
  '' => 'ใ',
  '' => 'ไ',
  '' => 'ๅ',
  '' => 'ๆ',
  '' => '็',
  '' => '่',
  '' => '้',
  '' => '๊',
  '' => '๋',
  '' => '์',
  '' => 'ํ',
  '' => '๎',
  '' => '๏',
  '' => '๐',
  '' => '๑',
  '' => '๒',
  '' => '๓',
  '' => '๔',
  '' => '๕',
  '' => '๖',
  '' => '๗',
  '' => '๘',
  '' => '๙',
  '' => '๚',
  '' => '๛',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '	',
  '' => '',
  '' => '',
  '' => '',
  '	' => '',
  '
' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => '',
  '!' => '',
  '"' => '',
  '#' => '',
  '$' => '',
  '%' => '
',
  '&' => '',
  '\'' => '',
  '(' => '',
  ')' => '',
  '*' => '',
  '+' => '',
  ',' => '',
  '-' => '',
  '.' => '',
  '/' => '',
  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' => ']',
  '[' => '$',
  '\\' => '*',
  ']' => ')',
  '^' => ';',
  '_' => '^',
  '`' => '-',
  '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',
  '' => '³',
  '' => '©',
  '' => '',
  '' => '',
  '' => '»',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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' => '】',
  '{' => '＋',
  '|' => '－',
  '}' => '±',
  '~' => '×',
  '' => '÷',
  '' => '＝',
  '' => '≠',
  '' => '＜',
  '' => '＞',
  '' => '≦',
  '' => '≧',
  '' => '∞',
  '' => '∴',
  '' => '♂',
  '' => '♀',
  '' => '°',
  '' => '′',
  '' => '″',
  '' => '℃',
  '' => '￥',
  '' => '＄',
  '' => '￠',
  '' => '￡',
  '' => '％',
  '' => '＃',
  '' => '＆',
  '' => '＊',
  '' => '＠',
  '' => '§',
  '' => '☆',
  '' => '★',
  '' => '○',
  '' => '●',
  '' => '◎',
  '' => '◇',
  '' => '◆',
  '' => '□',
  '' => '■',
  '' => '△',
  '' => '▲',
  '' => '▽',
  '' => '▼',
  '' => '※',
  '' => '〒',
  '' => '→',
  '' => '←',
  '' => '↑',
  '' => '↓',
  '' => '〓',
  '' => '∈',
  '' => '∋',
  '' => '⊆',
  '' => '⊇',
  '' => '⊂',
  '' => '⊃',
  '' => '∪',
  '' => '∩',
  '' => '∧',
  '' => '∨',
  '' => '￢',
  '' => '⇒',
  '' => '⇔',
  '' => '∀',
  '' => '∃',
  '' => '∠',
  '' => '⊥',
  '' => '⌒',
  '' => '∂',
  '' => '∇',
  '' => '≡',
  '' => '≒',
  '' => '≪',
  '' => '≫',
  '' => '√',
  '' => '∽',
  '' => '∝',
  '' => '∵',
  '' => '∫',
  '' => '∬',
  '' => 'Å',
  '' => '‰',
  '' => '♯',
  '' => '♭',
  '' => '♪',
  '' => '†',
  '' => '‡',
  '' => '¶',
  '' => '◯',
  'O' => '０',
  'P' => '１',
  'Q' => '２',
  'R' => '３',
  'S' => '４',
  'T' => '５',
  'U' => '６',
  'V' => '７',
  'W' => '８',
  'X' => '９',
  '`' => 'Ａ',
  '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' => 'Ｚ',
  '' => 'ａ',
  '' => 'ｂ',
  '' => 'ｃ',
  '' => 'ｄ',
  '' => 'ｅ',
  '' => 'ｆ',
  '' => 'ｇ',
  '' => 'ｈ',
  '' => 'ｉ',
  '' => 'ｊ',
  '' => 'ｋ',
  '' => 'ｌ',
  '' => 'ｍ',
  '' => 'ｎ',
  '' => 'ｏ',
  '' => 'ｐ',
  '' => 'ｑ',
  '' => 'ｒ',
  '' => 'ｓ',
  '' => 'ｔ',
  '' => 'ｕ',
  '' => 'ｖ',
  '' => 'ｗ',
  '' => 'ｘ',
  '' => 'ｙ',
  '' => 'ｚ',
  '' => 'ぁ',
  '' => 'あ',
  '' => 'ぃ',
  '' => 'い',
  '' => 'ぅ',
  '' => 'う',
  '' => 'ぇ',
  '' => 'え',
  '' => 'ぉ',
  '' => 'お',
  '' => 'か',
  '' => 'が',
  '' => 'き',
  '' => 'ぎ',
  '' => 'く',
  '' => 'ぐ',
  '' => 'け',
  '' => 'げ',
  '' => 'こ',
  '' => 'ご',
  '' => 'さ',
  '' => 'ざ',
  '' => 'し',
  '' => 'じ',
  '' => 'す',
  '' => 'ず',
  '' => 'せ',
  '' => 'ぜ',
  '' => 'そ',
  '' => 'ぞ',
  '' => 'た',
  '' => 'だ',
  '' => 'ち',
  '' => 'ぢ',
  '' => 'っ',
  '' => 'つ',
  '' => 'づ',
  '' => 'て',
  '' => 'で',
  '' => 'と',
  '' => 'ど',
  '' => 'な',
  '' => 'に',
  '' => 'ぬ',
  '' => 'ね',
  '' => 'の',
  '' => 'は',
  '' => 'ば',
  '' => 'ぱ',
  '' => 'ひ',
  '' => 'び',
  '' => 'ぴ',
  '' => 'ふ',
  '' => 'ぶ',
  '' => 'ぷ',
  '' => 'へ',
  '' => 'べ',
  '' => 'ぺ',
  '' => 'ほ',
  '' => 'ぼ',
  '' => 'ぽ',
  '' => 'ま',
  '' => 'み',
  '' => 'む',
  '' => 'め',
  '' => 'も',
  '' => 'ゃ',
  '' => 'や',
  '' => 'ゅ',
  '' => 'ゆ',
  '' => 'ょ',
  '' => 'よ',
  '' => 'ら',
  '' => 'り',
  '' => 'る',
  '' => 'れ',
  '' => 'ろ',
  '' => 'ゎ',
  '' => 'わ',
  '' => 'ゐ',
  '' => 'ゑ',
  '' => 'を',
  '' => 'ん',
  '@' => 'ァ',
  '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' => 'Щ',
  '[' => 'Ъ',
  '\\' => 'Ы',
  ']' => 'Ь',
  '^' => 'Э',
  '_' => 'Ю',
  '`' => 'Я',
  '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' => '㎡',
  '~' => '㍻',
  '' => '〝',
  '' => '〟',
  '' => '№',
  '' => '㏍',
  '' => '℡',
  '' => '㊤',
  '' => '㊥',
  '' => '㊦',
  '' => '㊧',
  '' => '㊨',
  '' => '㈱',
  '' => '㈲',
  '' => '㈹',
  '' => '㍾',
  '' => '㍽',
  '' => '㍼',
  '' => '≒',
  '' => '≡',
  '' => '∫',
  '' => '∮',
  '' => '∑',
  '' => '√',
  '' => '⊥',
  '' => '∠',
  '' => '∟',
  '' => '⊿',
  '' => '∵',
  '' => '∩',
  '' => '∪',
  '' => '亜',
  '' => '唖',
  '' => '娃',
  '' => '阿',
  '' => '哀',
  '' => '愛',
  '' => '挨',
  '' => '姶',
  '' => '逢',
  '' => '葵',
  '' => '茜',
  '' => '穐',
  '' => '悪',
  '' => '握',
  '' => '渥',
  '' => '旭',
  '' => '葦',
  '' => '芦',
  '' => '鯵',
  '' => '梓',
  '' => '圧',
  '' => '斡',
  '' => '扱',
  '' => '宛',
  '' => '姐',
  '' => '虻',
  '' => '飴',
  '' => '絢',
  '' => '綾',
  '' => '鮎',
  '' => '或',
  '' => '粟',
  '' => '袷',
  '' => '安',
  '' => '庵',
  '' => '按',
  '' => '暗',
  '' => '案',
  '' => '闇',
  '' => '鞍',
  '' => '杏',
  '' => '以',
  '' => '伊',
  '' => '位',
  '' => '依',
  '' => '偉',
  '' => '囲',
  '' => '夷',
  '' => '委',
  '' => '威',
  '' => '尉',
  '' => '惟',
  '' => '意',
  '' => '慰',
  '' => '易',
  '' => '椅',
  '' => '為',
  '' => '畏',
  '' => '異',
  '' => '移',
  '' => '維',
  '' => '緯',
  '' => '胃',
  '' => '萎',
  '' => '衣',
  '' => '謂',
  '' => '違',
  '' => '遺',
  '' => '医',
  '' => '井',
  '' => '亥',
  '' => '域',
  '' => '育',
  '' => '郁',
  '' => '磯',
  '' => '一',
  '' => '壱',
  '' => '溢',
  '' => '逸',
  '' => '稲',
  '' => '茨',
  '' => '芋',
  '' => '鰯',
  '' => '允',
  '' => '印',
  '' => '咽',
  '' => '員',
  '' => '因',
  '' => '姻',
  '' => '引',
  '' => '飲',
  '' => '淫',
  '' => '胤',
  '' => '蔭',
  '@' => '院',
  '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' => '住',
  '[' => '充',
  '\\' => '十',
  ']' => '従',
  '^' => '戎',
  '_' => '柔',
  '`' => '汁',
  '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' => '布',
  '{' => '府',
  '|' => '怖',
  '}' => '扶',
  '~' => '敷',
  '' => '斧',
  '' => '普',
  '' => '浮',
  '' => '父',
  '' => '符',
  '' => '腐',
  '' => '膚',
  '' => '芙',
  '' => '譜',
  '' => '負',
  '' => '賦',
  '' => '赴',
  '' => '阜',
  '' => '附',
  '' => '侮',
  '' => '撫',
  '' => '武',
  '' => '舞',
  '' => '葡',
  '' => '蕪',
  '' => '部',
  '' => '封',
  '' => '楓',
  '' => '風',
  '' => '葺',
  '' => '蕗',
  '' => '伏',
  '' => '副',
  '' => '復',
  '' => '幅',
  '' => '服',
  '' => '福',
  '' => '腹',
  '' => '複',
  '' => '覆',
  '' => '淵',
  '' => '弗',
  '' => '払',
  '' => '沸',
  '' => '仏',
  '' => '物',
  '' => '鮒',
  '' => '分',
  '' => '吻',
  '' => '噴',
  '' => '墳',
  '' => '憤',
  '' => '扮',
  '' => '焚',
  '' => '奮',
  '' => '粉',
  '' => '糞',
  '' => '紛',
  '' => '雰',
  '' => '文',
  '' => '聞',
  '' => '丙',
  '' => '併',
  '' => '兵',
  '' => '塀',
  '' => '幣',
  '' => '平',
  '' => '弊',
  '' => '柄',
  '' => '並',
  '' => '蔽',
  '' => '閉',
  '' => '陛',
  '' => '米',
  '' => '頁',
  '' => '僻',
  '' => '壁',
  '' => '癖',
  '' => '碧',
  '' => '別',
  '' => '瞥',
  '' => '蔑',
  '' => '箆',
  '' => '偏',
  '' => '変',
  '' => '片',
  '' => '篇',
  '' => '編',
  '' => '辺',
  '' => '返',
  '' => '遍',
  '' => '便',
  '' => '勉',
  '' => '娩',
  '' => '弁',
  '' => '鞭',
  '' => '保',
  '' => '舗',
  '' => '鋪',
  '' => '圃',
  '' => '捕',
  '' => '歩',
  '' => '甫',
  '' => '補',
  '' => '輔',
  '' => '穂',
  '' => '募',
  '' => '墓',
  '' => '慕',
  '' => '戊',
  '' => '暮',
  '' => '母',
  '' => '簿',
  '' => '菩',
  '' => '倣',
  '' => '俸',
  '' => '包',
  '' => '呆',
  '' => '報',
  '' => '奉',
  '' => '宝',
  '' => '峰',
  '' => '峯',
  '' => '崩',
  '' => '庖',
  '' => '抱',
  '' => '捧',
  '' => '放',
  '' => '方',
  '' => '朋',
  '@' => '法',
  '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' => '腕',
  '' => '弌',
  '' => '丐',
  '' => '丕',
  '' => '个',
  '' => '丱',
  '' => '丶',
  '' => '丼',
  '' => '丿',
  '' => '乂',
  '' => '乖',
  '' => '乘',
  '' => '亂',
  '' => '亅',
  '' => '豫',
  '' => '亊',
  '' => '舒',
  '' => '弍',
  '' => '于',
  '' => '亞',
  '' => '亟',
  '' => '亠',
  '' => '亢',
  '' => '亰',
  '' => '亳',
  '' => '亶',
  '' => '从',
  '' => '仍',
  '' => '仄',
  '' => '仆',
  '' => '仂',
  '' => '仗',
  '' => '仞',
  '' => '仭',
  '' => '仟',
  '' => '价',
  '' => '伉',
  '' => '佚',
  '' => '估',
  '' => '佛',
  '' => '佝',
  '' => '佗',
  '' => '佇',
  '' => '佶',
  '' => '侈',
  '' => '侏',
  '' => '侘',
  '' => '佻',
  '' => '佩',
  '' => '佰',
  '' => '侑',
  '' => '佯',
  '' => '來',
  '' => '侖',
  '' => '儘',
  '' => '俔',
  '' => '俟',
  '' => '俎',
  '' => '俘',
  '' => '俛',
  '' => '俑',
  '' => '俚',
  '' => '俐',
  '' => '俤',
  '' => '俥',
  '' => '倚',
  '' => '倨',
  '' => '倔',
  '' => '倪',
  '' => '倥',
  '' => '倅',
  '' => '伜',
  '' => '俶',
  '' => '倡',
  '' => '倩',
  '' => '倬',
  '' => '俾',
  '' => '俯',
  '' => '們',
  '' => '倆',
  '' => '偃',
  '' => '假',
  '' => '會',
  '' => '偕',
  '' => '偐',
  '' => '偈',
  '' => '做',
  '' => '偖',
  '' => '偬',
  '' => '偸',
  '' => '傀',
  '' => '傚',
  '' => '傅',
  '' => '傴',
  '' => '傲',
  '@' => '僉',
  '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' => '飮',
  '[' => '歇',
  '\\' => '歃',
  ']' => '歉',
  '^' => '歐',
  '_' => '歙',
  '`' => '歔',
  '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' => '蚫',
  '{' => '蛔',
  '|' => '蛞',
  '}' => '蛩',
  '~' => '蛬',
  '' => '蛟',
  '' => '蛛',
  '' => '蛯',
  '' => '蜒',
  '' => '蜆',
  '' => '蜈',
  '' => '蜀',
  '' => '蜃',
  '' => '蛻',
  '' => '蜑',
  '' => '蜉',
  '' => '蜍',
  '' => '蛹',
  '' => '蜊',
  '' => '蜴',
  '' => '蜿',
  '' => '蜷',
  '' => '蜻',
  '' => '蜥',
  '' => '蜩',
  '' => '蜚',
  '' => '蝠',
  '' => '蝟',
  '' => '蝸',
  '' => '蝌',
  '' => '蝎',
  '' => '蝴',
  '' => '蝗',
  '' => '蝨',
  '' => '蝮',
  '' => '蝙',
  '' => '蝓',
  '' => '蝣',
  '' => '蝪',
  '' => '蠅',
  '' => '螢',
  '' => '螟',
  '' => '螂',
  '' => '螯',
  '' => '蟋',
  '' => '螽',
  '' => '蟀',
  '' => '蟐',
  '' => '雖',
  '' => '螫',
  '' => '蟄',
  '' => '螳',
  '' => '蟇',
  '' => '蟆',
  '' => '螻',
  '' => '蟯',
  '' => '蟲',
  '' => '蟠',
  '' => '蠏',
  '' => '蠍',
  '' => '蟾',
  '' => '蟶',
  '' => '蟷',
  '' => '蠎',
  '' => '蟒',
  '' => '蠑',
  '' => '蠖',
  '' => '蠕',
  '' => '蠢',
  '' => '蠡',
  '' => '蠱',
  '' => '蠶',
  '' => '蠹',
  '' => '蠧',
  '' => '蠻',
  '' => '衄',
  '' => '衂',
  '' => '衒',
  '' => '衙',
  '' => '衞',
  '' => '衢',
  '' => '衫',
  '' => '袁',
  '' => '衾',
  '' => '袞',
  '' => '衵',
  '' => '衽',
  '' => '袵',
  '' => '衲',
  '' => '袂',
  '' => '袗',
  '' => '袒',
  '' => '袮',
  '' => '袙',
  '' => '袢',
  '' => '袍',
  '' => '袤',
  '' => '袰',
  '' => '袿',
  '' => '袱',
  '' => '裃',
  '' => '裄',
  '' => '裔',
  '' => '裘',
  '' => '裙',
  '' => '裝',
  '' => '裹',
  '' => '褂',
  '' => '裼',
  '' => '裴',
  '' => '裨',
  '' => '裲',
  '' => '褄',
  '' => '褌',
  '' => '褊',
  '' => '褓',
  '' => '襃',
  '' => '褞',
  '' => '褥',
  '' => '褪',
  '' => '褫',
  '' => '襁',
  '' => '襄',
  '' => '褻',
  '' => '褶',
  '' => '褸',
  '' => '襌',
  '' => '褝',
  '' => '襠',
  '' => '襞',
  '@' => '襦',
  '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' => '睆',
  '[' => '劯',
  '\\' => '砡',
  ']' => '硎',
  '^' => '硤',
  '_' => '硺',
  '`' => '礰',
  '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' => '黑',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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' => '俫',
  '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' => '坺',
  '{' => '坽',
  '|' => '坾',
  '}' => '坿',
  '~' => '垀',
  '' => '垁',
  '' => '垇',
  '' => '垈',
  '' => '垉',
  '' => '垊',
  '' => '垍',
  '' => '垎',
  '' => '垏',
  '' => '垐',
  '' => '垑',
  '' => '垔',
  '' => '垕',
  '' => '垖',
  '' => '垗',
  '' => '垘',
  '' => '垙',
  '' => '垚',
  '' => '垜',
  '' => '垝',
  '' => '垞',
  '' => '垟',
  '' => '垥',
  '' => '垨',
  '' => '垪',
  '' => '垬',
  '' => '垯',
  '' => '垰',
  '' => '垱',
  '' => '垳',
  '' => '垵',
  '' => '垶',
  '' => '垷',
  '' => '垹',
  '' => '垺',
  '' => '垻',
  '' => '垼',
  '' => '垽',
  '' => '垾',
  '' => '垿',
  '' => '埀',
  '' => '埁',
  '' => '埄',
  '' => '埅',
  '' => '埆',
  '' => '埇',
  '' => '埈',
  '' => '埉',
  '' => '埊',
  '' => '埌',
  '' => '埍',
  '' => '埐',
  '' => '埑',
  '' => '埓',
  '' => '埖',
  '' => '埗',
  '' => '埛',
  '' => '埜',
  '' => '埞',
  '' => '埡',
  '' => '埢',
  '' => '埣',
  '' => '埥',
  '' => '埦',
  '' => '埧',
  '' => '埨',
  '' => '埩',
  '' => '埪',
  '' => '埫',
  '' => '埬',
  '' => '埮',
  '' => '埰',
  '' => '埱',
  '' => '埲',
  '' => '埳',
  '' => '埵',
  '' => '埶',
  '' => '執',
  '' => '埻',
  '' => '埼',
  '' => '埾',
  '' => '埿',
  '' => '堁',
  '' => '堃',
  '' => '堄',
  '' => '堅',
  '' => '堈',
  '' => '堉',
  '' => '堊',
  '' => '堌',
  '' => '堎',
  '' => '堏',
  '' => '堐',
  '' => '堒',
  '' => '堓',
  '' => '堔',
  '' => '堖',
  '' => '堗',
  '' => '堘',
  '' => '堚',
  '' => '堛',
  '' => '堜',
  '' => '堝',
  '' => '堟',
  '' => '堢',
  '' => '堣',
  '' => '堥',
  '' => '堦',
  '' => '堧',
  '' => '堨',
  '' => '堩',
  '' => '堫',
  '' => '堬',
  '' => '堭',
  '' => '堮',
  '' => '堯',
  '' => '報',
  '' => '堲',
  '' => '堳',
  '' => '場',
  '' => '堶',
  '' => '堷',
  '' => '堸',
  '' => '堹',
  '' => '堺',
  '' => '堻',
  '' => '堼',
  '' => '堽',
  '@' => '堾',
  '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' => '廧',
  '[' => '廩',
  '\\' => '廫',
  ']' => '廬',
  '^' => '廭',
  '_' => '廮',
  '`' => '廯',
  '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' => '晍',
  '{' => '晎',
  '|' => '晐',
  '}' => '晑',
  '~' => '晘',
  '' => '晙',
  '' => '晛',
  '' => '晜',
  '' => '晝',
  '' => '晞',
  '' => '晠',
  '' => '晢',
  '' => '晣',
  '' => '晥',
  '' => '晧',
  '' => '晩',
  '' => '晪',
  '' => '晫',
  '' => '晬',
  '' => '晭',
  '' => '晱',
  '' => '晲',
  '' => '晳',
  '' => '晵',
  '' => '晸',
  '' => '晹',
  '' => '晻',
  '' => '晼',
  '' => '晽',
  '' => '晿',
  '' => '暀',
  '' => '暁',
  '' => '暃',
  '' => '暅',
  '' => '暆',
  '' => '暈',
  '' => '暉',
  '' => '暊',
  '' => '暋',
  '' => '暍',
  '' => '暎',
  '' => '暏',
  '' => '暐',
  '' => '暒',
  '' => '暓',
  '' => '暔',
  '' => '暕',
  '' => '暘',
  '' => '暙',
  '' => '暚',
  '' => '暛',
  '' => '暜',
  '' => '暞',
  '' => '暟',
  '' => '暠',
  '' => '暡',
  '' => '暢',
  '' => '暣',
  '' => '暤',
  '' => '暥',
  '' => '暦',
  '' => '暩',
  '' => '暪',
  '' => '暫',
  '' => '暬',
  '' => '暭',
  '' => '暯',
  '' => '暰',
  '' => '暱',
  '' => '暲',
  '' => '暳',
  '' => '暵',
  '' => '暶',
  '' => '暷',
  '' => '暸',
  '' => '暺',
  '' => '暻',
  '' => '暼',
  '' => '暽',
  '' => '暿',
  '' => '曀',
  '' => '曁',
  '' => '曂',
  '' => '曃',
  '' => '曄',
  '' => '曅',
  '' => '曆',
  '' => '曇',
  '' => '曈',
  '' => '曉',
  '' => '曊',
  '' => '曋',
  '' => '曌',
  '' => '曍',
  '' => '曎',
  '' => '曏',
  '' => '曐',
  '' => '曑',
  '' => '曒',
  '' => '曓',
  '' => '曔',
  '' => '曕',
  '' => '曖',
  '' => '曗',
  '' => '曘',
  '' => '曚',
  '' => '曞',
  '' => '曟',
  '' => '曠',
  '' => '曡',
  '' => '曢',
  '' => '曣',
  '' => '曤',
  '' => '曥',
  '' => '曧',
  '' => '曨',
  '' => '曪',
  '' => '曫',
  '' => '曬',
  '' => '曭',
  '' => '曮',
  '' => '曯',
  '' => '曱',
  '' => '曵',
  '' => '曶',
  '' => '書',
  '' => '曺',
  '' => '曻',
  '' => '曽',
  '' => '朁',
  '' => '朂',
  '' => '會',
  '@' => '朄',
  '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' => '淶',
  '[' => '淸',
  '\\' => '淺',
  ']' => '淽',
  '^' => '淾',
  '_' => '淿',
  '`' => '渀',
  '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' => '￤',
  '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' => '痁',
  '[' => '痆',
  '\\' => '痋',
  ']' => '痌',
  '^' => '痎',
  '_' => '痏',
  '`' => '痐',
  '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' => '祕',
  '{' => '祘',
  '|' => '祙',
  '}' => '祡',
  '~' => '祣',
  '' => '祤',
  '' => '祦',
  '' => '祩',
  '' => '祪',
  '' => '祫',
  '' => '祬',
  '' => '祮',
  '' => '祰',
  '' => '祱',
  '' => '祲',
  '' => '祳',
  '' => '祴',
  '' => '祵',
  '' => '祶',
  '' => '祹',
  '' => '祻',
  '' => '祼',
  '' => '祽',
  '' => '祾',
  '' => '祿',
  '' => '禂',
  '' => '禃',
  '' => '禆',
  '' => '禇',
  '' => '禈',
  '' => '禉',
  '' => '禋',
  '' => '禌',
  '' => '禍',
  '' => '禎',
  '' => '禐',
  '' => '禑',
  '' => '禒',
  '' => '怠',
  '' => '耽',
  '' => '担',
  '' => '丹',
  '' => '单',
  '' => '郸',
  '' => '掸',
  '' => '胆',
  '' => '旦',
  '' => '氮',
  '' => '但',
  '' => '惮',
  '' => '淡',
  '' => '诞',
  '' => '弹',
  '' => '蛋',
  '' => '当',
  '' => '挡',
  '' => '党',
  '' => '荡',
  '' => '档',
  '' => '刀',
  '' => '捣',
  '' => '蹈',
  '' => '倒',
  '' => '岛',
  '' => '祷',
  '' => '导',
  '' => '到',
  '' => '稻',
  '' => '悼',
  '' => '道',
  '' => '盗',
  '' => '德',
  '' => '得',
  '' => '的',
  '' => '蹬',
  '' => '灯',
  '' => '登',
  '' => '等',
  '' => '瞪',
  '' => '凳',
  '' => '邓',
  '' => '堤',
  '' => '低',
  '' => '滴',
  '' => '迪',
  '' => '敌',
  '' => '笛',
  '' => '狄',
  '' => '涤',
  '' => '翟',
  '' => '嫡',
  '' => '抵',
  '' => '底',
  '' => '地',
  '' => '蒂',
  '' => '第',
  '' => '帝',
  '' => '弟',
  '' => '递',
  '' => '缔',
  '' => '颠',
  '' => '掂',
  '' => '滇',
  '' => '碘',
  '' => '点',
  '' => '典',
  '' => '靛',
  '' => '垫',
  '' => '电',
  '' => '佃',
  '' => '甸',
  '' => '店',
  '' => '惦',
  '' => '奠',
  '' => '淀',
  '' => '殿',
  '' => '碉',
  '' => '叼',
  '' => '雕',
  '' => '凋',
  '' => '刁',
  '' => '掉',
  '' => '吊',
  '' => '钓',
  '' => '调',
  '' => '跌',
  '' => '爹',
  '' => '碟',
  '' => '蝶',
  '' => '迭',
  '' => '谍',
  '' => '叠',
  '@' => '禓',
  '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' => '糧',
  '[' => '糩',
  '\\' => '糪',
  ']' => '糫',
  '^' => '糬',
  '_' => '糭',
  '`' => '糮',
  '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' => '聑',
  '{' => '聓',
  '|' => '聕',
  '}' => '聖',
  '~' => '聗',
  '' => '聙',
  '' => '聛',
  '' => '聜',
  '' => '聝',
  '' => '聞',
  '' => '聟',
  '' => '聠',
  '' => '聡',
  '' => '聢',
  '' => '聣',
  '' => '聤',
  '' => '聥',
  '' => '聦',
  '' => '聧',
  '' => '聨',
  '' => '聫',
  '' => '聬',
  '' => '聭',
  '' => '聮',
  '' => '聯',
  '' => '聰',
  '' => '聲',
  '' => '聳',
  '' => '聴',
  '' => '聵',
  '' => '聶',
  '' => '職',
  '' => '聸',
  '' => '聹',
  '' => '聺',
  '' => '聻',
  '' => '聼',
  ' ' => '聽',
  '¡' => '隆',
  '¢' => '垄',
  '£' => '拢',
  '¤' => '陇',
  '¥' => '楼',
  '¦' => '娄',
  '§' => '搂',
  '¨' => '篓',
  '©' => '漏',
  'ª' => '陋',
  '«' => '芦',
  '¬' => '卢',
  '­' => '颅',
  '®' => '庐',
  '¯' => '炉',
  '°' => '掳',
  '±' => '卤',
  '²' => '虏',
  '³' => '鲁',
  '´' => '麓',
  'µ' => '碌',
  '¶' => '露',
  '·' => '路',
  '¸' => '赂',
  '¹' => '鹿',
  'º' => '潞',
  '»' => '禄',
  '¼' => '录',
  '½' => '陆',
  '¾' => '戮',
  '¿' => '驴',
  '' => '吕',
  '' => '铝',
  '' => '侣',
  '' => '旅',
  '' => '履',
  '' => '屡',
  '' => '缕',
  '' => '虑',
  '' => '氯',
  '' => '律',
  '' => '率',
  '' => '滤',
  '' => '绿',
  '' => '峦',
  '' => '挛',
  '' => '孪',
  '' => '滦',
  '' => '卵',
  '' => '乱',
  '' => '掠',
  '' => '略',
  '' => '抡',
  '' => '轮',
  '' => '伦',
  '' => '仑',
  '' => '沦',
  '' => '纶',
  '' => '论',
  '' => '萝',
  '' => '螺',
  '' => '罗',
  '' => '逻',
  '' => '锣',
  '' => '箩',
  '' => '骡',
  '' => '裸',
  '' => '落',
  '' => '洛',
  '' => '骆',
  '' => '络',
  '' => '妈',
  '' => '麻',
  '' => '玛',
  '' => '码',
  '' => '蚂',
  '' => '马',
  '' => '骂',
  '' => '嘛',
  '' => '吗',
  '' => '埋',
  '' => '买',
  '' => '麦',
  '' => '卖',
  '' => '迈',
  '' => '脉',
  '' => '瞒',
  '' => '馒',
  '' => '蛮',
  '' => '满',
  '' => '蔓',
  '' => '曼',
  '' => '慢',
  '' => '漫',
  '@' => '聾',
  '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' => '蒢',
  '[' => '蒣',
  '\\' => '蒤',
  ']' => '蒥',
  '^' => '蒦',
  '_' => '蒧',
  '`' => '蒨',
  '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' => '蟴',
  '{' => '蟵',
  '|' => '蟶',
  '}' => '蟷',
  '~' => '蟸',
  'π' => '蟺',
  'ρ' => '蟻',
  'ς' => '蟼',
  'σ' => '蟽',
  'τ' => '蟿',
  'υ' => '蠀',
  'φ' => '蠁',
  'χ' => '蠂',
  'ψ' => '蠄',
  'ω' => '蠅',
  'ϊ' => '蠆',
  'ϋ' => '蠇',
  'ό' => '蠈',
  'ύ' => '蠉',
  'ώ' => '蠋',
  'Ϗ' => '蠌',
  'ϐ' => '蠍',
  'ϑ' => '蠎',
  'ϒ' => '蠏',
  'ϓ' => '蠐',
  'ϔ' => '蠑',
  'ϕ' => '蠒',
  'ϖ' => '蠔',
  'ϗ' => '蠗',
  'Ϙ' => '蠘',
  'ϙ' => '蠙',
  'Ϛ' => '蠚',
  'ϛ' => '蠜',
  'Ϝ' => '蠝',
  'ϝ' => '蠞',
  'Ϟ' => '蠟',
  'ϟ' => '蠠',
  'Ϡ' => '蠣',
  'ϡ' => '稀',
  'Ϣ' => '息',
  'ϣ' => '希',
  'Ϥ' => '悉',
  'ϥ' => '膝',
  'Ϧ' => '夕',
  'ϧ' => '惜',
  'Ϩ' => '熄',
  'ϩ' => '烯',
  'Ϫ' => '溪',
  'ϫ' => '汐',
  'Ϭ' => '犀',
  'ϭ' => '檄',
  'Ϯ' => '袭',
  'ϯ' => '席',
  'ϰ' => '习',
  'ϱ' => '媳',
  'ϲ' => '喜',
  'ϳ' => '铣',
  'ϴ' => '洗',
  'ϵ' => '系',
  '϶' => '隙',
  'Ϸ' => '戏',
  'ϸ' => '细',
  'Ϲ' => '瞎',
  'Ϻ' => '虾',
  'ϻ' => '匣',
  'ϼ' => '霞',
  'Ͻ' => '辖',
  'Ͼ' => '暇',
  'Ͽ' => '峡',
  '' => '侠',
  '' => '狭',
  '' => '下',
  '' => '厦',
  '' => '夏',
  '' => '吓',
  '' => '掀',
  '' => '锨',
  '' => '先',
  '' => '仙',
  '' => '鲜',
  '' => '纤',
  '' => '咸',
  '' => '贤',
  '' => '衔',
  '' => '舷',
  '' => '闲',
  '' => '涎',
  '' => '弦',
  '' => '嫌',
  '' => '显',
  '' => '险',
  '' => '现',
  '' => '献',
  '' => '县',
  '' => '腺',
  '' => '馅',
  '' => '羡',
  '' => '宪',
  '' => '陷',
  '' => '限',
  '' => '线',
  '' => '相',
  '' => '厢',
  '' => '镶',
  '' => '香',
  '' => '箱',
  '' => '襄',
  '' => '湘',
  '' => '乡',
  '' => '翔',
  '' => '祥',
  '' => '详',
  '' => '想',
  '' => '响',
  '' => '享',
  '' => '项',
  '' => '巷',
  '' => '橡',
  '' => '像',
  '' => '向',
  '' => '象',
  '' => '萧',
  '' => '硝',
  '' => '霄',
  '' => '削',
  '' => '哮',
  '' => '嚣',
  '' => '销',
  '' => '消',
  '' => '宵',
  '' => '淆',
  '' => '晓',
  '@' => '蠤',
  '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' => '諾',
  '[' => '諿',
  '\\' => '謀',
  ']' => '謁',
  '^' => '謂',
  '_' => '謃',
  '`' => '謄',
  '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' => '躾',
  '{' => '躿',
  '|' => '軀',
  '}' => '軁',
  '~' => '軂',
  '܀' => '軃',
  '܁' => '軄',
  '܂' => '軅',
  '܃' => '軆',
  '܄' => '軇',
  '܅' => '軈',
  '܆' => '軉',
  '܇' => '車',
  '܈' => '軋',
  '܉' => '軌',
  '܊' => '軍',
  '܋' => '軏',
  '܌' => '軐',
  '܍' => '軑',
  '܎' => '軒',
  '܏' => '軓',
  'ܐ' => '軔',
  'ܑ' => '軕',
  'ܒ' => '軖',
  'ܓ' => '軗',
  'ܔ' => '軘',
  'ܕ' => '軙',
  'ܖ' => '軚',
  'ܗ' => '軛',
  'ܘ' => '軜',
  'ܙ' => '軝',
  'ܚ' => '軞',
  'ܛ' => '軟',
  'ܜ' => '軠',
  'ܝ' => '軡',
  'ܞ' => '転',
  'ܟ' => '軣',
  'ܠ' => '軤',
  'ܡ' => '堋',
  'ܢ' => '堍',
  'ܣ' => '埽',
  'ܤ' => '埭',
  'ܥ' => '堀',
  'ܦ' => '堞',
  'ܧ' => '堙',
  'ܨ' => '塄',
  'ܩ' => '堠',
  'ܪ' => '塥',
  'ܫ' => '塬',
  'ܬ' => '墁',
  'ܭ' => '墉',
  'ܮ' => '墚',
  'ܯ' => '墀',
  'ܰ' => '馨',
  'ܱ' => '鼙',
  'ܲ' => '懿',
  'ܳ' => '艹',
  'ܴ' => '艽',
  'ܵ' => '艿',
  'ܶ' => '芏',
  'ܷ' => '芊',
  'ܸ' => '芨',
  'ܹ' => '芄',
  'ܺ' => '芎',
  'ܻ' => '芑',
  'ܼ' => '芗',
  'ܽ' => '芙',
  'ܾ' => '芫',
  'ܿ' => '芸',
  '' => '芾',
  '' => '芰',
  '' => '苈',
  '' => '苊',
  '' => '苣',
  '' => '芘',
  '' => '芷',
  '' => '芮',
  '' => '苋',
  '' => '苌',
  '' => '苁',
  '' => '芩',
  '' => '芴',
  '' => '芡',
  '' => '芪',
  '' => '芟',
  '' => '苄',
  '' => '苎',
  '' => '芤',
  '' => '苡',
  '' => '茉',
  '' => '苷',
  '' => '苤',
  '' => '茏',
  '' => '茇',
  '' => '苜',
  '' => '苴',
  '' => '苒',
  '' => '苘',
  '' => '茌',
  '' => '苻',
  '' => '苓',
  '' => '茑',
  '' => '茚',
  '' => '茆',
  '' => '茔',
  '' => '茕',
  '' => '苠',
  '' => '苕',
  '' => '茜',
  '' => '荑',
  '' => '荛',
  '' => '荜',
  '' => '茈',
  '' => '莒',
  '' => '茼',
  '' => '茴',
  '' => '茱',
  '' => '莛',
  '' => '荞',
  '' => '茯',
  '' => '荏',
  '' => '荇',
  '' => '荃',
  '' => '荟',
  '' => '荀',
  '' => '茗',
  '' => '荠',
  '' => '茭',
  '' => '茺',
  '' => '茳',
  '' => '荦',
  '' => '荥',
  '@' => '軥',
  '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' => '鉠',
  '[' => '鉡',
  '\\' => '鉢',
  ']' => '鉣',
  '^' => '鉤',
  '_' => '鉥',
  '`' => '鉦',
  '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' => '閦',
  '{' => '閧',
  '|' => '閨',
  '}' => '閩',
  '~' => '閪',
  '' => '閫',
  '' => '閬',
  '' => '閭',
  '' => '閮',
  '' => '閯',
  '' => '閰',
  '' => '閱',
  '' => '閲',
  '' => '閳',
  '' => '閴',
  '' => '閵',
  '' => '閶',
  '' => '閷',
  '' => '閸',
  '' => '閹',
  '' => '閺',
  '' => '閻',
  '' => '閼',
  '' => '閽',
  '' => '閾',
  '' => '閿',
  '' => '闀',
  '' => '闁',
  '' => '闂',
  '' => '闃',
  '' => '闄',
  '' => '闅',
  '' => '闆',
  '' => '闇',
  '' => '闈',
  '' => '闉',
  '' => '闊',
  '' => '闋',
  '' => '椤',
  '' => '棰',
  '' => '椋',
  '' => '椁',
  '' => '楗',
  '' => '棣',
  '' => '椐',
  '' => '楱',
  '' => '椹',
  '' => '楠',
  '' => '楂',
  '' => '楝',
  '' => '榄',
  '' => '楫',
  '' => '榀',
  '' => '榘',
  '' => '楸',
  '' => '椴',
  '' => '槌',
  '' => '榇',
  '' => '榈',
  '' => '槎',
  '' => '榉',
  '' => '楦',
  '' => '楣',
  '' => '楹',
  '' => '榛',
  '' => '榧',
  '' => '榻',
  '' => '榫',
  '' => '榭',
  '' => '槔',
  '' => '榱',
  '' => '槁',
  '' => '槊',
  '' => '槟',
  '' => '榕',
  '' => '槠',
  '' => '榍',
  '' => '槿',
  '' => '樯',
  '' => '槭',
  '' => '樗',
  '' => '樘',
  '' => '橥',
  '' => '槲',
  '' => '橄',
  '' => '樾',
  '' => '檠',
  '' => '橐',
  '' => '橛',
  '' => '樵',
  '' => '檎',
  '' => '橹',
  '' => '樽',
  '' => '樨',
  '' => '橘',
  '' => '橼',
  '' => '檑',
  '' => '檐',
  '' => '檩',
  '' => '檗',
  '' => '檫',
  '' => '猷',
  '' => '獒',
  '' => '殁',
  '' => '殂',
  '' => '殇',
  '' => '殄',
  '' => '殒',
  '' => '殓',
  '' => '殍',
  '' => '殚',
  '' => '殛',
  '' => '殡',
  '' => '殪',
  '' => '轫',
  '' => '轭',
  '' => '轱',
  '' => '轲',
  '' => '轳',
  '' => '轵',
  '' => '轶',
  '' => '轸',
  '' => '轷',
  '' => '轹',
  '' => '轺',
  '' => '轼',
  '' => '轾',
  '' => '辁',
  '' => '辂',
  '' => '辄',
  '' => '辇',
  '' => '辋',
  '@' => '闌',
  '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' => '餤',
  '[' => '餥',
  '\\' => '餦',
  ']' => '餧',
  '^' => '館',
  '_' => '餩',
  '`' => '餪',
  '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' => '鰖',
  '{' => '鰗',
  '|' => '鰘',
  '}' => '鰙',
  '~' => '鰚',
  '' => '鰛',
  '' => '鰜',
  '' => '鰝',
  '' => '鰞',
  '' => '鰟',
  '' => '鰠',
  '' => '鰡',
  '' => '鰢',
  '' => '鰣',
  '' => '鰤',
  '' => '鰥',
  '' => '鰦',
  '' => '鰧',
  '' => '鰨',
  '' => '鰩',
  '' => '鰪',
  '' => '鰫',
  '' => '鰬',
  '' => '鰭',
  '' => '鰮',
  '' => '鰯',
  '' => '鰰',
  '' => '鰱',
  '' => '鰲',
  '' => '鰳',
  '' => '鰴',
  '' => '鰵',
  '' => '鰶',
  '' => '鰷',
  '' => '鰸',
  '' => '鰹',
  '' => '鰺',
  '' => '鰻',
  '' => '觥',
  '' => '觫',
  '' => '觯',
  '' => '訾',
  '' => '謦',
  '' => '靓',
  '' => '雩',
  '' => '雳',
  '' => '雯',
  '' => '霆',
  '' => '霁',
  '' => '霈',
  '' => '霏',
  '' => '霎',
  '' => '霪',
  '' => '霭',
  '' => '霰',
  '' => '霾',
  '' => '龀',
  '' => '龃',
  '' => '龅',
  '' => '龆',
  '' => '龇',
  '' => '龈',
  '' => '龉',
  '' => '龊',
  '' => '龌',
  '' => '黾',
  '' => '鼋',
  '' => '鼍',
  '' => '隹',
  '' => '隼',
  '' => '隽',
  '' => '雎',
  '' => '雒',
  '' => '瞿',
  '' => '雠',
  '' => '銎',
  '' => '銮',
  '' => '鋈',
  '' => '錾',
  '' => '鍪',
  '' => '鏊',
  '' => '鎏',
  '' => '鐾',
  '' => '鑫',
  '' => '鱿',
  '' => '鲂',
  '' => '鲅',
  '' => '鲆',
  '' => '鲇',
  '' => '鲈',
  '' => '稣',
  '' => '鲋',
  '' => '鲎',
  '' => '鲐',
  '' => '鲑',
  '' => '鲒',
  '' => '鲔',
  '' => '鲕',
  '' => '鲚',
  '' => '鲛',
  '' => '鲞',
  '' => '鲟',
  '' => '鲠',
  '' => '鲡',
  '' => '鲢',
  '' => '鲣',
  '' => '鲥',
  '' => '鲦',
  '' => '鲧',
  '' => '鲨',
  '' => '鲩',
  '' => '鲫',
  '' => '鲭',
  '' => '鲮',
  '' => '鲰',
  '' => '鲱',
  '' => '鲲',
  '' => '鲳',
  '' => '鲴',
  '' => '鲵',
  '' => '鲶',
  '' => '鲷',
  '' => '鲺',
  '' => '鲻',
  '' => '鲼',
  '' => '鲽',
  '' => '鳄',
  '' => '鳅',
  '' => '鳆',
  '' => '鳇',
  '' => '鳊',
  '' => '鳋',
  '@' => '鰼',
  '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' => '齔',
  '[' => '齕',
  '\\' => '齖',
  ']' => '齗',
  '^' => '齘',
  '_' => '齙',
  '`' => '齚',
  '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' => '﨩',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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' => '괾',
  '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' => '늷',
  '' => '늸',
  '' => '늹',
  '' => '늺',
  '' => '늻',
  '' => '늼',
  '' => '늽',
  '' => '늾',
  '' => '늿',
  '' => '닀',
  '' => '닁',
  '' => '닂',
  '' => '닃',
  '' => '닄',
  '' => '닅',
  '' => '닆',
  '' => '닇',
  '' => '닊',
  '' => '닋',
  '' => '닍',
  '' => '닎',
  '' => '닏',
  '' => '닑',
  '' => '닓',
  '' => '닔',
  '' => '닕',
  '' => '닖',
  '' => '닗',
  '' => '닚',
  '' => '닜',
  '' => '닞',
  '' => '닟',
  '' => '닠',
  '' => '닡',
  '' => '닣',
  '' => '닧',
  '' => '닩',
  '' => '닪',
  '' => '닰',
  '' => '닱',
  '' => '닲',
  '' => '닶',
  '' => '닼',
  '' => '닽',
  '' => '닾',
  '' => '댂',
  '' => '댃',
  '' => '댅',
  '' => '댆',
  '' => '댇',
  '' => '댉',
  '' => '댊',
  '' => '댋',
  '' => '댌',
  '' => '댍',
  '' => '댎',
  '' => '댏',
  '' => '댒',
  '' => '댖',
  '' => '댗',
  '' => '댘',
  '' => '댙',
  '' => '댚',
  '' => '댛',
  '' => '댝',
  '' => '댞',
  '' => '댟',
  '' => '댠',
  '' => '댡',
  '' => '댢',
  '' => '댣',
  '' => '댤',
  '' => '댥',
  '' => '댦',
  '' => '댧',
  '' => '댨',
  '' => '댩',
  '' => '댪',
  '' => '댫',
  '' => '댬',
  '' => '댭',
  '' => '댮',
  '' => '댯',
  '' => '댰',
  '' => '댱',
  '' => '댲',
  '' => '댳',
  '' => '댴',
  '' => '댵',
  '' => '댶',
  '' => '댷',
  '' => '댸',
  '' => '댹',
  '' => '댺',
  '' => '댻',
  '' => '댼',
  '' => '댽',
  '' => '댾',
  '' => '댿',
  '' => '덀',
  '' => '덁',
  '' => '덂',
  '' => '덃',
  '' => '덄',
  '' => '덅',
  '' => '덆',
  '' => '덇',
  '' => '덈',
  '' => '덉',
  '' => '덊',
  '' => '덋',
  '' => '덌',
  '' => '덍',
  '' => '덎',
  '' => '덏',
  '' => '덐',
  '' => '덑',
  '' => '덒',
  '' => '덓',
  '' => '덗',
  '' => '덙',
  '' => '덚',
  '' => '덝',
  '' => '덠',
  '' => '덡',
  '' => '덢',
  '' => '덣',
  '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' => '뢟',
  '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' => '븓',
  '' => '븕',
  '' => '븖',
  '' => '븗',
  '' => '븘',
  '' => '븙',
  '' => '븚',
  '' => '븛',
  '' => '븞',
  '' => '븠',
  '' => '븡',
  '' => '븢',
  '' => '븣',
  '' => '븤',
  '' => '븥',
  '' => '븦',
  '' => '븧',
  '' => '븨',
  '' => '븩',
  '' => '븪',
  '' => '븫',
  '' => '븬',
  '' => '븭',
  '' => '븮',
  '' => '븯',
  '' => '븰',
  '' => '븱',
  '' => '븲',
  '' => '븳',
  '' => '븴',
  '' => '븵',
  '' => '븶',
  '' => '븷',
  '' => '븸',
  '' => '븹',
  '' => '븺',
  '' => '븻',
  '' => '븼',
  '' => '븽',
  '' => '븾',
  '' => '븿',
  '' => '빀',
  '' => '빁',
  '' => '빂',
  '' => '빃',
  '' => '빆',
  '' => '빇',
  '' => '빉',
  '' => '빊',
  '' => '빋',
  '' => '빍',
  '' => '빏',
  '' => '빐',
  '' => '빑',
  '' => '빒',
  '' => '빓',
  '' => '빖',
  '' => '빘',
  '' => '빜',
  '' => '빝',
  '' => '빞',
  '' => '빟',
  '' => '빢',
  '' => '빣',
  '' => '빥',
  '' => '빦',
  '' => '빧',
  '' => '빩',
  '' => '빫',
  '' => '빬',
  '' => '빭',
  '' => '빮',
  '' => '빯',
  '' => '빲',
  '' => '빶',
  '' => '빷',
  '' => '빸',
  '' => '빹',
  '' => '빺',
  '' => '빾',
  '' => '빿',
  '' => '뺁',
  '' => '뺂',
  '' => '뺃',
  '' => '뺅',
  '' => '뺆',
  '' => '뺇',
  '' => '뺈',
  '' => '뺉',
  '' => '뺊',
  '' => '뺋',
  '' => '뺎',
  '' => '뺒',
  '' => '뺓',
  '' => '뺔',
  '' => '뺕',
  '' => '뺖',
  '' => '뺗',
  '' => '뺚',
  '' => '뺛',
  '' => '뺜',
  '' => '뺝',
  '' => '뺞',
  '' => '뺟',
  '' => '뺠',
  '' => '뺡',
  '' => '뺢',
  '' => '뺣',
  '' => '뺤',
  '' => '뺥',
  '' => '뺦',
  '' => '뺧',
  '' => '뺩',
  '' => '뺪',
  '' => '뺫',
  '' => '뺬',
  '' => '뺭',
  '' => '뺮',
  '' => '뺯',
  '' => '뺰',
  '' => '뺱',
  '' => '뺲',
  '' => '뺳',
  '' => '뺴',
  '' => '뺵',
  '' => '뺶',
  '' => '뺷',
  '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' => '쏾',
  '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' => '쥇',
  '' => '쥈',
  '' => '쥉',
  '' => '쥊',
  '' => '쥋',
  '' => '쥌',
  '' => '쥍',
  '' => '쥎',
  '' => '쥏',
  '' => '쥒',
  '' => '쥓',
  '' => '쥕',
  '' => '쥖',
  '' => '쥗',
  '' => '쥙',
  '' => '쥚',
  '' => '쥛',
  '' => '쥜',
  '' => '쥝',
  '' => '쥞',
  '' => '쥟',
  '' => '쥢',
  '' => '쥤',
  '' => '쥥',
  '' => '쥦',
  '' => '쥧',
  '' => '쥨',
  '' => '쥩',
  '' => '쥪',
  '' => '쥫',
  '' => '쥭',
  '' => '쥮',
  '' => '쥯',
  '' => '⇒',
  '' => '⇔',
  '' => '∀',
  '' => '∃',
  '' => '´',
  '' => '～',
  '' => 'ˇ',
  '' => '˘',
  '' => '˝',
  '' => '˚',
  '' => '˙',
  '' => '¸',
  '' => '˛',
  '' => '¡',
  '' => '¿',
  '' => 'ː',
  '' => '∮',
  '' => '∑',
  '' => '∏',
  '' => '¤',
  '' => '℉',
  '' => '‰',
  '' => '◁',
  '' => '◀',
  '' => '▷',
  '' => '▶',
  '' => '♤',
  '' => '♠',
  '' => '♡',
  '' => '♥',
  '' => '♧',
  '' => '♣',
  '' => '⊙',
  '' => '◈',
  '' => '▣',
  '' => '◐',
  '' => '◑',
  '' => '▒',
  '' => '▤',
  '' => '▥',
  '' => '▨',
  '' => '▧',
  '' => '▦',
  '' => '▩',
  '' => '♨',
  '' => '☏',
  '' => '☎',
  '' => '☜',
  '' => '☞',
  '' => '¶',
  '' => '†',
  '' => '‡',
  '' => '↕',
  '' => '↗',
  '' => '↙',
  '' => '↖',
  '' => '↘',
  '' => '♭',
  '' => '♩',
  '' => '♪',
  '' => '♬',
  '' => '㉿',
  '' => '㈜',
  '' => '№',
  '' => '㏇',
  '' => '™',
  '' => '㏂',
  '' => '㏘',
  '' => '℡',
  '' => '€',
  '' => '®',
  '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' => '쯟',
  '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' => '칬',
  '' => '칮',
  '' => '칯',
  '' => '칰',
  '' => '칱',
  '' => '칲',
  '' => '칳',
  '' => '칶',
  '' => '칷',
  '' => '칹',
  '' => '칺',
  '' => '칻',
  '' => '칽',
  '' => '칾',
  '' => '칿',
  '' => '캀',
  '' => '캁',
  '' => '캂',
  '' => '캃',
  '' => '캆',
  '' => '캈',
  '' => '캊',
  '' => '캋',
  '' => '캌',
  '' => '캍',
  '' => '캎',
  '' => '캏',
  '' => '캒',
  '' => '캓',
  '' => '캕',
  '' => '캖',
  '' => '캗',
  '' => '캙',
  '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' => '턟',
  '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' => '펮',
  '' => '펯',
  '' => '펰',
  '' => '펱',
  '' => '펲',
  '' => '펳',
  '' => '펵',
  '' => '펶',
  '' => '펷',
  '' => '펹',
  '' => '펺',
  '' => '펻',
  '' => '펽',
  '' => '펾',
  '' => '펿',
  '' => '폀',
  '' => '폁',
  '' => '폂',
  '' => '폃',
  '' => '폆',
  '' => '폇',
  '' => '폊',
  '' => '폋',
  '' => '폌',
  '' => '폍',
  '' => '폎',
  '' => '폏',
  '' => '폑',
  '' => '폒',
  '' => '폓',
  '' => '폔',
  '' => '폕',
  '' => '폖',
  '' => '샥',
  '' => '샨',
  '' => '샬',
  '' => '샴',
  '' => '샵',
  '' => '샷',
  '' => '샹',
  '' => '섀',
  '' => '섄',
  '' => '섈',
  '' => '섐',
  '' => '섕',
  '' => '서',
  '' => '석',
  '' => '섞',
  '' => '섟',
  '' => '선',
  '' => '섣',
  '' => '설',
  '' => '섦',
  '' => '섧',
  '' => '섬',
  '' => '섭',
  '' => '섯',
  '' => '섰',
  '' => '성',
  '' => '섶',
  '' => '세',
  '' => '섹',
  '' => '센',
  '' => '셀',
  '' => '셈',
  '' => '셉',
  '' => '셋',
  '' => '셌',
  '' => '셍',
  '' => '셔',
  '' => '셕',
  '' => '션',
  '' => '셜',
  '' => '셤',
  '' => '셥',
  '' => '셧',
  '' => '셨',
  '' => '셩',
  '' => '셰',
  '' => '셴',
  '' => '셸',
  '' => '솅',
  '' => '소',
  '' => '속',
  '' => '솎',
  '' => '손',
  '' => '솔',
  '' => '솖',
  '' => '솜',
  '' => '솝',
  '' => '솟',
  '' => '송',
  '' => '솥',
  '' => '솨',
  '' => '솩',
  '' => '솬',
  '' => '솰',
  '' => '솽',
  '' => '쇄',
  '' => '쇈',
  '' => '쇌',
  '' => '쇔',
  '' => '쇗',
  '' => '쇘',
  '' => '쇠',
  '' => '쇤',
  '' => '쇨',
  '' => '쇰',
  '' => '쇱',
  '' => '쇳',
  '' => '쇼',
  '' => '쇽',
  '' => '숀',
  '' => '숄',
  '' => '숌',
  '' => '숍',
  '' => '숏',
  '' => '숑',
  '' => '수',
  '' => '숙',
  '' => '순',
  '' => '숟',
  '' => '술',
  '' => '숨',
  '' => '숩',
  '' => '숫',
  '' => '숭',
  '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' => '홡',
  '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' => '힣',
  'ơ' => '퉤',
  'Ƣ' => '튀',
  'ƣ' => '튁',
  'Ƥ' => '튄',
  'ƥ' => '튈',
  'Ʀ' => '튐',
  'Ƨ' => '튑',
  'ƨ' => '튕',
  'Ʃ' => '튜',
  'ƪ' => '튠',
  'ƫ' => '튤',
  'Ƭ' => '튬',
  'ƭ' => '튱',
  'Ʈ' => '트',
  'Ư' => '특',
  'ư' => '튼',
  'Ʊ' => '튿',
  'Ʋ' => '틀',
  'Ƴ' => '틂',
  'ƴ' => '틈',
  'Ƶ' => '틉',
  'ƶ' => '틋',
  'Ʒ' => '틔',
  'Ƹ' => '틘',
  'ƹ' => '틜',
  'ƺ' => '틤',
  'ƻ' => '틥',
  'Ƽ' => '티',
  'ƽ' => '틱',
  'ƾ' => '틴',
  'ƿ' => '틸',
  '' => '팀',
  '' => '팁',
  '' => '팃',
  '' => '팅',
  '' => '파',
  '' => '팍',
  '' => '팎',
  '' => '판',
  '' => '팔',
  '' => '팖',
  '' => '팜',
  '' => '팝',
  '' => '팟',
  '' => '팠',
  '' => '팡',
  '' => '팥',
  '' => '패',
  '' => '팩',
  '' => '팬',
  '' => '팰',
  '' => '팸',
  '' => '팹',
  '' => '팻',
  '' => '팼',
  '' => '팽',
  '' => '퍄',
  '' => '퍅',
  '' => '퍼',
  '' => '퍽',
  '' => '펀',
  '' => '펄',
  '' => '펌',
  '' => '펍',
  '' => '펏',
  '' => '펐',
  '' => '펑',
  '' => '페',
  '' => '펙',
  '' => '펜',
  '' => '펠',
  '' => '펨',
  '' => '펩',
  '' => '펫',
  '' => '펭',
  '' => '펴',
  '' => '편',
  '' => '펼',
  '' => '폄',
  '' => '폅',
  '' => '폈',
  '' => '평',
  '' => '폐',
  '' => '폘',
  '' => '폡',
  '' => '폣',
  '' => '포',
  '' => '폭',
  '' => '폰',
  '' => '폴',
  '' => '폼',
  '' => '폽',
  '' => '폿',
  '' => '퐁',
  'ǡ' => '퐈',
  'Ǣ' => '퐝',
  'ǣ' => '푀',
  'Ǥ' => '푄',
  'ǥ' => '표',
  'Ǧ' => '푠',
  'ǧ' => '푤',
  'Ǩ' => '푭',
  'ǩ' => '푯',
  'Ǫ' => '푸',
  'ǫ' => '푹',
  'Ǭ' => '푼',
  'ǭ' => '푿',
  'Ǯ' => '풀',
  'ǯ' => '풂',
  'ǰ' => '품',
  'Ǳ' => '풉',
  'ǲ' => '풋',
  'ǳ' => '풍',
  'Ǵ' => '풔',
  'ǵ' => '풩',
  'Ƕ' => '퓌',
  'Ƿ' => '퓐',
  'Ǹ' => '퓔',
  'ǹ' => '퓜',
  'Ǻ' => '퓟',
  'ǻ' => '퓨',
  'Ǽ' => '퓬',
  'ǽ' => '퓰',
  'Ǿ' => '퓸',
  'ǿ' => '퓻',
  '' => '퓽',
  '' => '프',
  '' => '픈',
  '' => '플',
  '' => '픔',
  '' => '픕',
  '' => '픗',
  '' => '피',
  '' => '픽',
  '' => '핀',
  '' => '필',
  '' => '핌',
  '' => '핍',
  '' => '핏',
  '' => '핑',
  '' => '하',
  '' => '학',
  '' => '한',
  '' => '할',
  '' => '핥',
  '' => '함',
  '' => '합',
  '' => '핫',
  '' => '항',
  '' => '해',
  '' => '핵',
  '' => '핸',
  '' => '핼',
  '' => '햄',
  '' => '햅',
  '' => '햇',
  '' => '했',
  '' => '행',
  '' => '햐',
  '' => '향',
  '' => '허',
  '' => '헉',
  '' => '헌',
  '' => '헐',
  '' => '헒',
  '' => '험',
  '' => '헙',
  '' => '헛',
  '' => '헝',
  '' => '헤',
  '' => '헥',
  '' => '헨',
  '' => '헬',
  '' => '헴',
  '' => '헵',
  '' => '헷',
  '' => '헹',
  '' => '혀',
  '' => '혁',
  '' => '현',
  '' => '혈',
  '' => '혐',
  '' => '협',
  '' => '혓',
  '' => '혔',
  '' => '형',
  '' => '혜',
  '' => '혠',
  'ȡ' => '혤',
  'Ȣ' => '혭',
  'ȣ' => '호',
  'Ȥ' => '혹',
  'ȥ' => '혼',
  'Ȧ' => '홀',
  'ȧ' => '홅',
  'Ȩ' => '홈',
  'ȩ' => '홉',
  'Ȫ' => '홋',
  'ȫ' => '홍',
  'Ȭ' => '홑',
  'ȭ' => '화',
  'Ȯ' => '확',
  'ȯ' => '환',
  'Ȱ' => '활',
  'ȱ' => '홧',
  'Ȳ' => '황',
  'ȳ' => '홰',
  'ȴ' => '홱',
  'ȵ' => '홴',
  'ȶ' => '횃',
  'ȷ' => '횅',
  'ȸ' => '회',
  'ȹ' => '획',
  'Ⱥ' => '횐',
  'Ȼ' => '횔',
  'ȼ' => '횝',
  'Ƚ' => '횟',
  'Ⱦ' => '횡',
  'ȿ' => '효',
  '' => '횬',
  '' => '횰',
  '' => '횹',
  '' => '횻',
  '' => '후',
  '' => '훅',
  '' => '훈',
  '' => '훌',
  '' => '훑',
  '' => '훔',
  '' => '훗',
  '' => '훙',
  '' => '훠',
  '' => '훤',
  '' => '훨',
  '' => '훰',
  '' => '훵',
  '' => '훼',
  '' => '훽',
  '' => '휀',
  '' => '휄',
  '' => '휑',
  '' => '휘',
  '' => '휙',
  '' => '휜',
  '' => '휠',
  '' => '휨',
  '' => '휩',
  '' => '휫',
  '' => '휭',
  '' => '휴',
  '' => '휵',
  '' => '휸',
  '' => '휼',
  '' => '흄',
  '' => '흇',
  '' => '흉',
  '' => '흐',
  '' => '흑',
  '' => '흔',
  '' => '흖',
  '' => '흗',
  '' => '흘',
  '' => '흙',
  '' => '흠',
  '' => '흡',
  '' => '흣',
  '' => '흥',
  '' => '흩',
  '' => '희',
  '' => '흰',
  '' => '흴',
  '' => '흼',
  '' => '흽',
  '' => '힁',
  '' => '히',
  '' => '힉',
  '' => '힌',
  '' => '힐',
  '' => '힘',
  '' => '힙',
  '' => '힛',
  '' => '힝',
  'ʡ' => '伽',
  'ʢ' => '佳',
  'ʣ' => '假',
  'ʤ' => '價',
  'ʥ' => '加',
  'ʦ' => '可',
  'ʧ' => '呵',
  'ʨ' => '哥',
  'ʩ' => '嘉',
  'ʪ' => '嫁',
  'ʫ' => '家',
  'ʬ' => '暇',
  'ʭ' => '架',
  'ʮ' => '枷',
  'ʯ' => '柯',
  'ʰ' => '歌',
  'ʱ' => '珂',
  'ʲ' => '痂',
  'ʳ' => '稼',
  'ʴ' => '苛',
  'ʵ' => '茄',
  'ʶ' => '街',
  'ʷ' => '袈',
  'ʸ' => '訶',
  'ʹ' => '賈',
  'ʺ' => '跏',
  'ʻ' => '軻',
  'ʼ' => '迦',
  'ʽ' => '駕',
  'ʾ' => '刻',
  'ʿ' => '却',
  '' => '各',
  '' => '恪',
  '' => '慤',
  '' => '殼',
  '' => '珏',
  '' => '脚',
  '' => '覺',
  '' => '角',
  '' => '閣',
  '' => '侃',
  '' => '刊',
  '' => '墾',
  '' => '奸',
  '' => '姦',
  '' => '干',
  '' => '幹',
  '' => '懇',
  '' => '揀',
  '' => '杆',
  '' => '柬',
  '' => '桿',
  '' => '澗',
  '' => '癎',
  '' => '看',
  '' => '磵',
  '' => '稈',
  '' => '竿',
  '' => '簡',
  '' => '肝',
  '' => '艮',
  '' => '艱',
  '' => '諫',
  '' => '間',
  '' => '乫',
  '' => '喝',
  '' => '曷',
  '' => '渴',
  '' => '碣',
  '' => '竭',
  '' => '葛',
  '' => '褐',
  '' => '蝎',
  '' => '鞨',
  '' => '勘',
  '' => '坎',
  '' => '堪',
  '' => '嵌',
  '' => '感',
  '' => '憾',
  '' => '戡',
  '' => '敢',
  '' => '柑',
  '' => '橄',
  '' => '減',
  '' => '甘',
  '' => '疳',
  '' => '監',
  '' => '瞰',
  '' => '紺',
  '' => '邯',
  '' => '鑑',
  '' => '鑒',
  '' => '龕',
  'ˡ' => '匣',
  'ˢ' => '岬',
  'ˣ' => '甲',
  'ˤ' => '胛',
  '˥' => '鉀',
  '˦' => '閘',
  '˧' => '剛',
  '˨' => '堈',
  '˩' => '姜',
  '˪' => '岡',
  '˫' => '崗',
  'ˬ' => '康',
  '˭' => '强',
  'ˮ' => '彊',
  '˯' => '慷',
  '˰' => '江',
  '˱' => '畺',
  '˲' => '疆',
  '˳' => '糠',
  '˴' => '絳',
  '˵' => '綱',
  '˶' => '羌',
  '˷' => '腔',
  '˸' => '舡',
  '˹' => '薑',
  '˺' => '襁',
  '˻' => '講',
  '˼' => '鋼',
  '˽' => '降',
  '˾' => '鱇',
  '˿' => '介',
  '' => '价',
  '' => '個',
  '' => '凱',
  '' => '塏',
  '' => '愷',
  '' => '愾',
  '' => '慨',
  '' => '改',
  '' => '槪',
  '' => '漑',
  '' => '疥',
  '' => '皆',
  '' => '盖',
  '' => '箇',
  '' => '芥',
  '' => '蓋',
  '' => '豈',
  '' => '鎧',
  '' => '開',
  '' => '喀',
  '' => '客',
  '' => '坑',
  '' => '更',
  '' => '粳',
  '' => '羹',
  '' => '醵',
  '' => '倨',
  '' => '去',
  '' => '居',
  '' => '巨',
  '' => '拒',
  '' => '据',
  '' => '據',
  '' => '擧',
  '' => '渠',
  '' => '炬',
  '' => '祛',
  '' => '距',
  '' => '踞',
  '' => '車',
  '' => '遽',
  '' => '鉅',
  '' => '鋸',
  '' => '乾',
  '' => '件',
  '' => '健',
  '' => '巾',
  '' => '建',
  '' => '愆',
  '' => '楗',
  '' => '腱',
  '' => '虔',
  '' => '蹇',
  '' => '鍵',
  '' => '騫',
  '' => '乞',
  '' => '傑',
  '' => '杰',
  '' => '桀',
  '' => '儉',
  '' => '劍',
  '' => '劒',
  '' => '檢',
  '̡' => '瞼',
  '̢' => '鈐',
  '̣' => '黔',
  '̤' => '劫',
  '̥' => '怯',
  '̦' => '迲',
  '̧' => '偈',
  '̨' => '憩',
  '̩' => '揭',
  '̪' => '擊',
  '̫' => '格',
  '̬' => '檄',
  '̭' => '激',
  '̮' => '膈',
  '̯' => '覡',
  '̰' => '隔',
  '̱' => '堅',
  '̲' => '牽',
  '̳' => '犬',
  '̴' => '甄',
  '̵' => '絹',
  '̶' => '繭',
  '̷' => '肩',
  '̸' => '見',
  '̹' => '譴',
  '̺' => '遣',
  '̻' => '鵑',
  '̼' => '抉',
  '̽' => '決',
  '̾' => '潔',
  '̿' => '結',
  '' => '缺',
  '' => '訣',
  '' => '兼',
  '' => '慊',
  '' => '箝',
  '' => '謙',
  '' => '鉗',
  '' => '鎌',
  '' => '京',
  '' => '俓',
  '' => '倞',
  '' => '傾',
  '' => '儆',
  '' => '勁',
  '' => '勍',
  '' => '卿',
  '' => '坰',
  '' => '境',
  '' => '庚',
  '' => '徑',
  '' => '慶',
  '' => '憬',
  '' => '擎',
  '' => '敬',
  '' => '景',
  '' => '暻',
  '' => '更',
  '' => '梗',
  '' => '涇',
  '' => '炅',
  '' => '烱',
  '' => '璟',
  '' => '璥',
  '' => '瓊',
  '' => '痙',
  '' => '硬',
  '' => '磬',
  '' => '竟',
  '' => '競',
  '' => '絅',
  '' => '經',
  '' => '耕',
  '' => '耿',
  '' => '脛',
  '' => '莖',
  '' => '警',
  '' => '輕',
  '' => '逕',
  '' => '鏡',
  '' => '頃',
  '' => '頸',
  '' => '驚',
  '' => '鯨',
  '' => '係',
  '' => '啓',
  '' => '堺',
  '' => '契',
  '' => '季',
  '' => '屆',
  '' => '悸',
  '' => '戒',
  '' => '桂',
  '' => '械',
  '͡' => '棨',
  '͢' => '溪',
  'ͣ' => '界',
  'ͤ' => '癸',
  'ͥ' => '磎',
  'ͦ' => '稽',
  'ͧ' => '系',
  'ͨ' => '繫',
  'ͩ' => '繼',
  'ͪ' => '計',
  'ͫ' => '誡',
  'ͬ' => '谿',
  'ͭ' => '階',
  'ͮ' => '鷄',
  'ͯ' => '古',
  'Ͱ' => '叩',
  'ͱ' => '告',
  'Ͳ' => '呱',
  'ͳ' => '固',
  'ʹ' => '姑',
  '͵' => '孤',
  'Ͷ' => '尻',
  'ͷ' => '庫',
  '͸' => '拷',
  '͹' => '攷',
  'ͺ' => '故',
  'ͻ' => '敲',
  'ͼ' => '暠',
  'ͽ' => '枯',
  ';' => '槁',
  'Ϳ' => '沽',
  '' => '痼',
  '' => '皐',
  '' => '睾',
  '' => '稿',
  '' => '羔',
  '' => '考',
  '' => '股',
  '' => '膏',
  '' => '苦',
  '' => '苽',
  '' => '菰',
  '' => '藁',
  '' => '蠱',
  '' => '袴',
  '' => '誥',
  '' => '賈',
  '' => '辜',
  '' => '錮',
  '' => '雇',
  '' => '顧',
  '' => '高',
  '' => '鼓',
  '' => '哭',
  '' => '斛',
  '' => '曲',
  '' => '梏',
  '' => '穀',
  '' => '谷',
  '' => '鵠',
  '' => '困',
  '' => '坤',
  '' => '崑',
  '' => '昆',
  '' => '梱',
  '' => '棍',
  '' => '滾',
  '' => '琨',
  '' => '袞',
  '' => '鯤',
  '' => '汨',
  '' => '滑',
  '' => '骨',
  '' => '供',
  '' => '公',
  '' => '共',
  '' => '功',
  '' => '孔',
  '' => '工',
  '' => '恐',
  '' => '恭',
  '' => '拱',
  '' => '控',
  '' => '攻',
  '' => '珙',
  '' => '空',
  '' => '蚣',
  '' => '貢',
  '' => '鞏',
  '' => '串',
  '' => '寡',
  '' => '戈',
  '' => '果',
  '' => '瓜',
  'Ρ' => '科',
  '΢' => '菓',
  'Σ' => '誇',
  'Τ' => '課',
  'Υ' => '跨',
  'Φ' => '過',
  'Χ' => '鍋',
  'Ψ' => '顆',
  'Ω' => '廓',
  'Ϊ' => '槨',
  'Ϋ' => '藿',
  'ά' => '郭',
  'έ' => '串',
  'ή' => '冠',
  'ί' => '官',
  'ΰ' => '寬',
  'α' => '慣',
  'β' => '棺',
  'γ' => '款',
  'δ' => '灌',
  'ε' => '琯',
  'ζ' => '瓘',
  'η' => '管',
  'θ' => '罐',
  'ι' => '菅',
  'κ' => '觀',
  'λ' => '貫',
  'μ' => '關',
  'ν' => '館',
  'ξ' => '刮',
  'ο' => '恝',
  '' => '括',
  '' => '适',
  '' => '侊',
  '' => '光',
  '' => '匡',
  '' => '壙',
  '' => '廣',
  '' => '曠',
  '' => '洸',
  '' => '炚',
  '' => '狂',
  '' => '珖',
  '' => '筐',
  '' => '胱',
  '' => '鑛',
  '' => '卦',
  '' => '掛',
  '' => '罫',
  '' => '乖',
  '' => '傀',
  '' => '塊',
  '' => '壞',
  '' => '怪',
  '' => '愧',
  '' => '拐',
  '' => '槐',
  '' => '魁',
  '' => '宏',
  '' => '紘',
  '' => '肱',
  '' => '轟',
  '' => '交',
  '' => '僑',
  '' => '咬',
  '' => '喬',
  '' => '嬌',
  '' => '嶠',
  '' => '巧',
  '' => '攪',
  '' => '敎',
  '' => '校',
  '' => '橋',
  '' => '狡',
  '' => '皎',
  '' => '矯',
  '' => '絞',
  '' => '翹',
  '' => '膠',
  '' => '蕎',
  '' => '蛟',
  '' => '較',
  '' => '轎',
  '' => '郊',
  '' => '餃',
  '' => '驕',
  '' => '鮫',
  '' => '丘',
  '' => '久',
  '' => '九',
  '' => '仇',
  '' => '俱',
  '' => '具',
  '' => '勾',
  'ϡ' => '區',
  'Ϣ' => '口',
  'ϣ' => '句',
  'Ϥ' => '咎',
  'ϥ' => '嘔',
  'Ϧ' => '坵',
  'ϧ' => '垢',
  'Ϩ' => '寇',
  'ϩ' => '嶇',
  'Ϫ' => '廐',
  'ϫ' => '懼',
  'Ϭ' => '拘',
  'ϭ' => '救',
  'Ϯ' => '枸',
  'ϯ' => '柩',
  'ϰ' => '構',
  'ϱ' => '歐',
  'ϲ' => '毆',
  'ϳ' => '毬',
  'ϴ' => '求',
  'ϵ' => '溝',
  '϶' => '灸',
  'Ϸ' => '狗',
  'ϸ' => '玖',
  'Ϲ' => '球',
  'Ϻ' => '瞿',
  'ϻ' => '矩',
  'ϼ' => '究',
  'Ͻ' => '絿',
  'Ͼ' => '耉',
  'Ͽ' => '臼',
  '' => '舅',
  '' => '舊',
  '' => '苟',
  '' => '衢',
  '' => '謳',
  '' => '購',
  '' => '軀',
  '' => '逑',
  '' => '邱',
  '' => '鉤',
  '' => '銶',
  '' => '駒',
  '' => '驅',
  '' => '鳩',
  '' => '鷗',
  '' => '龜',
  '' => '國',
  '' => '局',
  '' => '菊',
  '' => '鞠',
  '' => '鞫',
  '' => '麴',
  '' => '君',
  '' => '窘',
  '' => '群',
  '' => '裙',
  '' => '軍',
  '' => '郡',
  '' => '堀',
  '' => '屈',
  '' => '掘',
  '' => '窟',
  '' => '宮',
  '' => '弓',
  '' => '穹',
  '' => '窮',
  '' => '芎',
  '' => '躬',
  '' => '倦',
  '' => '券',
  '' => '勸',
  '' => '卷',
  '' => '圈',
  '' => '拳',
  '' => '捲',
  '' => '權',
  '' => '淃',
  '' => '眷',
  '' => '厥',
  '' => '獗',
  '' => '蕨',
  '' => '蹶',
  '' => '闕',
  '' => '机',
  '' => '櫃',
  '' => '潰',
  '' => '詭',
  '' => '軌',
  '' => '饋',
  '' => '句',
  '' => '晷',
  '' => '歸',
  '' => '貴',
  'С' => '鬼',
  'Т' => '龜',
  'У' => '叫',
  'Ф' => '圭',
  'Х' => '奎',
  'Ц' => '揆',
  'Ч' => '槻',
  'Ш' => '珪',
  'Щ' => '硅',
  'Ъ' => '窺',
  'Ы' => '竅',
  'Ь' => '糾',
  'Э' => '葵',
  'Ю' => '規',
  'Я' => '赳',
  'а' => '逵',
  'б' => '閨',
  'в' => '勻',
  'г' => '均',
  'д' => '畇',
  'е' => '筠',
  'ж' => '菌',
  'з' => '鈞',
  'и' => '龜',
  'й' => '橘',
  'к' => '克',
  'л' => '剋',
  'м' => '劇',
  'н' => '戟',
  'о' => '棘',
  'п' => '極',
  '' => '隙',
  '' => '僅',
  '' => '劤',
  '' => '勤',
  '' => '懃',
  '' => '斤',
  '' => '根',
  '' => '槿',
  '' => '瑾',
  '' => '筋',
  '' => '芹',
  '' => '菫',
  '' => '覲',
  '' => '謹',
  '' => '近',
  '' => '饉',
  '' => '契',
  '' => '今',
  '' => '妗',
  '' => '擒',
  '' => '昑',
  '' => '檎',
  '' => '琴',
  '' => '禁',
  '' => '禽',
  '' => '芩',
  '' => '衾',
  '' => '衿',
  '' => '襟',
  '' => '金',
  '' => '錦',
  '' => '伋',
  '' => '及',
  '' => '急',
  '' => '扱',
  '' => '汲',
  '' => '級',
  '' => '給',
  '' => '亘',
  '' => '兢',
  '' => '矜',
  '' => '肯',
  '' => '企',
  '' => '伎',
  '' => '其',
  '' => '冀',
  '' => '嗜',
  '' => '器',
  '' => '圻',
  '' => '基',
  '' => '埼',
  '' => '夔',
  '' => '奇',
  '' => '妓',
  '' => '寄',
  '' => '岐',
  '' => '崎',
  '' => '己',
  '' => '幾',
  '' => '忌',
  '' => '技',
  '' => '旗',
  '' => '旣',
  'ѡ' => '朞',
  'Ѣ' => '期',
  'ѣ' => '杞',
  'Ѥ' => '棋',
  'ѥ' => '棄',
  'Ѧ' => '機',
  'ѧ' => '欺',
  'Ѩ' => '氣',
  'ѩ' => '汽',
  'Ѫ' => '沂',
  'ѫ' => '淇',
  'Ѭ' => '玘',
  'ѭ' => '琦',
  'Ѯ' => '琪',
  'ѯ' => '璂',
  'Ѱ' => '璣',
  'ѱ' => '畸',
  'Ѳ' => '畿',
  'ѳ' => '碁',
  'Ѵ' => '磯',
  'ѵ' => '祁',
  'Ѷ' => '祇',
  'ѷ' => '祈',
  'Ѹ' => '祺',
  'ѹ' => '箕',
  'Ѻ' => '紀',
  'ѻ' => '綺',
  'Ѽ' => '羈',
  'ѽ' => '耆',
  'Ѿ' => '耭',
  'ѿ' => '肌',
  '' => '記',
  '' => '譏',
  '' => '豈',
  '' => '起',
  '' => '錡',
  '' => '錤',
  '' => '飢',
  '' => '饑',
  '' => '騎',
  '' => '騏',
  '' => '驥',
  '' => '麒',
  '' => '緊',
  '' => '佶',
  '' => '吉',
  '' => '拮',
  '' => '桔',
  '' => '金',
  '' => '喫',
  '' => '儺',
  '' => '喇',
  '' => '奈',
  '' => '娜',
  '' => '懦',
  '' => '懶',
  '' => '拏',
  '' => '拿',
  '' => '癩',
  '' => '羅',
  '' => '蘿',
  '' => '螺',
  '' => '裸',
  '' => '邏',
  '' => '那',
  '' => '樂',
  '' => '洛',
  '' => '烙',
  '' => '珞',
  '' => '落',
  '' => '諾',
  '' => '酪',
  '' => '駱',
  '' => '亂',
  '' => '卵',
  '' => '暖',
  '' => '欄',
  '' => '煖',
  '' => '爛',
  '' => '蘭',
  '' => '難',
  '' => '鸞',
  '' => '捏',
  '' => '捺',
  '' => '南',
  '' => '嵐',
  '' => '枏',
  '' => '楠',
  '' => '湳',
  '' => '濫',
  '' => '男',
  '' => '藍',
  '' => '襤',
  '' => '拉',
  'ҡ' => '納',
  'Ң' => '臘',
  'ң' => '蠟',
  'Ҥ' => '衲',
  'ҥ' => '囊',
  'Ҧ' => '娘',
  'ҧ' => '廊',
  'Ҩ' => '朗',
  'ҩ' => '浪',
  'Ҫ' => '狼',
  'ҫ' => '郎',
  'Ҭ' => '乃',
  'ҭ' => '來',
  'Ү' => '內',
  'ү' => '奈',
  'Ұ' => '柰',
  'ұ' => '耐',
  'Ҳ' => '冷',
  'ҳ' => '女',
  'Ҵ' => '年',
  'ҵ' => '撚',
  'Ҷ' => '秊',
  'ҷ' => '念',
  'Ҹ' => '恬',
  'ҹ' => '拈',
  'Һ' => '捻',
  'һ' => '寧',
  'Ҽ' => '寗',
  'ҽ' => '努',
  'Ҿ' => '勞',
  'ҿ' => '奴',
  '' => '弩',
  '' => '怒',
  '' => '擄',
  '' => '櫓',
  '' => '爐',
  '' => '瑙',
  '' => '盧',
  '' => '老',
  '' => '蘆',
  '' => '虜',
  '' => '路',
  '' => '露',
  '' => '駑',
  '' => '魯',
  '' => '鷺',
  '' => '碌',
  '' => '祿',
  '' => '綠',
  '' => '菉',
  '' => '錄',
  '' => '鹿',
  '' => '論',
  '' => '壟',
  '' => '弄',
  '' => '濃',
  '' => '籠',
  '' => '聾',
  '' => '膿',
  '' => '農',
  '' => '惱',
  '' => '牢',
  '' => '磊',
  '' => '腦',
  '' => '賂',
  '' => '雷',
  '' => '尿',
  '' => '壘',
  '' => '屢',
  '' => '樓',
  '' => '淚',
  '' => '漏',
  '' => '累',
  '' => '縷',
  '' => '陋',
  '' => '嫩',
  '' => '訥',
  '' => '杻',
  '' => '紐',
  '' => '勒',
  '' => '肋',
  '' => '凜',
  '' => '凌',
  '' => '稜',
  '' => '綾',
  '' => '能',
  '' => '菱',
  '' => '陵',
  '' => '尼',
  '' => '泥',
  '' => '匿',
  '' => '溺',
  '' => '多',
  '' => '茶',
  'ӡ' => '丹',
  'Ӣ' => '亶',
  'ӣ' => '但',
  'Ӥ' => '單',
  'ӥ' => '團',
  'Ӧ' => '壇',
  'ӧ' => '彖',
  'Ө' => '斷',
  'ө' => '旦',
  'Ӫ' => '檀',
  'ӫ' => '段',
  'Ӭ' => '湍',
  'ӭ' => '短',
  'Ӯ' => '端',
  'ӯ' => '簞',
  'Ӱ' => '緞',
  'ӱ' => '蛋',
  'Ӳ' => '袒',
  'ӳ' => '鄲',
  'Ӵ' => '鍛',
  'ӵ' => '撻',
  'Ӷ' => '澾',
  'ӷ' => '獺',
  'Ӹ' => '疸',
  'ӹ' => '達',
  'Ӻ' => '啖',
  'ӻ' => '坍',
  'Ӽ' => '憺',
  'ӽ' => '擔',
  'Ӿ' => '曇',
  'ӿ' => '淡',
  '' => '湛',
  '' => '潭',
  '' => '澹',
  '' => '痰',
  '' => '聃',
  '' => '膽',
  '' => '蕁',
  '' => '覃',
  '' => '談',
  '' => '譚',
  '' => '錟',
  '' => '沓',
  '' => '畓',
  '' => '答',
  '' => '踏',
  '' => '遝',
  '' => '唐',
  '' => '堂',
  '' => '塘',
  '' => '幢',
  '' => '戇',
  '' => '撞',
  '' => '棠',
  '' => '當',
  '' => '糖',
  '' => '螳',
  '' => '黨',
  '' => '代',
  '' => '垈',
  '' => '坮',
  '' => '大',
  '' => '對',
  '' => '岱',
  '' => '帶',
  '' => '待',
  '' => '戴',
  '' => '擡',
  '' => '玳',
  '' => '臺',
  '' => '袋',
  '' => '貸',
  '' => '隊',
  '' => '黛',
  '' => '宅',
  '' => '德',
  '' => '悳',
  '' => '倒',
  '' => '刀',
  '' => '到',
  '' => '圖',
  '' => '堵',
  '' => '塗',
  '' => '導',
  '' => '屠',
  '' => '島',
  '' => '嶋',
  '' => '度',
  '' => '徒',
  '' => '悼',
  '' => '挑',
  '' => '掉',
  '' => '搗',
  '' => '桃',
  'ԡ' => '棹',
  'Ԣ' => '櫂',
  'ԣ' => '淘',
  'Ԥ' => '渡',
  'ԥ' => '滔',
  'Ԧ' => '濤',
  'ԧ' => '燾',
  'Ԩ' => '盜',
  'ԩ' => '睹',
  'Ԫ' => '禱',
  'ԫ' => '稻',
  'Ԭ' => '萄',
  'ԭ' => '覩',
  'Ԯ' => '賭',
  'ԯ' => '跳',
  '԰' => '蹈',
  'Ա' => '逃',
  'Բ' => '途',
  'Գ' => '道',
  'Դ' => '都',
  'Ե' => '鍍',
  'Զ' => '陶',
  'Է' => '韜',
  'Ը' => '毒',
  'Թ' => '瀆',
  'Ժ' => '牘',
  'Ի' => '犢',
  'Լ' => '獨',
  'Խ' => '督',
  'Ծ' => '禿',
  'Կ' => '篤',
  '' => '纛',
  '' => '讀',
  '' => '墩',
  '' => '惇',
  '' => '敦',
  '' => '旽',
  '' => '暾',
  '' => '沌',
  '' => '焞',
  '' => '燉',
  '' => '豚',
  '' => '頓',
  '' => '乭',
  '' => '突',
  '' => '仝',
  '' => '冬',
  '' => '凍',
  '' => '動',
  '' => '同',
  '' => '憧',
  '' => '東',
  '' => '桐',
  '' => '棟',
  '' => '洞',
  '' => '潼',
  '' => '疼',
  '' => '瞳',
  '' => '童',
  '' => '胴',
  '' => '董',
  '' => '銅',
  '' => '兜',
  '' => '斗',
  '' => '杜',
  '' => '枓',
  '' => '痘',
  '' => '竇',
  '' => '荳',
  '' => '讀',
  '' => '豆',
  '' => '逗',
  '' => '頭',
  '' => '屯',
  '' => '臀',
  '' => '芚',
  '' => '遁',
  '' => '遯',
  '' => '鈍',
  '' => '得',
  '' => '嶝',
  '' => '橙',
  '' => '燈',
  '' => '登',
  '' => '等',
  '' => '藤',
  '' => '謄',
  '' => '鄧',
  '' => '騰',
  '' => '喇',
  '' => '懶',
  '' => '拏',
  '' => '癩',
  '' => '羅',
  'ա' => '蘿',
  'բ' => '螺',
  'գ' => '裸',
  'դ' => '邏',
  'ե' => '樂',
  'զ' => '洛',
  'է' => '烙',
  'ը' => '珞',
  'թ' => '絡',
  'ժ' => '落',
  'ի' => '諾',
  'լ' => '酪',
  'խ' => '駱',
  'ծ' => '丹',
  'կ' => '亂',
  'հ' => '卵',
  'ձ' => '欄',
  'ղ' => '欒',
  'ճ' => '瀾',
  'մ' => '爛',
  'յ' => '蘭',
  'ն' => '鸞',
  'շ' => '剌',
  'ո' => '辣',
  'չ' => '嵐',
  'պ' => '擥',
  'ջ' => '攬',
  'ռ' => '欖',
  'ս' => '濫',
  'վ' => '籃',
  'տ' => '纜',
  '' => '藍',
  '' => '襤',
  '' => '覽',
  '' => '拉',
  '' => '臘',
  '' => '蠟',
  '' => '廊',
  '' => '朗',
  '' => '浪',
  '' => '狼',
  '' => '琅',
  '' => '瑯',
  '' => '螂',
  '' => '郞',
  '' => '來',
  '' => '崍',
  '' => '徠',
  '' => '萊',
  '' => '冷',
  '' => '掠',
  '' => '略',
  '' => '亮',
  '' => '倆',
  '' => '兩',
  '' => '凉',
  '' => '梁',
  '' => '樑',
  '' => '粮',
  '' => '粱',
  '' => '糧',
  '' => '良',
  '' => '諒',
  '' => '輛',
  '' => '量',
  '' => '侶',
  '' => '儷',
  '' => '勵',
  '' => '呂',
  '' => '廬',
  '' => '慮',
  '' => '戾',
  '' => '旅',
  '' => '櫚',
  '' => '濾',
  '' => '礪',
  '' => '藜',
  '' => '蠣',
  '' => '閭',
  '' => '驢',
  '' => '驪',
  '' => '麗',
  '' => '黎',
  '' => '力',
  '' => '曆',
  '' => '歷',
  '' => '瀝',
  '' => '礫',
  '' => '轢',
  '' => '靂',
  '' => '憐',
  '' => '戀',
  '' => '攣',
  '' => '漣',
  '֡' => '煉',
  '֢' => '璉',
  '֣' => '練',
  '֤' => '聯',
  '֥' => '蓮',
  '֦' => '輦',
  '֧' => '連',
  '֨' => '鍊',
  '֩' => '冽',
  '֪' => '列',
  '֫' => '劣',
  '֬' => '洌',
  '֭' => '烈',
  '֮' => '裂',
  '֯' => '廉',
  'ְ' => '斂',
  'ֱ' => '殮',
  'ֲ' => '濂',
  'ֳ' => '簾',
  'ִ' => '獵',
  'ֵ' => '令',
  'ֶ' => '伶',
  'ַ' => '囹',
  'ָ' => '寧',
  'ֹ' => '岺',
  'ֺ' => '嶺',
  'ֻ' => '怜',
  'ּ' => '玲',
  'ֽ' => '笭',
  '־' => '羚',
  'ֿ' => '翎',
  '' => '聆',
  '' => '逞',
  '' => '鈴',
  '' => '零',
  '' => '靈',
  '' => '領',
  '' => '齡',
  '' => '例',
  '' => '澧',
  '' => '禮',
  '' => '醴',
  '' => '隷',
  '' => '勞',
  '' => '怒',
  '' => '撈',
  '' => '擄',
  '' => '櫓',
  '' => '潞',
  '' => '瀘',
  '' => '爐',
  '' => '盧',
  '' => '老',
  '' => '蘆',
  '' => '虜',
  '' => '路',
  '' => '輅',
  '' => '露',
  '' => '魯',
  '' => '鷺',
  '' => '鹵',
  '' => '碌',
  '' => '祿',
  '' => '綠',
  '' => '菉',
  '' => '錄',
  '' => '鹿',
  '' => '麓',
  '' => '論',
  '' => '壟',
  '' => '弄',
  '' => '朧',
  '' => '瀧',
  '' => '瓏',
  '' => '籠',
  '' => '聾',
  '' => '儡',
  '' => '瀨',
  '' => '牢',
  '' => '磊',
  '' => '賂',
  '' => '賚',
  '' => '賴',
  '' => '雷',
  '' => '了',
  '' => '僚',
  '' => '寮',
  '' => '廖',
  '' => '料',
  '' => '燎',
  '' => '療',
  '' => '瞭',
  '' => '聊',
  '' => '蓼',
  'ס' => '遼',
  'ע' => '鬧',
  'ף' => '龍',
  'פ' => '壘',
  'ץ' => '婁',
  'צ' => '屢',
  'ק' => '樓',
  'ר' => '淚',
  'ש' => '漏',
  'ת' => '瘻',
  '׫' => '累',
  '׬' => '縷',
  '׭' => '蔞',
  '׮' => '褸',
  'ׯ' => '鏤',
  'װ' => '陋',
  'ױ' => '劉',
  'ײ' => '旒',
  '׳' => '柳',
  '״' => '榴',
  '׵' => '流',
  '׶' => '溜',
  '׷' => '瀏',
  '׸' => '琉',
  '׹' => '瑠',
  '׺' => '留',
  '׻' => '瘤',
  '׼' => '硫',
  '׽' => '謬',
  '׾' => '類',
  '׿' => '六',
  '' => '戮',
  '' => '陸',
  '' => '侖',
  '' => '倫',
  '' => '崙',
  '' => '淪',
  '' => '綸',
  '' => '輪',
  '' => '律',
  '' => '慄',
  '' => '栗',
  '' => '率',
  '' => '隆',
  '' => '勒',
  '' => '肋',
  '' => '凜',
  '' => '凌',
  '' => '楞',
  '' => '稜',
  '' => '綾',
  '' => '菱',
  '' => '陵',
  '' => '俚',
  '' => '利',
  '' => '厘',
  '' => '吏',
  '' => '唎',
  '' => '履',
  '' => '悧',
  '' => '李',
  '' => '梨',
  '' => '浬',
  '' => '犁',
  '' => '狸',
  '' => '理',
  '' => '璃',
  '' => '異',
  '' => '痢',
  '' => '籬',
  '' => '罹',
  '' => '羸',
  '' => '莉',
  '' => '裏',
  '' => '裡',
  '' => '里',
  '' => '釐',
  '' => '離',
  '' => '鯉',
  '' => '吝',
  '' => '潾',
  '' => '燐',
  '' => '璘',
  '' => '藺',
  '' => '躪',
  '' => '隣',
  '' => '鱗',
  '' => '麟',
  '' => '林',
  '' => '淋',
  '' => '琳',
  '' => '臨',
  '' => '霖',
  '' => '砬',
  'ء' => '立',
  'آ' => '笠',
  'أ' => '粒',
  'ؤ' => '摩',
  'إ' => '瑪',
  'ئ' => '痲',
  'ا' => '碼',
  'ب' => '磨',
  'ة' => '馬',
  'ت' => '魔',
  'ث' => '麻',
  'ج' => '寞',
  'ح' => '幕',
  'خ' => '漠',
  'د' => '膜',
  'ذ' => '莫',
  'ر' => '邈',
  'ز' => '万',
  'س' => '卍',
  'ش' => '娩',
  'ص' => '巒',
  'ض' => '彎',
  'ط' => '慢',
  'ظ' => '挽',
  'ع' => '晩',
  'غ' => '曼',
  'ػ' => '滿',
  'ؼ' => '漫',
  'ؽ' => '灣',
  'ؾ' => '瞞',
  'ؿ' => '萬',
  '' => '蔓',
  '' => '蠻',
  '' => '輓',
  '' => '饅',
  '' => '鰻',
  '' => '唜',
  '' => '抹',
  '' => '末',
  '' => '沫',
  '' => '茉',
  '' => '襪',
  '' => '靺',
  '' => '亡',
  '' => '妄',
  '' => '忘',
  '' => '忙',
  '' => '望',
  '' => '網',
  '' => '罔',
  '' => '芒',
  '' => '茫',
  '' => '莽',
  '' => '輞',
  '' => '邙',
  '' => '埋',
  '' => '妹',
  '' => '媒',
  '' => '寐',
  '' => '昧',
  '' => '枚',
  '' => '梅',
  '' => '每',
  '' => '煤',
  '' => '罵',
  '' => '買',
  '' => '賣',
  '' => '邁',
  '' => '魅',
  '' => '脈',
  '' => '貊',
  '' => '陌',
  '' => '驀',
  '' => '麥',
  '' => '孟',
  '' => '氓',
  '' => '猛',
  '' => '盲',
  '' => '盟',
  '' => '萌',
  '' => '冪',
  '' => '覓',
  '' => '免',
  '' => '冕',
  '' => '勉',
  '' => '棉',
  '' => '沔',
  '' => '眄',
  '' => '眠',
  '' => '綿',
  '' => '緬',
  '' => '面',
  '' => '麵',
  '' => '滅',
  '١' => '蔑',
  '٢' => '冥',
  '٣' => '名',
  '٤' => '命',
  '٥' => '明',
  '٦' => '暝',
  '٧' => '椧',
  '٨' => '溟',
  '٩' => '皿',
  '٪' => '瞑',
  '٫' => '茗',
  '٬' => '蓂',
  '٭' => '螟',
  'ٮ' => '酩',
  'ٯ' => '銘',
  'ٰ' => '鳴',
  'ٱ' => '袂',
  'ٲ' => '侮',
  'ٳ' => '冒',
  'ٴ' => '募',
  'ٵ' => '姆',
  'ٶ' => '帽',
  'ٷ' => '慕',
  'ٸ' => '摸',
  'ٹ' => '摹',
  'ٺ' => '暮',
  'ٻ' => '某',
  'ټ' => '模',
  'ٽ' => '母',
  'پ' => '毛',
  'ٿ' => '牟',
  '' => '牡',
  '' => '瑁',
  '' => '眸',
  '' => '矛',
  '' => '耗',
  '' => '芼',
  '' => '茅',
  '' => '謀',
  '' => '謨',
  '' => '貌',
  '' => '木',
  '' => '沐',
  '' => '牧',
  '' => '目',
  '' => '睦',
  '' => '穆',
  '' => '鶩',
  '' => '歿',
  '' => '沒',
  '' => '夢',
  '' => '朦',
  '' => '蒙',
  '' => '卯',
  '' => '墓',
  '' => '妙',
  '' => '廟',
  '' => '描',
  '' => '昴',
  '' => '杳',
  '' => '渺',
  '' => '猫',
  '' => '竗',
  '' => '苗',
  '' => '錨',
  '' => '務',
  '' => '巫',
  '' => '憮',
  '' => '懋',
  '' => '戊',
  '' => '拇',
  '' => '撫',
  '' => '无',
  '' => '楙',
  '' => '武',
  '' => '毋',
  '' => '無',
  '' => '珷',
  '' => '畝',
  '' => '繆',
  '' => '舞',
  '' => '茂',
  '' => '蕪',
  '' => '誣',
  '' => '貿',
  '' => '霧',
  '' => '鵡',
  '' => '墨',
  '' => '默',
  '' => '們',
  '' => '刎',
  '' => '吻',
  '' => '問',
  '' => '文',
  'ڡ' => '汶',
  'ڢ' => '紊',
  'ڣ' => '紋',
  'ڤ' => '聞',
  'ڥ' => '蚊',
  'ڦ' => '門',
  'ڧ' => '雯',
  'ڨ' => '勿',
  'ک' => '沕',
  'ڪ' => '物',
  'ګ' => '味',
  'ڬ' => '媚',
  'ڭ' => '尾',
  'ڮ' => '嵋',
  'گ' => '彌',
  'ڰ' => '微',
  'ڱ' => '未',
  'ڲ' => '梶',
  'ڳ' => '楣',
  'ڴ' => '渼',
  'ڵ' => '湄',
  'ڶ' => '眉',
  'ڷ' => '米',
  'ڸ' => '美',
  'ڹ' => '薇',
  'ں' => '謎',
  'ڻ' => '迷',
  'ڼ' => '靡',
  'ڽ' => '黴',
  'ھ' => '岷',
  'ڿ' => '悶',
  '' => '愍',
  '' => '憫',
  '' => '敏',
  '' => '旻',
  '' => '旼',
  '' => '民',
  '' => '泯',
  '' => '玟',
  '' => '珉',
  '' => '緡',
  '' => '閔',
  '' => '密',
  '' => '蜜',
  '' => '謐',
  '' => '剝',
  '' => '博',
  '' => '拍',
  '' => '搏',
  '' => '撲',
  '' => '朴',
  '' => '樸',
  '' => '泊',
  '' => '珀',
  '' => '璞',
  '' => '箔',
  '' => '粕',
  '' => '縛',
  '' => '膊',
  '' => '舶',
  '' => '薄',
  '' => '迫',
  '' => '雹',
  '' => '駁',
  '' => '伴',
  '' => '半',
  '' => '反',
  '' => '叛',
  '' => '拌',
  '' => '搬',
  '' => '攀',
  '' => '斑',
  '' => '槃',
  '' => '泮',
  '' => '潘',
  '' => '班',
  '' => '畔',
  '' => '瘢',
  '' => '盤',
  '' => '盼',
  '' => '磐',
  '' => '磻',
  '' => '礬',
  '' => '絆',
  '' => '般',
  '' => '蟠',
  '' => '返',
  '' => '頒',
  '' => '飯',
  '' => '勃',
  '' => '拔',
  '' => '撥',
  '' => '渤',
  '' => '潑',
  'ۡ' => '發',
  'ۢ' => '跋',
  'ۣ' => '醱',
  'ۤ' => '鉢',
  'ۥ' => '髮',
  'ۦ' => '魃',
  'ۧ' => '倣',
  'ۨ' => '傍',
  '۩' => '坊',
  '۪' => '妨',
  '۫' => '尨',
  '۬' => '幇',
  'ۭ' => '彷',
  'ۮ' => '房',
  'ۯ' => '放',
  '۰' => '方',
  '۱' => '旁',
  '۲' => '昉',
  '۳' => '枋',
  '۴' => '榜',
  '۵' => '滂',
  '۶' => '磅',
  '۷' => '紡',
  '۸' => '肪',
  '۹' => '膀',
  'ۺ' => '舫',
  'ۻ' => '芳',
  'ۼ' => '蒡',
  '۽' => '蚌',
  '۾' => '訪',
  'ۿ' => '謗',
  '' => '邦',
  '' => '防',
  '' => '龐',
  '' => '倍',
  '' => '俳',
  '' => '北',
  '' => '培',
  '' => '徘',
  '' => '拜',
  '' => '排',
  '' => '杯',
  '' => '湃',
  '' => '焙',
  '' => '盃',
  '' => '背',
  '' => '胚',
  '' => '裴',
  '' => '裵',
  '' => '褙',
  '' => '賠',
  '' => '輩',
  '' => '配',
  '' => '陪',
  '' => '伯',
  '' => '佰',
  '' => '帛',
  '' => '柏',
  '' => '栢',
  '' => '白',
  '' => '百',
  '' => '魄',
  '' => '幡',
  '' => '樊',
  '' => '煩',
  '' => '燔',
  '' => '番',
  '' => '磻',
  '' => '繁',
  '' => '蕃',
  '' => '藩',
  '' => '飜',
  '' => '伐',
  '' => '筏',
  '' => '罰',
  '' => '閥',
  '' => '凡',
  '' => '帆',
  '' => '梵',
  '' => '氾',
  '' => '汎',
  '' => '泛',
  '' => '犯',
  '' => '範',
  '' => '范',
  '' => '法',
  '' => '琺',
  '' => '僻',
  '' => '劈',
  '' => '壁',
  '' => '擘',
  '' => '檗',
  '' => '璧',
  '' => '癖',
  'ܡ' => '碧',
  'ܢ' => '蘗',
  'ܣ' => '闢',
  'ܤ' => '霹',
  'ܥ' => '便',
  'ܦ' => '卞',
  'ܧ' => '弁',
  'ܨ' => '變',
  'ܩ' => '辨',
  'ܪ' => '辯',
  'ܫ' => '邊',
  'ܬ' => '別',
  'ܭ' => '瞥',
  'ܮ' => '鱉',
  'ܯ' => '鼈',
  'ܰ' => '丙',
  'ܱ' => '倂',
  'ܲ' => '兵',
  'ܳ' => '屛',
  'ܴ' => '幷',
  'ܵ' => '昞',
  'ܶ' => '昺',
  'ܷ' => '柄',
  'ܸ' => '棅',
  'ܹ' => '炳',
  'ܺ' => '甁',
  'ܻ' => '病',
  'ܼ' => '秉',
  'ܽ' => '竝',
  'ܾ' => '輧',
  'ܿ' => '餠',
  '' => '騈',
  '' => '保',
  '' => '堡',
  '' => '報',
  '' => '寶',
  '' => '普',
  '' => '步',
  '' => '洑',
  '' => '湺',
  '' => '潽',
  '' => '珤',
  '' => '甫',
  '' => '菩',
  '' => '補',
  '' => '褓',
  '' => '譜',
  '' => '輔',
  '' => '伏',
  '' => '僕',
  '' => '匐',
  '' => '卜',
  '' => '宓',
  '' => '復',
  '' => '服',
  '' => '福',
  '' => '腹',
  '' => '茯',
  '' => '蔔',
  '' => '複',
  '' => '覆',
  '' => '輹',
  '' => '輻',
  '' => '馥',
  '' => '鰒',
  '' => '本',
  '' => '乶',
  '' => '俸',
  '' => '奉',
  '' => '封',
  '' => '峯',
  '' => '峰',
  '' => '捧',
  '' => '棒',
  '' => '烽',
  '' => '熢',
  '' => '琫',
  '' => '縫',
  '' => '蓬',
  '' => '蜂',
  '' => '逢',
  '' => '鋒',
  '' => '鳳',
  '' => '不',
  '' => '付',
  '' => '俯',
  '' => '傅',
  '' => '剖',
  '' => '副',
  '' => '否',
  '' => '咐',
  '' => '埠',
  '' => '夫',
  '' => '婦',
  'ݡ' => '孚',
  'ݢ' => '孵',
  'ݣ' => '富',
  'ݤ' => '府',
  'ݥ' => '復',
  'ݦ' => '扶',
  'ݧ' => '敷',
  'ݨ' => '斧',
  'ݩ' => '浮',
  'ݪ' => '溥',
  'ݫ' => '父',
  'ݬ' => '符',
  'ݭ' => '簿',
  'ݮ' => '缶',
  'ݯ' => '腐',
  'ݰ' => '腑',
  'ݱ' => '膚',
  'ݲ' => '艀',
  'ݳ' => '芙',
  'ݴ' => '莩',
  'ݵ' => '訃',
  'ݶ' => '負',
  'ݷ' => '賦',
  'ݸ' => '賻',
  'ݹ' => '赴',
  'ݺ' => '趺',
  'ݻ' => '部',
  'ݼ' => '釜',
  'ݽ' => '阜',
  'ݾ' => '附',
  'ݿ' => '駙',
  '' => '鳧',
  '' => '北',
  '' => '分',
  '' => '吩',
  '' => '噴',
  '' => '墳',
  '' => '奔',
  '' => '奮',
  '' => '忿',
  '' => '憤',
  '' => '扮',
  '' => '昐',
  '' => '汾',
  '' => '焚',
  '' => '盆',
  '' => '粉',
  '' => '糞',
  '' => '紛',
  '' => '芬',
  '' => '賁',
  '' => '雰',
  '' => '不',
  '' => '佛',
  '' => '弗',
  '' => '彿',
  '' => '拂',
  '' => '崩',
  '' => '朋',
  '' => '棚',
  '' => '硼',
  '' => '繃',
  '' => '鵬',
  '' => '丕',
  '' => '備',
  '' => '匕',
  '' => '匪',
  '' => '卑',
  '' => '妃',
  '' => '婢',
  '' => '庇',
  '' => '悲',
  '' => '憊',
  '' => '扉',
  '' => '批',
  '' => '斐',
  '' => '枇',
  '' => '榧',
  '' => '比',
  '' => '毖',
  '' => '毗',
  '' => '毘',
  '' => '沸',
  '' => '泌',
  '' => '琵',
  '' => '痺',
  '' => '砒',
  '' => '碑',
  '' => '秕',
  '' => '秘',
  '' => '粃',
  '' => '緋',
  '' => '翡',
  '' => '肥',
  'ޡ' => '脾',
  'ޢ' => '臂',
  'ޣ' => '菲',
  'ޤ' => '蜚',
  'ޥ' => '裨',
  'ަ' => '誹',
  'ާ' => '譬',
  'ި' => '費',
  'ީ' => '鄙',
  'ު' => '非',
  'ޫ' => '飛',
  'ެ' => '鼻',
  'ޭ' => '嚬',
  'ޮ' => '嬪',
  'ޯ' => '彬',
  'ް' => '斌',
  'ޱ' => '檳',
  '޲' => '殯',
  '޳' => '浜',
  '޴' => '濱',
  '޵' => '瀕',
  '޶' => '牝',
  '޷' => '玭',
  '޸' => '貧',
  '޹' => '賓',
  '޺' => '頻',
  '޻' => '憑',
  '޼' => '氷',
  '޽' => '聘',
  '޾' => '騁',
  '޿' => '乍',
  '' => '事',
  '' => '些',
  '' => '仕',
  '' => '伺',
  '' => '似',
  '' => '使',
  '' => '俟',
  '' => '僿',
  '' => '史',
  '' => '司',
  '' => '唆',
  '' => '嗣',
  '' => '四',
  '' => '士',
  '' => '奢',
  '' => '娑',
  '' => '寫',
  '' => '寺',
  '' => '射',
  '' => '巳',
  '' => '師',
  '' => '徙',
  '' => '思',
  '' => '捨',
  '' => '斜',
  '' => '斯',
  '' => '柶',
  '' => '査',
  '' => '梭',
  '' => '死',
  '' => '沙',
  '' => '泗',
  '' => '渣',
  '' => '瀉',
  '' => '獅',
  '' => '砂',
  '' => '社',
  '' => '祀',
  '' => '祠',
  '' => '私',
  '' => '篩',
  '' => '紗',
  '' => '絲',
  '' => '肆',
  '' => '舍',
  '' => '莎',
  '' => '蓑',
  '' => '蛇',
  '' => '裟',
  '' => '詐',
  '' => '詞',
  '' => '謝',
  '' => '賜',
  '' => '赦',
  '' => '辭',
  '' => '邪',
  '' => '飼',
  '' => '駟',
  '' => '麝',
  '' => '削',
  '' => '數',
  '' => '朔',
  '' => '索',
  'ߡ' => '傘',
  'ߢ' => '刪',
  'ߣ' => '山',
  'ߤ' => '散',
  'ߥ' => '汕',
  'ߦ' => '珊',
  'ߧ' => '産',
  'ߨ' => '疝',
  'ߩ' => '算',
  'ߪ' => '蒜',
  '߫' => '酸',
  '߬' => '霰',
  '߭' => '乷',
  '߮' => '撒',
  '߯' => '殺',
  '߰' => '煞',
  '߱' => '薩',
  '߲' => '三',
  '߳' => '參',
  'ߴ' => '杉',
  'ߵ' => '森',
  '߶' => '渗',
  '߷' => '芟',
  '߸' => '蔘',
  '߹' => '衫',
  'ߺ' => '揷',
  '߻' => '澁',
  '߼' => '鈒',
  '߽' => '颯',
  '߾' => '上',
  '߿' => '傷',
  '' => '像',
  '' => '償',
  '' => '商',
  '' => '喪',
  '' => '嘗',
  '' => '孀',
  '' => '尙',
  '' => '峠',
  '' => '常',
  '' => '床',
  '' => '庠',
  '' => '廂',
  '' => '想',
  '' => '桑',
  '' => '橡',
  '' => '湘',
  '' => '爽',
  '' => '牀',
  '' => '狀',
  '' => '相',
  '' => '祥',
  '' => '箱',
  '' => '翔',
  '' => '裳',
  '' => '觴',
  '' => '詳',
  '' => '象',
  '' => '賞',
  '' => '霜',
  '' => '塞',
  '' => '璽',
  '' => '賽',
  '' => '嗇',
  '' => '塞',
  '' => '穡',
  '' => '索',
  '' => '色',
  '' => '牲',
  '' => '生',
  '' => '甥',
  '' => '省',
  '' => '笙',
  '' => '墅',
  '' => '壻',
  '' => '嶼',
  '' => '序',
  '' => '庶',
  '' => '徐',
  '' => '恕',
  '' => '抒',
  '' => '捿',
  '' => '敍',
  '' => '暑',
  '' => '曙',
  '' => '書',
  '' => '栖',
  '' => '棲',
  '' => '犀',
  '' => '瑞',
  '' => '筮',
  '' => '絮',
  '' => '緖',
  '' => '署',
  '' => '胥',
  '' => '舒',
  '' => '薯',
  '' => '西',
  '' => '誓',
  '' => '逝',
  '' => '鋤',
  '' => '黍',
  '' => '鼠',
  '' => '夕',
  '' => '奭',
  '' => '席',
  '' => '惜',
  '' => '昔',
  '' => '晳',
  '' => '析',
  '' => '汐',
  '' => '淅',
  '' => '潟',
  '' => '石',
  '' => '碩',
  '' => '蓆',
  '' => '釋',
  '' => '錫',
  '' => '仙',
  '' => '僊',
  '' => '先',
  '' => '善',
  '' => '嬋',
  '' => '宣',
  '' => '扇',
  '' => '敾',
  '' => '旋',
  '' => '渲',
  '' => '煽',
  '' => '琁',
  '' => '瑄',
  '' => '璇',
  '' => '璿',
  '' => '癬',
  '' => '禪',
  '' => '線',
  '' => '繕',
  '' => '羨',
  '' => '腺',
  '' => '膳',
  '' => '船',
  '' => '蘚',
  '' => '蟬',
  '' => '詵',
  '' => '跣',
  '' => '選',
  '' => '銑',
  '' => '鐥',
  '' => '饍',
  '' => '鮮',
  '' => '卨',
  '' => '屑',
  '' => '楔',
  '' => '泄',
  '' => '洩',
  '' => '渫',
  '' => '舌',
  '' => '薛',
  '' => '褻',
  '' => '設',
  '' => '說',
  '' => '雪',
  '' => '齧',
  '' => '剡',
  '' => '暹',
  '' => '殲',
  '' => '纖',
  '' => '蟾',
  '' => '贍',
  '' => '閃',
  '' => '陝',
  '' => '攝',
  '' => '涉',
  '' => '燮',
  '' => '葉',
  '' => '城',
  '' => '姓',
  '' => '宬',
  '' => '性',
  '' => '惺',
  '' => '成',
  '' => '星',
  '' => '晟',
  '' => '猩',
  '' => '珹',
  '' => '盛',
  '' => '省',
  '' => '筬',
  '' => '聖',
  '' => '聲',
  '' => '腥',
  '' => '誠',
  '' => '醒',
  '' => '世',
  '' => '勢',
  '' => '歲',
  '' => '洗',
  '' => '稅',
  '' => '笹',
  '' => '細',
  '' => '說',
  '' => '貰',
  '' => '召',
  '' => '嘯',
  '' => '塑',
  '' => '宵',
  '' => '小',
  '' => '少',
  '' => '巢',
  '' => '所',
  '' => '掃',
  '' => '搔',
  '' => '昭',
  '' => '梳',
  '' => '沼',
  '' => '消',
  '' => '溯',
  '' => '瀟',
  '' => '炤',
  '' => '燒',
  '' => '甦',
  '' => '疏',
  '' => '疎',
  '' => '瘙',
  '' => '笑',
  '' => '篠',
  '' => '簫',
  '' => '素',
  '' => '紹',
  '' => '蔬',
  '' => '蕭',
  '' => '蘇',
  '' => '訴',
  '' => '逍',
  '' => '遡',
  '' => '邵',
  '' => '銷',
  '' => '韶',
  '' => '騷',
  '' => '俗',
  '' => '屬',
  '' => '束',
  '' => '涑',
  '' => '粟',
  '' => '續',
  '' => '謖',
  '' => '贖',
  '' => '速',
  '' => '孫',
  '' => '巽',
  '' => '損',
  '' => '蓀',
  '' => '遜',
  '' => '飡',
  '' => '率',
  '' => '宋',
  '' => '悚',
  '' => '松',
  '' => '淞',
  '' => '訟',
  '' => '誦',
  '' => '送',
  '' => '頌',
  '' => '刷',
  '' => '殺',
  '' => '灑',
  '' => '碎',
  '' => '鎖',
  '' => '衰',
  '' => '釗',
  '' => '修',
  '' => '受',
  '' => '嗽',
  '' => '囚',
  '' => '垂',
  '' => '壽',
  '' => '嫂',
  '' => '守',
  '' => '岫',
  '' => '峀',
  '' => '帥',
  '' => '愁',
  '' => '戍',
  '' => '手',
  '' => '授',
  '' => '搜',
  '' => '收',
  '' => '數',
  '' => '樹',
  '' => '殊',
  '' => '水',
  '' => '洙',
  '' => '漱',
  '' => '燧',
  '' => '狩',
  '' => '獸',
  '' => '琇',
  '' => '璲',
  '' => '瘦',
  '' => '睡',
  '' => '秀',
  '' => '穗',
  '' => '竪',
  '' => '粹',
  '' => '綏',
  '' => '綬',
  '' => '繡',
  '' => '羞',
  '' => '脩',
  '' => '茱',
  '' => '蒐',
  '' => '蓚',
  '' => '藪',
  '' => '袖',
  '' => '誰',
  '' => '讐',
  '' => '輸',
  '' => '遂',
  '' => '邃',
  '' => '酬',
  '' => '銖',
  '' => '銹',
  '' => '隋',
  '' => '隧',
  '' => '隨',
  '' => '雖',
  '' => '需',
  '' => '須',
  '' => '首',
  '' => '髓',
  '' => '鬚',
  '' => '叔',
  '' => '塾',
  '' => '夙',
  '' => '孰',
  '' => '宿',
  '' => '淑',
  '' => '潚',
  '' => '熟',
  '' => '琡',
  '' => '璹',
  '' => '肅',
  '' => '菽',
  '' => '巡',
  '' => '徇',
  '' => '循',
  '' => '恂',
  '' => '旬',
  '' => '栒',
  '' => '楯',
  '' => '橓',
  '' => '殉',
  '' => '洵',
  '' => '淳',
  '' => '珣',
  '' => '盾',
  '' => '瞬',
  '' => '筍',
  '' => '純',
  '' => '脣',
  '' => '舜',
  '' => '荀',
  '' => '蓴',
  '' => '蕣',
  '' => '詢',
  '' => '諄',
  '' => '醇',
  '' => '錞',
  '' => '順',
  '' => '馴',
  '' => '戌',
  '' => '術',
  '' => '述',
  '' => '鉥',
  '' => '崇',
  '' => '崧',
  '' => '嵩',
  '' => '瑟',
  '' => '膝',
  '' => '蝨',
  '' => '濕',
  '' => '拾',
  '' => '習',
  '' => '褶',
  '' => '襲',
  '' => '丞',
  '' => '乘',
  '' => '僧',
  '' => '勝',
  '' => '升',
  '' => '承',
  '' => '昇',
  '' => '繩',
  '' => '蠅',
  '' => '陞',
  '' => '侍',
  '' => '匙',
  '' => '嘶',
  '' => '始',
  '' => '媤',
  '' => '尸',
  '' => '屎',
  '' => '屍',
  '' => '市',
  '' => '弑',
  '' => '恃',
  '' => '施',
  '' => '是',
  '' => '時',
  '' => '枾',
  '' => '柴',
  '' => '猜',
  '' => '矢',
  '' => '示',
  '' => '翅',
  '' => '蒔',
  '' => '蓍',
  '' => '視',
  '' => '試',
  '' => '詩',
  '' => '諡',
  '' => '豕',
  '' => '豺',
  '' => '埴',
  '' => '寔',
  '' => '式',
  '' => '息',
  '' => '拭',
  '' => '植',
  '' => '殖',
  '' => '湜',
  '' => '熄',
  '' => '篒',
  '' => '蝕',
  '' => '識',
  '' => '軾',
  '' => '食',
  '' => '飾',
  '' => '伸',
  '' => '侁',
  '' => '信',
  '' => '呻',
  '' => '娠',
  '' => '宸',
  '' => '愼',
  '' => '新',
  '' => '晨',
  '' => '燼',
  '' => '申',
  '' => '神',
  '' => '紳',
  '' => '腎',
  '' => '臣',
  '' => '莘',
  '' => '薪',
  '' => '藎',
  '' => '蜃',
  '' => '訊',
  '' => '身',
  '' => '辛',
  '' => '辰',
  '' => '迅',
  '' => '失',
  '' => '室',
  '' => '實',
  '' => '悉',
  '' => '審',
  '' => '尋',
  '' => '心',
  '' => '沁',
  '' => '沈',
  '' => '深',
  '' => '瀋',
  '' => '甚',
  '' => '芯',
  '' => '諶',
  '' => '什',
  '' => '十',
  '' => '拾',
  '' => '雙',
  '' => '氏',
  '' => '亞',
  '' => '俄',
  '' => '兒',
  '' => '啞',
  '' => '娥',
  '' => '峨',
  '' => '我',
  '' => '牙',
  '' => '芽',
  '' => '莪',
  '' => '蛾',
  '' => '衙',
  '' => '訝',
  '' => '阿',
  '' => '雅',
  '' => '餓',
  '' => '鴉',
  '' => '鵝',
  '' => '堊',
  '' => '岳',
  '' => '嶽',
  '' => '幄',
  '' => '惡',
  '' => '愕',
  '' => '握',
  '' => '樂',
  '' => '渥',
  '' => '鄂',
  '' => '鍔',
  '' => '顎',
  '' => '鰐',
  '' => '齷',
  '' => '安',
  '' => '岸',
  '' => '按',
  '' => '晏',
  '' => '案',
  '' => '眼',
  '' => '雁',
  '' => '鞍',
  '' => '顔',
  '' => '鮟',
  '' => '斡',
  '' => '謁',
  '' => '軋',
  '' => '閼',
  '' => '唵',
  '' => '岩',
  '' => '巖',
  '' => '庵',
  '' => '暗',
  '' => '癌',
  '' => '菴',
  '' => '闇',
  '' => '壓',
  '' => '押',
  '' => '狎',
  '' => '鴨',
  '' => '仰',
  '' => '央',
  '' => '怏',
  '' => '昻',
  '' => '殃',
  '' => '秧',
  '' => '鴦',
  '' => '厓',
  '' => '哀',
  '' => '埃',
  '' => '崖',
  '' => '愛',
  '' => '曖',
  '' => '涯',
  '' => '碍',
  '' => '艾',
  '' => '隘',
  '' => '靄',
  '' => '厄',
  '' => '扼',
  '' => '掖',
  '' => '液',
  '' => '縊',
  '' => '腋',
  '' => '額',
  '' => '櫻',
  '' => '罌',
  '' => '鶯',
  '' => '鸚',
  '' => '也',
  '' => '倻',
  '' => '冶',
  '' => '夜',
  '' => '惹',
  '' => '揶',
  '' => '椰',
  '' => '爺',
  '' => '耶',
  '' => '若',
  '' => '野',
  '' => '弱',
  '' => '掠',
  '' => '略',
  '' => '約',
  '' => '若',
  '' => '葯',
  '' => '蒻',
  '' => '藥',
  '' => '躍',
  '' => '亮',
  '' => '佯',
  '' => '兩',
  '' => '凉',
  '' => '壤',
  '' => '孃',
  '' => '恙',
  '' => '揚',
  '' => '攘',
  '' => '敭',
  '' => '暘',
  '' => '梁',
  '' => '楊',
  '' => '樣',
  '' => '洋',
  '' => '瀁',
  '' => '煬',
  '' => '痒',
  '' => '瘍',
  '' => '禳',
  '' => '穰',
  '' => '糧',
  '' => '羊',
  '' => '良',
  '' => '襄',
  '' => '諒',
  '' => '讓',
  '' => '釀',
  '' => '陽',
  '' => '量',
  '' => '養',
  '' => '圄',
  '' => '御',
  '' => '於',
  '' => '漁',
  '' => '瘀',
  '' => '禦',
  '' => '語',
  '' => '馭',
  '' => '魚',
  '' => '齬',
  '' => '億',
  '' => '憶',
  '' => '抑',
  '' => '檍',
  '' => '臆',
  '' => '偃',
  '' => '堰',
  '' => '彦',
  '' => '焉',
  '' => '言',
  '' => '諺',
  '' => '孼',
  '' => '蘖',
  '' => '俺',
  '' => '儼',
  '' => '嚴',
  '' => '奄',
  '' => '掩',
  '' => '淹',
  '' => '嶪',
  '' => '業',
  '' => '円',
  '' => '予',
  '' => '余',
  '' => '勵',
  '' => '呂',
  '' => '女',
  '' => '如',
  '' => '廬',
  '' => '旅',
  '' => '歟',
  '' => '汝',
  '' => '濾',
  '' => '璵',
  '' => '礖',
  '' => '礪',
  '' => '與',
  '' => '艅',
  '' => '茹',
  '' => '輿',
  '' => '轝',
  '' => '閭',
  '' => '餘',
  '' => '驪',
  '' => '麗',
  '' => '黎',
  '' => '亦',
  '' => '力',
  '' => '域',
  '' => '役',
  '' => '易',
  '' => '曆',
  '' => '歷',
  '' => '疫',
  '' => '繹',
  '' => '譯',
  '' => '轢',
  '' => '逆',
  '' => '驛',
  '' => '嚥',
  '' => '堧',
  '' => '姸',
  '' => '娟',
  '' => '宴',
  '' => '年',
  '' => '延',
  '' => '憐',
  '' => '戀',
  '' => '捐',
  '' => '挻',
  '' => '撚',
  '' => '椽',
  '' => '沇',
  '' => '沿',
  '' => '涎',
  '' => '涓',
  '' => '淵',
  '' => '演',
  '' => '漣',
  '' => '烟',
  '' => '然',
  '' => '煙',
  '' => '煉',
  '' => '燃',
  '' => '燕',
  '' => '璉',
  '' => '硏',
  '' => '硯',
  '' => '秊',
  '' => '筵',
  '' => '緣',
  '' => '練',
  '' => '縯',
  '' => '聯',
  '' => '衍',
  '' => '軟',
  '' => '輦',
  '' => '蓮',
  '' => '連',
  '' => '鉛',
  '' => '鍊',
  '' => '鳶',
  '' => '列',
  '' => '劣',
  '' => '咽',
  '' => '悅',
  '' => '涅',
  '' => '烈',
  '' => '熱',
  '' => '裂',
  '' => '說',
  '' => '閱',
  '' => '厭',
  '' => '廉',
  '' => '念',
  '' => '捻',
  '' => '染',
  '' => '殮',
  '' => '炎',
  '' => '焰',
  '' => '琰',
  '' => '艶',
  '' => '苒',
  '' => '簾',
  '' => '閻',
  '' => '髥',
  '' => '鹽',
  '' => '曄',
  '' => '獵',
  '' => '燁',
  '' => '葉',
  '' => '令',
  '' => '囹',
  '' => '塋',
  '' => '寧',
  '' => '嶺',
  '' => '嶸',
  '' => '影',
  '' => '怜',
  '' => '映',
  '' => '暎',
  '' => '楹',
  '' => '榮',
  '' => '永',
  '' => '泳',
  '' => '渶',
  '' => '潁',
  '' => '濚',
  '' => '瀛',
  '' => '瀯',
  '' => '煐',
  '' => '營',
  '' => '獰',
  '' => '玲',
  '' => '瑛',
  '' => '瑩',
  '' => '瓔',
  '' => '盈',
  '' => '穎',
  '' => '纓',
  '' => '羚',
  '' => '聆',
  '' => '英',
  '' => '詠',
  '' => '迎',
  '' => '鈴',
  '' => '鍈',
  '' => '零',
  '' => '霙',
  '' => '靈',
  '' => '領',
  '' => '乂',
  '' => '倪',
  '' => '例',
  '' => '刈',
  '' => '叡',
  '' => '曳',
  '' => '汭',
  '' => '濊',
  '' => '猊',
  '' => '睿',
  '' => '穢',
  '' => '芮',
  '' => '藝',
  '' => '蘂',
  '' => '禮',
  '' => '裔',
  '' => '詣',
  '' => '譽',
  '' => '豫',
  '' => '醴',
  '' => '銳',
  '' => '隸',
  '' => '霓',
  '' => '預',
  '' => '五',
  '' => '伍',
  '' => '俉',
  '' => '傲',
  '' => '午',
  '' => '吾',
  '' => '吳',
  '' => '嗚',
  '' => '塢',
  '' => '墺',
  '' => '奧',
  '' => '娛',
  '' => '寤',
  '' => '悟',
  '' => '惡',
  '' => '懊',
  '' => '敖',
  '' => '旿',
  '' => '晤',
  '' => '梧',
  '' => '汚',
  '' => '澳',
  '' => '烏',
  '' => '熬',
  '' => '獒',
  '' => '筽',
  '' => '蜈',
  '' => '誤',
  '' => '鰲',
  '' => '鼇',
  '' => '屋',
  '' => '沃',
  '' => '獄',
  '' => '玉',
  '' => '鈺',
  '' => '溫',
  '' => '瑥',
  '' => '瘟',
  '' => '穩',
  '' => '縕',
  '' => '蘊',
  '' => '兀',
  '' => '壅',
  '' => '擁',
  '' => '瓮',
  '' => '甕',
  '' => '癰',
  '' => '翁',
  '' => '邕',
  '' => '雍',
  '' => '饔',
  '' => '渦',
  '' => '瓦',
  '' => '窩',
  '' => '窪',
  '' => '臥',
  '' => '蛙',
  '' => '蝸',
  '' => '訛',
  '' => '婉',
  '' => '完',
  '' => '宛',
  '' => '梡',
  '' => '椀',
  '' => '浣',
  '' => '玩',
  '' => '琓',
  '' => '琬',
  '' => '碗',
  '' => '緩',
  '' => '翫',
  '' => '脘',
  '' => '腕',
  '' => '莞',
  '' => '豌',
  '' => '阮',
  '' => '頑',
  '' => '曰',
  '' => '往',
  '' => '旺',
  '' => '枉',
  '' => '汪',
  '' => '王',
  '' => '倭',
  '' => '娃',
  '' => '歪',
  '' => '矮',
  '' => '外',
  '' => '嵬',
  '' => '巍',
  '' => '猥',
  '' => '畏',
  '' => '了',
  '' => '僚',
  '' => '僥',
  '' => '凹',
  '' => '堯',
  '' => '夭',
  '' => '妖',
  '' => '姚',
  '' => '寥',
  '' => '寮',
  '' => '尿',
  '' => '嶢',
  '' => '拗',
  '' => '搖',
  '' => '撓',
  '' => '擾',
  '' => '料',
  '' => '曜',
  '' => '樂',
  '' => '橈',
  '' => '燎',
  '' => '燿',
  '' => '瑤',
  '' => '療',
  '' => '窈',
  '' => '窯',
  '' => '繇',
  '' => '繞',
  '' => '耀',
  '' => '腰',
  '' => '蓼',
  '' => '蟯',
  '' => '要',
  '' => '謠',
  '' => '遙',
  '' => '遼',
  '' => '邀',
  '' => '饒',
  '' => '慾',
  '' => '欲',
  '' => '浴',
  '' => '縟',
  '' => '褥',
  '' => '辱',
  '' => '俑',
  '' => '傭',
  '' => '冗',
  '' => '勇',
  '' => '埇',
  '' => '墉',
  '' => '容',
  '' => '庸',
  '' => '慂',
  '' => '榕',
  '' => '涌',
  '' => '湧',
  '' => '溶',
  '' => '熔',
  '' => '瑢',
  '' => '用',
  '' => '甬',
  '' => '聳',
  '' => '茸',
  '' => '蓉',
  '' => '踊',
  '' => '鎔',
  '' => '鏞',
  '' => '龍',
  '' => '于',
  '' => '佑',
  '' => '偶',
  '' => '優',
  '' => '又',
  '' => '友',
  '' => '右',
  '' => '宇',
  '' => '寓',
  '' => '尤',
  '' => '愚',
  '' => '憂',
  '' => '旴',
  '' => '牛',
  '' => '玗',
  '' => '瑀',
  '' => '盂',
  '' => '祐',
  '' => '禑',
  '' => '禹',
  '' => '紆',
  '' => '羽',
  '' => '芋',
  '' => '藕',
  '' => '虞',
  '' => '迂',
  '' => '遇',
  '' => '郵',
  '' => '釪',
  '' => '隅',
  '' => '雨',
  '' => '雩',
  '' => '勖',
  '' => '彧',
  '' => '旭',
  '' => '昱',
  '' => '栯',
  '' => '煜',
  '' => '稶',
  '' => '郁',
  '' => '頊',
  '' => '云',
  '' => '暈',
  '' => '橒',
  '' => '殞',
  '' => '澐',
  '' => '熉',
  '' => '耘',
  '' => '芸',
  '' => '蕓',
  '' => '運',
  '' => '隕',
  '' => '雲',
  '' => '韻',
  '' => '蔚',
  '' => '鬱',
  '' => '亐',
  '' => '熊',
  '' => '雄',
  '' => '元',
  '' => '原',
  '' => '員',
  '' => '圓',
  '' => '園',
  '' => '垣',
  '' => '媛',
  '' => '嫄',
  '' => '寃',
  '' => '怨',
  '' => '愿',
  '' => '援',
  '' => '沅',
  '' => '洹',
  '' => '湲',
  '' => '源',
  '' => '爰',
  '' => '猿',
  '' => '瑗',
  '' => '苑',
  '' => '袁',
  '' => '轅',
  '' => '遠',
  '' => '阮',
  '' => '院',
  '' => '願',
  '' => '鴛',
  '' => '月',
  '' => '越',
  '' => '鉞',
  '' => '位',
  '' => '偉',
  '' => '僞',
  '' => '危',
  '' => '圍',
  '' => '委',
  '' => '威',
  '' => '尉',
  '' => '慰',
  '' => '暐',
  '' => '渭',
  '' => '爲',
  '' => '瑋',
  '' => '緯',
  '' => '胃',
  '' => '萎',
  '' => '葦',
  '' => '蔿',
  '' => '蝟',
  '' => '衛',
  '' => '褘',
  '' => '謂',
  '' => '違',
  '' => '韋',
  '' => '魏',
  '' => '乳',
  '' => '侑',
  '' => '儒',
  '' => '兪',
  '' => '劉',
  '' => '唯',
  '' => '喩',
  '' => '孺',
  '' => '宥',
  '' => '幼',
  '' => '幽',
  '' => '庾',
  '' => '悠',
  '' => '惟',
  '' => '愈',
  '' => '愉',
  '' => '揄',
  '' => '攸',
  '' => '有',
  '' => '杻',
  '' => '柔',
  '' => '柚',
  '' => '柳',
  '' => '楡',
  '' => '楢',
  '' => '油',
  '' => '洧',
  '' => '流',
  '' => '游',
  '' => '溜',
  '' => '濡',
  '' => '猶',
  '' => '猷',
  '' => '琉',
  '' => '瑜',
  '' => '由',
  '' => '留',
  '' => '癒',
  '' => '硫',
  '' => '紐',
  '' => '維',
  '' => '臾',
  '' => '萸',
  '' => '裕',
  '' => '誘',
  '' => '諛',
  '' => '諭',
  '' => '踰',
  '' => '蹂',
  '' => '遊',
  '' => '逾',
  '' => '遺',
  '' => '酉',
  '' => '釉',
  '' => '鍮',
  '' => '類',
  '' => '六',
  '' => '堉',
  '' => '戮',
  '' => '毓',
  '' => '肉',
  '' => '育',
  '' => '陸',
  '' => '倫',
  '' => '允',
  '' => '奫',
  '' => '尹',
  '' => '崙',
  '' => '淪',
  '' => '潤',
  '' => '玧',
  '' => '胤',
  '' => '贇',
  '' => '輪',
  '' => '鈗',
  '' => '閏',
  '' => '律',
  '' => '慄',
  '' => '栗',
  '' => '率',
  '' => '聿',
  '' => '戎',
  '' => '瀜',
  '' => '絨',
  '' => '融',
  '' => '隆',
  '' => '垠',
  '' => '恩',
  '' => '慇',
  '' => '殷',
  '' => '誾',
  '' => '銀',
  '' => '隱',
  '' => '乙',
  '' => '吟',
  '' => '淫',
  '' => '蔭',
  '' => '陰',
  '' => '音',
  '' => '飮',
  '' => '揖',
  '' => '泣',
  '' => '邑',
  '' => '凝',
  '' => '應',
  '' => '膺',
  '' => '鷹',
  '' => '依',
  '' => '倚',
  '' => '儀',
  '' => '宜',
  '' => '意',
  '' => '懿',
  '' => '擬',
  '' => '椅',
  '' => '毅',
  '' => '疑',
  '' => '矣',
  '' => '義',
  '' => '艤',
  '' => '薏',
  '' => '蟻',
  '' => '衣',
  '' => '誼',
  '' => '議',
  '' => '醫',
  '' => '二',
  '' => '以',
  '' => '伊',
  '' => '利',
  '' => '吏',
  '' => '夷',
  '' => '姨',
  '' => '履',
  '' => '已',
  '' => '弛',
  '' => '彛',
  '' => '怡',
  '' => '易',
  '' => '李',
  '' => '梨',
  '' => '泥',
  '' => '爾',
  '' => '珥',
  '' => '理',
  '' => '異',
  '' => '痍',
  '' => '痢',
  '' => '移',
  '' => '罹',
  '' => '而',
  '' => '耳',
  '' => '肄',
  '' => '苡',
  '' => '荑',
  '' => '裏',
  '' => '裡',
  '' => '貽',
  '' => '貳',
  '' => '邇',
  '' => '里',
  '' => '離',
  '' => '飴',
  '' => '餌',
  '' => '匿',
  '' => '溺',
  '' => '瀷',
  '' => '益',
  '' => '翊',
  '' => '翌',
  '' => '翼',
  '' => '謚',
  '' => '人',
  '' => '仁',
  '' => '刃',
  '' => '印',
  '' => '吝',
  '' => '咽',
  '' => '因',
  '' => '姻',
  '' => '寅',
  '' => '引',
  '' => '忍',
  '' => '湮',
  '' => '燐',
  '' => '璘',
  '' => '絪',
  '' => '茵',
  '' => '藺',
  '' => '蚓',
  '' => '認',
  '' => '隣',
  '' => '靭',
  '' => '靷',
  '' => '鱗',
  '' => '麟',
  '' => '一',
  '' => '佚',
  '' => '佾',
  '' => '壹',
  '' => '日',
  '' => '溢',
  '' => '逸',
  '' => '鎰',
  '' => '馹',
  '' => '任',
  '' => '壬',
  '' => '妊',
  '' => '姙',
  '' => '恁',
  '' => '林',
  '' => '淋',
  '' => '稔',
  '' => '臨',
  '' => '荏',
  '' => '賃',
  '' => '入',
  '' => '卄',
  '' => '立',
  '' => '笠',
  '' => '粒',
  '' => '仍',
  '' => '剩',
  '' => '孕',
  '' => '芿',
  '' => '仔',
  '' => '刺',
  '' => '咨',
  '' => '姉',
  '' => '姿',
  '' => '子',
  '' => '字',
  '' => '孜',
  '' => '恣',
  '' => '慈',
  '' => '滋',
  '' => '炙',
  '' => '煮',
  '' => '玆',
  '' => '瓷',
  '' => '疵',
  '' => '磁',
  '' => '紫',
  '' => '者',
  '' => '自',
  '' => '茨',
  '' => '蔗',
  '' => '藉',
  '' => '諮',
  '' => '資',
  '' => '雌',
  '' => '作',
  '' => '勺',
  '' => '嚼',
  '' => '斫',
  '' => '昨',
  '' => '灼',
  '' => '炸',
  '' => '爵',
  '' => '綽',
  '' => '芍',
  '' => '酌',
  '' => '雀',
  '' => '鵲',
  '' => '孱',
  '' => '棧',
  '' => '殘',
  '' => '潺',
  '' => '盞',
  '' => '岑',
  '' => '暫',
  '' => '潛',
  '' => '箴',
  '' => '簪',
  '' => '蠶',
  '' => '雜',
  '' => '丈',
  '' => '仗',
  '' => '匠',
  '' => '場',
  '' => '墻',
  '' => '壯',
  '' => '奬',
  '' => '將',
  '' => '帳',
  '' => '庄',
  '' => '張',
  '' => '掌',
  '' => '暲',
  '' => '杖',
  '' => '樟',
  '' => '檣',
  '' => '欌',
  '' => '漿',
  '' => '牆',
  '' => '狀',
  '' => '獐',
  '' => '璋',
  '' => '章',
  '' => '粧',
  '' => '腸',
  '' => '臟',
  '' => '臧',
  '' => '莊',
  '' => '葬',
  '' => '蔣',
  '' => '薔',
  '' => '藏',
  '' => '裝',
  '' => '贓',
  '' => '醬',
  '' => '長',
  '' => '障',
  '' => '再',
  '' => '哉',
  '' => '在',
  '' => '宰',
  '' => '才',
  '' => '材',
  '' => '栽',
  '' => '梓',
  '' => '渽',
  '' => '滓',
  '' => '災',
  '' => '縡',
  '' => '裁',
  '' => '財',
  '' => '載',
  '' => '齋',
  '' => '齎',
  '' => '爭',
  '' => '箏',
  '' => '諍',
  '' => '錚',
  '' => '佇',
  '' => '低',
  '' => '儲',
  '' => '咀',
  '' => '姐',
  '' => '底',
  '' => '抵',
  '' => '杵',
  '' => '楮',
  '' => '樗',
  '' => '沮',
  '' => '渚',
  '' => '狙',
  '' => '猪',
  '' => '疽',
  '' => '箸',
  '' => '紵',
  '' => '苧',
  '' => '菹',
  '' => '著',
  '' => '藷',
  '' => '詛',
  '' => '貯',
  '' => '躇',
  '' => '這',
  '' => '邸',
  '' => '雎',
  '' => '齟',
  '' => '勣',
  '' => '吊',
  '' => '嫡',
  '' => '寂',
  '' => '摘',
  '' => '敵',
  '' => '滴',
  '' => '狄',
  '' => '炙',
  '' => '的',
  '' => '積',
  '' => '笛',
  '' => '籍',
  '' => '績',
  '' => '翟',
  '' => '荻',
  '' => '謫',
  '' => '賊',
  '' => '赤',
  '' => '跡',
  '' => '蹟',
  '' => '迪',
  '' => '迹',
  '' => '適',
  '' => '鏑',
  '' => '佃',
  '' => '佺',
  '' => '傳',
  '' => '全',
  '' => '典',
  '' => '前',
  '' => '剪',
  '' => '塡',
  '' => '塼',
  '' => '奠',
  '' => '專',
  '' => '展',
  '' => '廛',
  '' => '悛',
  '' => '戰',
  '' => '栓',
  '' => '殿',
  '' => '氈',
  '' => '澱',
  '' => '煎',
  '' => '琠',
  '' => '田',
  '' => '甸',
  '' => '畑',
  '' => '癲',
  '' => '筌',
  '' => '箋',
  '' => '箭',
  '' => '篆',
  '' => '纏',
  '' => '詮',
  '' => '輾',
  '' => '轉',
  '' => '鈿',
  '' => '銓',
  '' => '錢',
  '' => '鐫',
  '' => '電',
  '' => '顚',
  '' => '顫',
  '' => '餞',
  '' => '切',
  '' => '截',
  '' => '折',
  '' => '浙',
  '' => '癤',
  '' => '竊',
  '' => '節',
  '' => '絶',
  '' => '占',
  '' => '岾',
  '' => '店',
  '' => '漸',
  '' => '点',
  '' => '粘',
  '' => '霑',
  '' => '鮎',
  '' => '點',
  '' => '接',
  '' => '摺',
  '' => '蝶',
  '' => '丁',
  '' => '井',
  '' => '亭',
  '' => '停',
  '' => '偵',
  '' => '呈',
  '' => '姃',
  '' => '定',
  '' => '幀',
  '' => '庭',
  '' => '廷',
  '' => '征',
  '' => '情',
  '' => '挺',
  '' => '政',
  '' => '整',
  '' => '旌',
  '' => '晶',
  '' => '晸',
  '' => '柾',
  '' => '楨',
  '' => '檉',
  '' => '正',
  '' => '汀',
  '' => '淀',
  '' => '淨',
  '' => '渟',
  '' => '湞',
  '' => '瀞',
  '' => '炡',
  '' => '玎',
  '' => '珽',
  '' => '町',
  '' => '睛',
  '' => '碇',
  '' => '禎',
  '' => '程',
  '' => '穽',
  '' => '精',
  '' => '綎',
  '' => '艇',
  '' => '訂',
  '' => '諪',
  '' => '貞',
  '' => '鄭',
  '' => '酊',
  '' => '釘',
  '' => '鉦',
  '' => '鋌',
  '' => '錠',
  '' => '霆',
  '' => '靖',
  '' => '靜',
  '' => '頂',
  '' => '鼎',
  '' => '制',
  '' => '劑',
  '' => '啼',
  '' => '堤',
  '' => '帝',
  '' => '弟',
  '' => '悌',
  '' => '提',
  '' => '梯',
  '' => '濟',
  '' => '祭',
  '' => '第',
  '' => '臍',
  '' => '薺',
  '' => '製',
  '' => '諸',
  '' => '蹄',
  '' => '醍',
  '' => '除',
  '' => '際',
  '' => '霽',
  '' => '題',
  '' => '齊',
  '' => '俎',
  '' => '兆',
  '' => '凋',
  '' => '助',
  '' => '嘲',
  '' => '弔',
  '' => '彫',
  '' => '措',
  '' => '操',
  '' => '早',
  '' => '晁',
  '' => '曺',
  '' => '曹',
  '' => '朝',
  '' => '條',
  '' => '棗',
  '' => '槽',
  '' => '漕',
  '' => '潮',
  '' => '照',
  '' => '燥',
  '' => '爪',
  '' => '璪',
  '' => '眺',
  '' => '祖',
  '' => '祚',
  '' => '租',
  '' => '稠',
  '' => '窕',
  '' => '粗',
  '' => '糟',
  '' => '組',
  '' => '繰',
  '' => '肇',
  '' => '藻',
  '' => '蚤',
  '' => '詔',
  '' => '調',
  '' => '趙',
  '' => '躁',
  '' => '造',
  '' => '遭',
  '' => '釣',
  '' => '阻',
  '' => '雕',
  '' => '鳥',
  '' => '族',
  '' => '簇',
  '' => '足',
  '' => '鏃',
  '' => '存',
  '' => '尊',
  '' => '卒',
  '' => '拙',
  '' => '猝',
  '' => '倧',
  '' => '宗',
  '' => '從',
  '' => '悰',
  '' => '慫',
  '' => '棕',
  '' => '淙',
  '' => '琮',
  '' => '種',
  '' => '終',
  '' => '綜',
  '' => '縱',
  '' => '腫',
  '' => '踪',
  '' => '踵',
  '' => '鍾',
  '' => '鐘',
  '' => '佐',
  '' => '坐',
  '' => '左',
  '' => '座',
  '' => '挫',
  '' => '罪',
  '' => '主',
  '' => '住',
  '' => '侏',
  '' => '做',
  '' => '姝',
  '' => '胄',
  '' => '呪',
  '' => '周',
  '' => '嗾',
  '' => '奏',
  '' => '宙',
  '' => '州',
  '' => '廚',
  '' => '晝',
  '' => '朱',
  '' => '柱',
  '' => '株',
  '' => '注',
  '' => '洲',
  '' => '湊',
  '' => '澍',
  '' => '炷',
  '' => '珠',
  '' => '疇',
  '' => '籌',
  '' => '紂',
  '' => '紬',
  '' => '綢',
  '' => '舟',
  '' => '蛛',
  '' => '註',
  '' => '誅',
  '' => '走',
  '' => '躊',
  '' => '輳',
  '' => '週',
  '' => '酎',
  '' => '酒',
  '' => '鑄',
  '' => '駐',
  '' => '竹',
  '' => '粥',
  '' => '俊',
  '' => '儁',
  '' => '准',
  '' => '埈',
  '' => '寯',
  '' => '峻',
  '' => '晙',
  '' => '樽',
  '' => '浚',
  '' => '準',
  '' => '濬',
  '' => '焌',
  '' => '畯',
  '' => '竣',
  '' => '蠢',
  '' => '逡',
  '' => '遵',
  '' => '雋',
  '' => '駿',
  '' => '茁',
  '' => '中',
  '' => '仲',
  '' => '衆',
  '' => '重',
  '' => '卽',
  '' => '櫛',
  '' => '楫',
  '' => '汁',
  '' => '葺',
  '' => '增',
  '' => '憎',
  '' => '曾',
  '' => '拯',
  '' => '烝',
  '' => '甑',
  '' => '症',
  '' => '繒',
  '' => '蒸',
  '' => '證',
  '' => '贈',
  '' => '之',
  '' => '只',
  '' => '咫',
  '' => '地',
  '' => '址',
  '' => '志',
  '' => '持',
  '' => '指',
  '' => '摯',
  '' => '支',
  '' => '旨',
  '' => '智',
  '' => '枝',
  '' => '枳',
  '' => '止',
  '' => '池',
  '' => '沚',
  '' => '漬',
  '' => '知',
  '' => '砥',
  '' => '祉',
  '' => '祗',
  '' => '紙',
  '' => '肢',
  '' => '脂',
  '' => '至',
  '' => '芝',
  '' => '芷',
  '' => '蜘',
  '' => '誌',
  '' => '識',
  '' => '贄',
  '' => '趾',
  '' => '遲',
  '' => '直',
  '' => '稙',
  '' => '稷',
  '' => '織',
  '' => '職',
  '' => '唇',
  '' => '嗔',
  '' => '塵',
  '' => '振',
  '' => '搢',
  '' => '晉',
  '' => '晋',
  '' => '桭',
  '' => '榛',
  '' => '殄',
  '' => '津',
  '' => '溱',
  '' => '珍',
  '' => '瑨',
  '' => '璡',
  '' => '畛',
  '' => '疹',
  '' => '盡',
  '' => '眞',
  '' => '瞋',
  '' => '秦',
  '' => '縉',
  '' => '縝',
  '' => '臻',
  '' => '蔯',
  '' => '袗',
  '' => '診',
  '' => '賑',
  '' => '軫',
  '' => '辰',
  '' => '進',
  '' => '鎭',
  '' => '陣',
  '' => '陳',
  '' => '震',
  '' => '侄',
  '' => '叱',
  '' => '姪',
  '' => '嫉',
  '' => '帙',
  '' => '桎',
  '' => '瓆',
  '' => '疾',
  '' => '秩',
  '' => '窒',
  '' => '膣',
  '' => '蛭',
  '' => '質',
  '' => '跌',
  '' => '迭',
  '' => '斟',
  '' => '朕',
  '' => '什',
  '' => '執',
  '' => '潗',
  '' => '緝',
  '' => '輯',
  '' => '鏶',
  '' => '集',
  '' => '徵',
  '' => '懲',
  '' => '澄',
  '' => '且',
  '' => '侘',
  '' => '借',
  '' => '叉',
  '' => '嗟',
  '' => '嵯',
  '' => '差',
  '' => '次',
  '' => '此',
  '' => '磋',
  '' => '箚',
  '' => '茶',
  '' => '蹉',
  '' => '車',
  '' => '遮',
  '' => '捉',
  '' => '搾',
  '' => '着',
  '' => '窄',
  '' => '錯',
  '' => '鑿',
  '' => '齪',
  '' => '撰',
  '' => '澯',
  '' => '燦',
  '' => '璨',
  '' => '瓚',
  '' => '竄',
  '' => '簒',
  '' => '纂',
  '' => '粲',
  '' => '纘',
  '' => '讚',
  '' => '贊',
  '' => '鑽',
  '' => '餐',
  '' => '饌',
  '' => '刹',
  '' => '察',
  '' => '擦',
  '' => '札',
  '' => '紮',
  '' => '僭',
  '' => '參',
  '' => '塹',
  '' => '慘',
  '' => '慙',
  '' => '懺',
  '' => '斬',
  '' => '站',
  '' => '讒',
  '' => '讖',
  '' => '倉',
  '' => '倡',
  '' => '創',
  '' => '唱',
  '' => '娼',
  '' => '廠',
  '' => '彰',
  '' => '愴',
  '' => '敞',
  '' => '昌',
  '' => '昶',
  '' => '暢',
  '' => '槍',
  '' => '滄',
  '' => '漲',
  '' => '猖',
  '' => '瘡',
  '' => '窓',
  '' => '脹',
  '' => '艙',
  '' => '菖',
  '' => '蒼',
  '' => '債',
  '' => '埰',
  '' => '寀',
  '' => '寨',
  '' => '彩',
  '' => '採',
  '' => '砦',
  '' => '綵',
  '' => '菜',
  '' => '蔡',
  '' => '采',
  '' => '釵',
  '' => '冊',
  '' => '柵',
  '' => '策',
  '' => '責',
  '' => '凄',
  '' => '妻',
  '' => '悽',
  '' => '處',
  '' => '倜',
  '' => '刺',
  '' => '剔',
  '' => '尺',
  '' => '慽',
  '' => '戚',
  '' => '拓',
  '' => '擲',
  '' => '斥',
  '' => '滌',
  '' => '瘠',
  '' => '脊',
  '' => '蹠',
  '' => '陟',
  '' => '隻',
  '' => '仟',
  '' => '千',
  '' => '喘',
  '' => '天',
  '' => '川',
  '' => '擅',
  '' => '泉',
  '' => '淺',
  '' => '玔',
  '' => '穿',
  '' => '舛',
  '' => '薦',
  '' => '賤',
  '' => '踐',
  '' => '遷',
  '' => '釧',
  '' => '闡',
  '' => '阡',
  '' => '韆',
  '' => '凸',
  '' => '哲',
  '' => '喆',
  '' => '徹',
  '' => '撤',
  '' => '澈',
  '' => '綴',
  '' => '輟',
  '' => '轍',
  '' => '鐵',
  '' => '僉',
  '' => '尖',
  '' => '沾',
  '' => '添',
  '' => '甛',
  '' => '瞻',
  '' => '簽',
  '' => '籤',
  '' => '詹',
  '' => '諂',
  '' => '堞',
  '' => '妾',
  '' => '帖',
  '' => '捷',
  '' => '牒',
  '' => '疊',
  '' => '睫',
  '' => '諜',
  '' => '貼',
  '' => '輒',
  '' => '廳',
  '' => '晴',
  '' => '淸',
  '' => '聽',
  '' => '菁',
  '' => '請',
  '' => '靑',
  '' => '鯖',
  '' => '切',
  '' => '剃',
  '' => '替',
  '' => '涕',
  '' => '滯',
  '' => '締',
  '' => '諦',
  '' => '逮',
  '' => '遞',
  '' => '體',
  '' => '初',
  '' => '剿',
  '' => '哨',
  '' => '憔',
  '' => '抄',
  '' => '招',
  '' => '梢',
  '' => '椒',
  '' => '楚',
  '' => '樵',
  '' => '炒',
  '' => '焦',
  '' => '硝',
  '' => '礁',
  '' => '礎',
  '' => '秒',
  '' => '稍',
  '' => '肖',
  '' => '艸',
  '' => '苕',
  '' => '草',
  '' => '蕉',
  '' => '貂',
  '' => '超',
  '' => '酢',
  '' => '醋',
  '' => '醮',
  '' => '促',
  '' => '囑',
  '' => '燭',
  '' => '矗',
  '' => '蜀',
  '' => '觸',
  '' => '寸',
  '' => '忖',
  '' => '村',
  '' => '邨',
  '' => '叢',
  '' => '塚',
  '' => '寵',
  '' => '悤',
  '' => '憁',
  '' => '摠',
  '' => '總',
  '' => '聰',
  '' => '蔥',
  '' => '銃',
  '' => '撮',
  '' => '催',
  '' => '崔',
  '' => '最',
  '' => '墜',
  '' => '抽',
  '' => '推',
  '' => '椎',
  '' => '楸',
  '' => '樞',
  '' => '湫',
  '' => '皺',
  '' => '秋',
  '' => '芻',
  '' => '萩',
  '' => '諏',
  '' => '趨',
  '' => '追',
  '' => '鄒',
  '' => '酋',
  '' => '醜',
  '' => '錐',
  '' => '錘',
  '' => '鎚',
  '' => '雛',
  '' => '騶',
  '' => '鰍',
  '' => '丑',
  '' => '畜',
  '' => '祝',
  '' => '竺',
  '' => '筑',
  '' => '築',
  '' => '縮',
  '' => '蓄',
  '' => '蹙',
  '' => '蹴',
  '' => '軸',
  '' => '逐',
  '' => '春',
  '' => '椿',
  '' => '瑃',
  '' => '出',
  '' => '朮',
  '' => '黜',
  '' => '充',
  '' => '忠',
  '' => '沖',
  '' => '蟲',
  '' => '衝',
  '' => '衷',
  '' => '悴',
  '' => '膵',
  '' => '萃',
  '' => '贅',
  '' => '取',
  '' => '吹',
  '' => '嘴',
  '' => '娶',
  '' => '就',
  '' => '炊',
  '' => '翠',
  '' => '聚',
  '' => '脆',
  '' => '臭',
  '' => '趣',
  '' => '醉',
  '' => '驟',
  '' => '鷲',
  '' => '側',
  '' => '仄',
  '' => '厠',
  '' => '惻',
  '' => '測',
  '' => '層',
  '' => '侈',
  '' => '値',
  '' => '嗤',
  '' => '峙',
  '' => '幟',
  '' => '恥',
  '' => '梔',
  '' => '治',
  '' => '淄',
  '' => '熾',
  '' => '痔',
  '' => '痴',
  '' => '癡',
  '' => '稚',
  '' => '穉',
  '' => '緇',
  '' => '緻',
  '' => '置',
  '' => '致',
  '' => '蚩',
  '' => '輜',
  '' => '雉',
  '' => '馳',
  '' => '齒',
  '' => '則',
  '' => '勅',
  '' => '飭',
  '' => '親',
  '' => '七',
  '' => '柒',
  '' => '漆',
  '' => '侵',
  '' => '寢',
  '' => '枕',
  '' => '沈',
  '' => '浸',
  '' => '琛',
  '' => '砧',
  '' => '針',
  '' => '鍼',
  '' => '蟄',
  '' => '秤',
  '' => '稱',
  '' => '快',
  '' => '他',
  '' => '咤',
  '' => '唾',
  '' => '墮',
  '' => '妥',
  '' => '惰',
  '' => '打',
  '' => '拖',
  '' => '朶',
  '' => '楕',
  '' => '舵',
  '' => '陀',
  '' => '馱',
  '' => '駝',
  '' => '倬',
  '' => '卓',
  '' => '啄',
  '' => '坼',
  '' => '度',
  '' => '托',
  '' => '拓',
  '' => '擢',
  '' => '晫',
  '' => '柝',
  '' => '濁',
  '' => '濯',
  '' => '琢',
  '' => '琸',
  '' => '託',
  '' => '鐸',
  '' => '呑',
  '' => '嘆',
  '' => '坦',
  '' => '彈',
  '' => '憚',
  '' => '歎',
  '' => '灘',
  '' => '炭',
  '' => '綻',
  '' => '誕',
  '' => '奪',
  '' => '脫',
  '' => '探',
  '' => '眈',
  '' => '耽',
  '' => '貪',
  '' => '塔',
  '' => '搭',
  '' => '榻',
  '' => '宕',
  '' => '帑',
  '' => '湯',
  '' => '糖',
  '' => '蕩',
  '' => '兌',
  '' => '台',
  '' => '太',
  '' => '怠',
  '' => '態',
  '' => '殆',
  '' => '汰',
  '' => '泰',
  '' => '笞',
  '' => '胎',
  '' => '苔',
  '' => '跆',
  '' => '邰',
  '' => '颱',
  '' => '宅',
  '' => '擇',
  '' => '澤',
  '' => '撑',
  '' => '攄',
  '' => '兎',
  '' => '吐',
  '' => '土',
  '' => '討',
  '' => '慟',
  '' => '桶',
  '' => '洞',
  '' => '痛',
  '' => '筒',
  '' => '統',
  '' => '通',
  '' => '堆',
  '' => '槌',
  '' => '腿',
  '' => '褪',
  '' => '退',
  '' => '頹',
  '' => '偸',
  '' => '套',
  '' => '妬',
  '' => '投',
  '' => '透',
  '' => '鬪',
  '' => '慝',
  '' => '特',
  '' => '闖',
  '' => '坡',
  '' => '婆',
  '' => '巴',
  '' => '把',
  '' => '播',
  '' => '擺',
  '' => '杷',
  '' => '波',
  '' => '派',
  '' => '爬',
  '' => '琶',
  '' => '破',
  '' => '罷',
  '' => '芭',
  '' => '跛',
  '' => '頗',
  '' => '判',
  '' => '坂',
  '' => '板',
  '' => '版',
  '' => '瓣',
  '' => '販',
  '' => '辦',
  '' => '鈑',
  '' => '阪',
  '' => '八',
  '' => '叭',
  '' => '捌',
  '' => '佩',
  '' => '唄',
  '' => '悖',
  '' => '敗',
  '' => '沛',
  '' => '浿',
  '' => '牌',
  '' => '狽',
  '' => '稗',
  '' => '覇',
  '' => '貝',
  '' => '彭',
  '' => '澎',
  '' => '烹',
  '' => '膨',
  '' => '愎',
  '' => '便',
  '' => '偏',
  '' => '扁',
  '' => '片',
  '' => '篇',
  '' => '編',
  '' => '翩',
  '' => '遍',
  '' => '鞭',
  '' => '騙',
  '' => '貶',
  '' => '坪',
  '' => '平',
  '' => '枰',
  '' => '萍',
  '' => '評',
  '' => '吠',
  '' => '嬖',
  '' => '幣',
  '' => '廢',
  '' => '弊',
  '' => '斃',
  '' => '肺',
  '' => '蔽',
  '' => '閉',
  '' => '陛',
  '' => '佈',
  '' => '包',
  '' => '匍',
  '' => '匏',
  '' => '咆',
  '' => '哺',
  '' => '圃',
  '' => '布',
  '' => '怖',
  '' => '抛',
  '' => '抱',
  '' => '捕',
  '' => '暴',
  '' => '泡',
  '' => '浦',
  '' => '疱',
  '' => '砲',
  '' => '胞',
  '' => '脯',
  '' => '苞',
  '' => '葡',
  '' => '蒲',
  '' => '袍',
  '' => '褒',
  '' => '逋',
  '' => '鋪',
  '' => '飽',
  '' => '鮑',
  '' => '幅',
  '' => '暴',
  '' => '曝',
  '' => '瀑',
  '' => '爆',
  '' => '輻',
  '' => '俵',
  '' => '剽',
  '' => '彪',
  '' => '慓',
  '' => '杓',
  '' => '標',
  '' => '漂',
  '' => '瓢',
  '' => '票',
  '' => '表',
  '' => '豹',
  '' => '飇',
  '' => '飄',
  '' => '驃',
  '' => '品',
  '' => '稟',
  '' => '楓',
  '' => '諷',
  '' => '豊',
  '' => '風',
  '' => '馮',
  '' => '彼',
  '' => '披',
  '' => '疲',
  '' => '皮',
  '' => '被',
  '' => '避',
  '' => '陂',
  '' => '匹',
  '' => '弼',
  '' => '必',
  '' => '泌',
  '' => '珌',
  '' => '畢',
  '' => '疋',
  '' => '筆',
  '' => '苾',
  '' => '馝',
  '' => '乏',
  '' => '逼',
  '' => '下',
  '' => '何',
  '' => '厦',
  '' => '夏',
  '' => '廈',
  '' => '昰',
  '' => '河',
  '' => '瑕',
  '' => '荷',
  '' => '蝦',
  '' => '賀',
  '' => '遐',
  '' => '霞',
  '' => '鰕',
  '' => '壑',
  '' => '學',
  '' => '虐',
  '' => '謔',
  '' => '鶴',
  '' => '寒',
  '' => '恨',
  '' => '悍',
  '' => '旱',
  '' => '汗',
  '' => '漢',
  '' => '澣',
  '' => '瀚',
  '' => '罕',
  '' => '翰',
  '' => '閑',
  '' => '閒',
  '' => '限',
  '' => '韓',
  '' => '割',
  '' => '轄',
  '' => '函',
  '' => '含',
  '' => '咸',
  '' => '啣',
  '' => '喊',
  '' => '檻',
  '' => '涵',
  '' => '緘',
  '' => '艦',
  '' => '銜',
  '' => '陷',
  '' => '鹹',
  '' => '合',
  '' => '哈',
  '' => '盒',
  '' => '蛤',
  '' => '閤',
  '' => '闔',
  '' => '陜',
  '' => '亢',
  '' => '伉',
  '' => '姮',
  '' => '嫦',
  '' => '巷',
  '' => '恒',
  '' => '抗',
  '' => '杭',
  '' => '桁',
  '' => '沆',
  '' => '港',
  '' => '缸',
  '' => '肛',
  '' => '航',
  '' => '行',
  '' => '降',
  '' => '項',
  '' => '亥',
  '' => '偕',
  '' => '咳',
  '' => '垓',
  '' => '奚',
  '' => '孩',
  '' => '害',
  '' => '懈',
  '' => '楷',
  '' => '海',
  '' => '瀣',
  '' => '蟹',
  '' => '解',
  '' => '該',
  '' => '諧',
  '' => '邂',
  '' => '駭',
  '' => '骸',
  '' => '劾',
  '' => '核',
  '' => '倖',
  '' => '幸',
  '' => '杏',
  '' => '荇',
  '' => '行',
  '' => '享',
  '' => '向',
  '' => '嚮',
  '' => '珦',
  '' => '鄕',
  '' => '響',
  '' => '餉',
  '' => '饗',
  '' => '香',
  '' => '噓',
  '' => '墟',
  '' => '虛',
  '' => '許',
  '' => '憲',
  '' => '櫶',
  '' => '獻',
  '' => '軒',
  '' => '歇',
  '' => '險',
  '' => '驗',
  '' => '奕',
  '' => '爀',
  '' => '赫',
  '' => '革',
  '' => '俔',
  '' => '峴',
  '' => '弦',
  '' => '懸',
  '' => '晛',
  '' => '泫',
  '' => '炫',
  '' => '玄',
  '' => '玹',
  '' => '現',
  '' => '眩',
  '' => '睍',
  '' => '絃',
  '' => '絢',
  '' => '縣',
  '' => '舷',
  '' => '衒',
  '' => '見',
  '' => '賢',
  '' => '鉉',
  '' => '顯',
  '' => '孑',
  '' => '穴',
  '' => '血',
  '' => '頁',
  '' => '嫌',
  '' => '俠',
  '' => '協',
  '' => '夾',
  '' => '峽',
  '' => '挾',
  '' => '浹',
  '' => '狹',
  '' => '脅',
  '' => '脇',
  '' => '莢',
  '' => '鋏',
  '' => '頰',
  '' => '亨',
  '' => '兄',
  '' => '刑',
  '' => '型',
  '' => '形',
  '' => '泂',
  '' => '滎',
  '' => '瀅',
  '' => '灐',
  '' => '炯',
  '' => '熒',
  '' => '珩',
  '' => '瑩',
  '' => '荊',
  '' => '螢',
  '' => '衡',
  '' => '逈',
  '' => '邢',
  '' => '鎣',
  '' => '馨',
  '' => '兮',
  '' => '彗',
  '' => '惠',
  '' => '慧',
  '' => '暳',
  '' => '蕙',
  '' => '蹊',
  '' => '醯',
  '' => '鞋',
  '' => '乎',
  '' => '互',
  '' => '呼',
  '' => '壕',
  '' => '壺',
  '' => '好',
  '' => '岵',
  '' => '弧',
  '' => '戶',
  '' => '扈',
  '' => '昊',
  '' => '晧',
  '' => '毫',
  '' => '浩',
  '' => '淏',
  '' => '湖',
  '' => '滸',
  '' => '澔',
  '' => '濠',
  '' => '濩',
  '' => '灝',
  '' => '狐',
  '' => '琥',
  '' => '瑚',
  '' => '瓠',
  '' => '皓',
  '' => '祜',
  '' => '糊',
  '' => '縞',
  '' => '胡',
  '' => '芦',
  '' => '葫',
  '' => '蒿',
  '' => '虎',
  '' => '號',
  '' => '蝴',
  '' => '護',
  '' => '豪',
  '' => '鎬',
  '' => '頀',
  '' => '顥',
  '' => '惑',
  '' => '或',
  '' => '酷',
  '' => '婚',
  '' => '昏',
  '' => '混',
  '' => '渾',
  '' => '琿',
  '' => '魂',
  '' => '忽',
  '' => '惚',
  '' => '笏',
  '' => '哄',
  '' => '弘',
  '' => '汞',
  '' => '泓',
  '' => '洪',
  '' => '烘',
  '' => '紅',
  '' => '虹',
  '' => '訌',
  '' => '鴻',
  '' => '化',
  '' => '和',
  '' => '嬅',
  '' => '樺',
  '' => '火',
  '' => '畵',
  '' => '禍',
  '' => '禾',
  '' => '花',
  '' => '華',
  '' => '話',
  '' => '譁',
  '' => '貨',
  '' => '靴',
  '' => '廓',
  '' => '擴',
  '' => '攫',
  '' => '確',
  '' => '碻',
  '' => '穫',
  '' => '丸',
  '' => '喚',
  '' => '奐',
  '' => '宦',
  '' => '幻',
  '' => '患',
  '' => '換',
  '' => '歡',
  '' => '晥',
  '' => '桓',
  '' => '渙',
  '' => '煥',
  '' => '環',
  '' => '紈',
  '' => '還',
  '' => '驩',
  '' => '鰥',
  '' => '活',
  '' => '滑',
  '' => '猾',
  '' => '豁',
  '' => '闊',
  '' => '凰',
  '' => '幌',
  '' => '徨',
  '' => '恍',
  '' => '惶',
  '' => '愰',
  '' => '慌',
  '' => '晃',
  '' => '晄',
  '' => '榥',
  '' => '況',
  '' => '湟',
  '' => '滉',
  '' => '潢',
  '' => '煌',
  '' => '璜',
  '' => '皇',
  '' => '篁',
  '' => '簧',
  '' => '荒',
  '' => '蝗',
  '' => '遑',
  '' => '隍',
  '' => '黃',
  '' => '匯',
  '' => '回',
  '' => '廻',
  '' => '徊',
  '' => '恢',
  '' => '悔',
  '' => '懷',
  '' => '晦',
  '' => '會',
  '' => '檜',
  '' => '淮',
  '' => '澮',
  '' => '灰',
  '' => '獪',
  '' => '繪',
  '' => '膾',
  '' => '茴',
  '' => '蛔',
  '' => '誨',
  '' => '賄',
  '' => '劃',
  '' => '獲',
  '' => '宖',
  '' => '橫',
  '' => '鐄',
  '' => '哮',
  '' => '嚆',
  '' => '孝',
  '' => '效',
  '' => '斅',
  '' => '曉',
  '' => '梟',
  '' => '涍',
  '' => '淆',
  '' => '爻',
  '' => '肴',
  '' => '酵',
  '' => '驍',
  '' => '侯',
  '' => '候',
  '' => '厚',
  '' => '后',
  '' => '吼',
  '' => '喉',
  '' => '嗅',
  '' => '帿',
  '' => '後',
  '' => '朽',
  '' => '煦',
  '' => '珝',
  '' => '逅',
  '' => '勛',
  '' => '勳',
  '' => '塤',
  '' => '壎',
  '' => '焄',
  '' => '熏',
  '' => '燻',
  '' => '薰',
  '' => '訓',
  '' => '暈',
  '' => '薨',
  '' => '喧',
  '' => '暄',
  '' => '煊',
  '' => '萱',
  '' => '卉',
  '' => '喙',
  '' => '毁',
  '' => '彙',
  '' => '徽',
  '' => '揮',
  '' => '暉',
  '' => '煇',
  '' => '諱',
  '' => '輝',
  '' => '麾',
  '' => '休',
  '' => '携',
  '' => '烋',
  '' => '畦',
  '' => '虧',
  '' => '恤',
  '' => '譎',
  '' => '鷸',
  '' => '兇',
  '' => '凶',
  '' => '匈',
  '' => '洶',
  '' => '胸',
  '' => '黑',
  '' => '昕',
  '' => '欣',
  '' => '炘',
  '' => '痕',
  '' => '吃',
  '' => '屹',
  '' => '紇',
  '' => '訖',
  '' => '欠',
  '' => '欽',
  '' => '歆',
  '' => '吸',
  '' => '恰',
  '' => '洽',
  '' => '翕',
  '' => '興',
  '' => '僖',
  '' => '凞',
  '' => '喜',
  '' => '噫',
  '' => '囍',
  '' => '姬',
  '' => '嬉',
  '' => '希',
  '' => '憙',
  '' => '憘',
  '' => '戱',
  '' => '晞',
  '' => '曦',
  '' => '熙',
  '' => '熹',
  '' => '熺',
  '' => '犧',
  '' => '禧',
  '' => '稀',
  '' => '羲',
  '' => '詰',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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' => '▆',
  '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' => '肛',
  '{' => '肚',
  '|' => '育',
  '}' => '良',
  '~' => '芒',
  '' => '芋',
  '' => '芍',
  '' => '見',
  '' => '角',
  '' => '言',
  '' => '谷',
  '' => '豆',
  '' => '豕',
  '' => '貝',
  '' => '赤',
  '' => '走',
  '' => '足',
  '' => '身',
  '' => '車',
  '' => '辛',
  '' => '辰',
  '' => '迂',
  '' => '迆',
  '' => '迅',
  '' => '迄',
  '' => '巡',
  '' => '邑',
  '' => '邢',
  '' => '邪',
  '' => '邦',
  '' => '那',
  '' => '酉',
  '' => '釆',
  '' => '里',
  '' => '防',
  '' => '阮',
  '' => '阱',
  '' => '阪',
  '' => '阬',
  '' => '並',
  '' => '乖',
  '' => '乳',
  '' => '事',
  '' => '些',
  '' => '亞',
  '' => '享',
  '' => '京',
  '' => '佯',
  '' => '依',
  '' => '侍',
  '' => '佳',
  '' => '使',
  '' => '佬',
  '' => '供',
  '' => '例',
  '' => '來',
  '' => '侃',
  '' => '佰',
  '' => '併',
  '' => '侈',
  '' => '佩',
  '' => '佻',
  '' => '侖',
  '' => '佾',
  '' => '侏',
  '' => '侑',
  '' => '佺',
  '' => '兔',
  '' => '兒',
  '' => '兕',
  '' => '兩',
  '' => '具',
  '' => '其',
  '' => '典',
  '' => '冽',
  '' => '函',
  '' => '刻',
  '' => '券',
  '' => '刷',
  '' => '刺',
  '' => '到',
  '' => '刮',
  '' => '制',
  '' => '剁',
  '' => '劾',
  '' => '劻',
  '' => '卒',
  '' => '協',
  '' => '卓',
  '' => '卑',
  '' => '卦',
  '' => '卷',
  '' => '卸',
  '' => '卹',
  '' => '取',
  '' => '叔',
  '' => '受',
  '' => '味',
  '' => '呵',
  '@' => '咖',
  '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' => '班',
  '[' => '琉',
  '\\' => '珮',
  ']' => '珠',
  '^' => '珪',
  '_' => '珞',
  '`' => '畔',
  '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' => '稈',
  '{' => '程',
  '|' => '稅',
  '}' => '稀',
  '~' => '窘',
  '' => '窗',
  '' => '窖',
  '' => '童',
  '' => '竣',
  '' => '等',
  '' => '策',
  '' => '筆',
  '' => '筐',
  '' => '筒',
  '' => '答',
  '' => '筍',
  '' => '筋',
  '' => '筏',
  '' => '筑',
  '' => '粟',
  '' => '粥',
  '' => '絞',
  '' => '結',
  '' => '絨',
  '' => '絕',
  '' => '紫',
  '' => '絮',
  '' => '絲',
  '' => '絡',
  '' => '給',
  '' => '絢',
  '' => '絰',
  '' => '絳',
  '' => '善',
  '' => '翔',
  '' => '翕',
  '' => '耋',
  '' => '聒',
  '' => '肅',
  '' => '腕',
  '' => '腔',
  '' => '腋',
  '' => '腑',
  '' => '腎',
  '' => '脹',
  '' => '腆',
  '' => '脾',
  '' => '腌',
  '' => '腓',
  '' => '腴',
  '' => '舒',
  '' => '舜',
  '' => '菩',
  '' => '萃',
  '' => '菸',
  '' => '萍',
  '' => '菠',
  '' => '菅',
  '' => '萋',
  '' => '菁',
  '' => '華',
  '' => '菱',
  '' => '菴',
  '' => '著',
  '' => '萊',
  '' => '菰',
  '' => '萌',
  '' => '菌',
  '' => '菽',
  '' => '菲',
  '' => '菊',
  '' => '萸',
  '' => '萎',
  '' => '萄',
  '' => '菜',
  '' => '萇',
  '' => '菔',
  '' => '菟',
  '' => '虛',
  '' => '蛟',
  '' => '蛙',
  '' => '蛭',
  '' => '蛔',
  '' => '蛛',
  '' => '蛤',
  '' => '蛐',
  '' => '蛞',
  '' => '街',
  '' => '裁',
  '' => '裂',
  '' => '袱',
  '' => '覃',
  '' => '視',
  '' => '註',
  '' => '詠',
  '' => '評',
  '' => '詞',
  '' => '証',
  '' => '詁',
  '@' => '詔',
  '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' => '墮',
  '[' => '墩',
  '\\' => '墦',
  ']' => '奭',
  '^' => '嬉',
  '_' => '嫻',
  '`' => '嬋',
  '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' => '璧',
  '{' => '璿',
  '|' => '甕',
  '}' => '癖',
  '~' => '癘',
  '¡' => '癒',
  '¢' => '瞽',
  '£' => '瞿',
  '¤' => '瞻',
  '¥' => '瞼',
  '¦' => '礎',
  '§' => '禮',
  '¨' => '穡',
  '©' => '穢',
  'ª' => '穠',
  '«' => '竄',
  '¬' => '竅',
  '­' => '簫',
  '®' => '簧',
  '¯' => '簪',
  '°' => '簞',
  '±' => '簣',
  '²' => '簡',
  '³' => '糧',
  '´' => '織',
  'µ' => '繕',
  '¶' => '繞',
  '·' => '繚',
  '¸' => '繡',
  '¹' => '繒',
  'º' => '繙',
  '»' => '罈',
  '¼' => '翹',
  '½' => '翻',
  '¾' => '職',
  '¿' => '聶',
  '' => '臍',
  '' => '臏',
  '' => '舊',
  '' => '藏',
  '' => '薩',
  '' => '藍',
  '' => '藐',
  '' => '藉',
  '' => '薰',
  '' => '薺',
  '' => '薹',
  '' => '薦',
  '' => '蟯',
  '' => '蟬',
  '' => '蟲',
  '' => '蟠',
  '' => '覆',
  '' => '覲',
  '' => '觴',
  '' => '謨',
  '' => '謹',
  '' => '謬',
  '' => '謫',
  '' => '豐',
  '' => '贅',
  '' => '蹙',
  '' => '蹣',
  '' => '蹦',
  '' => '蹤',
  '' => '蹟',
  '' => '蹕',
  '' => '軀',
  '' => '轉',
  '' => '轍',
  '' => '邇',
  '' => '邃',
  '' => '邈',
  '' => '醫',
  '' => '醬',
  '' => '釐',
  '' => '鎔',
  '' => '鎊',
  '' => '鎖',
  '' => '鎢',
  '' => '鎳',
  '' => '鎮',
  '' => '鎬',
  '' => '鎰',
  '' => '鎘',
  '' => '鎚',
  '' => '鎗',
  '' => '闔',
  '' => '闖',
  '' => '闐',
  '' => '闕',
  '' => '離',
  '' => '雜',
  '' => '雙',
  '' => '雛',
  '' => '雞',
  '' => '霤',
  '' => '鞣',
  '' => '鞦',
  '@' => '鞭',
  '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' => '汳',
  '[' => '汥',
  '\\' => '汻',
  ']' => '沎',
  '^' => '灴',
  '_' => '灺',
  '`' => '牣',
  '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' => '弰',
  '{' => '彧',
  '|' => '恝',
  '}' => '恚',
  '~' => '恧',
  'ѡ' => '恁',
  'Ѣ' => '悢',
  'ѣ' => '悈',
  'Ѥ' => '悀',
  'ѥ' => '悒',
  'Ѧ' => '悁',
  'ѧ' => '悝',
  'Ѩ' => '悃',
  'ѩ' => '悕',
  'Ѫ' => '悛',
  'ѫ' => '悗',
  'Ѭ' => '悇',
  'ѭ' => '悜',
  'Ѯ' => '悎',
  'ѯ' => '戙',
  'Ѱ' => '扆',
  'ѱ' => '拲',
  'Ѳ' => '挐',
  'ѳ' => '捖',
  'Ѵ' => '挬',
  'ѵ' => '捄',
  'Ѷ' => '捅',
  'ѷ' => '挶',
  'Ѹ' => '捃',
  'ѹ' => '揤',
  'Ѻ' => '挹',
  'ѻ' => '捋',
  'Ѽ' => '捊',
  'ѽ' => '挼',
  'Ѿ' => '挩',
  'ѿ' => '捁',
  '' => '挴',
  '' => '捘',
  '' => '捔',
  '' => '捙',
  '' => '挭',
  '' => '捇',
  '' => '挳',
  '' => '捚',
  '' => '捑',
  '' => '挸',
  '' => '捗',
  '' => '捀',
  '' => '捈',
  '' => '敊',
  '' => '敆',
  '' => '旆',
  '' => '旃',
  '' => '旄',
  '' => '旂',
  '' => '晊',
  '' => '晟',
  '' => '晇',
  '' => '晑',
  '' => '朒',
  '' => '朓',
  '' => '栟',
  '' => '栚',
  '' => '桉',
  '' => '栲',
  '' => '栳',
  '' => '栻',
  '' => '桋',
  '' => '桏',
  '' => '栖',
  '' => '栱',
  '' => '栜',
  '' => '栵',
  '' => '栫',
  '' => '栭',
  '' => '栯',
  '' => '桎',
  '' => '桄',
  '' => '栴',
  '' => '栝',
  '' => '栒',
  '' => '栔',
  '' => '栦',
  '' => '栨',
  '' => '栮',
  '' => '桍',
  '' => '栺',
  '' => '栥',
  '' => '栠',
  '' => '欬',
  '' => '欯',
  '' => '欭',
  '' => '欱',
  '' => '欴',
  '' => '歭',
  '' => '肂',
  '' => '殈',
  '' => '毦',
  '' => '毤',
  '@' => '毨',
  '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' => '傝',
  '[' => '偨',
  '\\' => '傜',
  ']' => '傒',
  '^' => '傂',
  '_' => '傇',
  '`' => '兟',
  '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' => '煋',
  '{' => '煰',
  '|' => '煟',
  '}' => '煐',
  '~' => '煓',
  'ޡ' => '煄',
  'ޢ' => '煍',
  'ޣ' => '煚',
  'ޤ' => '牏',
  'ޥ' => '犍',
  'ަ' => '犌',
  'ާ' => '犑',
  'ި' => '犐',
  'ީ' => '犎',
  'ު' => '猼',
  'ޫ' => '獂',
  'ެ' => '猻',
  'ޭ' => '猺',
  'ޮ' => '獀',
  'ޯ' => '獊',
  'ް' => '獉',
  'ޱ' => '瑄',
  '޲' => '瑊',
  '޳' => '瑋',
  '޴' => '瑒',
  '޵' => '瑑',
  '޶' => '瑗',
  '޷' => '瑀',
  '޸' => '瑏',
  '޹' => '瑐',
  '޺' => '瑎',
  '޻' => '瑂',
  '޼' => '瑆',
  '޽' => '瑍',
  '޾' => '瑔',
  '޿' => '瓡',
  '' => '瓿',
  '' => '瓾',
  '' => '瓽',
  '' => '甝',
  '' => '畹',
  '' => '畷',
  '' => '榃',
  '' => '痯',
  '' => '瘏',
  '' => '瘃',
  '' => '痷',
  '' => '痾',
  '' => '痼',
  '' => '痹',
  '' => '痸',
  '' => '瘐',
  '' => '痻',
  '' => '痶',
  '' => '痭',
  '' => '痵',
  '' => '痽',
  '' => '皙',
  '' => '皵',
  '' => '盝',
  '' => '睕',
  '' => '睟',
  '' => '睠',
  '' => '睒',
  '' => '睖',
  '' => '睚',
  '' => '睩',
  '' => '睧',
  '' => '睔',
  '' => '睙',
  '' => '睭',
  '' => '矠',
  '' => '碇',
  '' => '碚',
  '' => '碔',
  '' => '碏',
  '' => '碄',
  '' => '碕',
  '' => '碅',
  '' => '碆',
  '' => '碡',
  '' => '碃',
  '' => '硹',
  '' => '碙',
  '' => '碀',
  '' => '碖',
  '' => '硻',
  '' => '祼',
  '' => '禂',
  '' => '祽',
  '' => '祹',
  '' => '稑',
  '' => '稘',
  '' => '稙',
  '' => '稒',
  '' => '稗',
  '' => '稕',
  '' => '稢',
  '' => '稓',
  '@' => '稛',
  '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' => '嫸',
  '[' => '嬂',
  '\\' => '嫹',
  ']' => '嬁',
  '^' => '嬇',
  '_' => '嬅',
  '`' => '嬏',
  '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' => '褯',
  '{' => '褬',
  '|' => '褟',
  '}' => '觱',
  '~' => '諠',
  '' => '諢',
  '' => '諲',
  '' => '諴',
  '' => '諵',
  '' => '諝',
  '' => '謔',
  '' => '諤',
  '' => '諟',
  '' => '諰',
  '' => '諈',
  '' => '諞',
  '' => '諡',
  '' => '諨',
  '' => '諿',
  '' => '諯',
  '' => '諻',
  '' => '貑',
  '' => '貒',
  '' => '貐',
  '' => '賵',
  '' => '賮',
  '' => '賱',
  '' => '賰',
  '' => '賳',
  '' => '赬',
  '' => '赮',
  '' => '趥',
  '' => '趧',
  '' => '踳',
  '' => '踾',
  '' => '踸',
  '' => '蹀',
  '' => '蹅',
  '' => '踶',
  '' => '踼',
  '' => '踽',
  '' => '蹁',
  '' => '踰',
  '' => '踿',
  '' => '躽',
  '' => '輶',
  '' => '輮',
  '' => '輵',
  '' => '輲',
  '' => '輹',
  '' => '輷',
  '' => '輴',
  '' => '遶',
  '' => '遹',
  '' => '遻',
  '' => '邆',
  '' => '郺',
  '' => '鄳',
  '' => '鄵',
  '' => '鄶',
  '' => '醓',
  '' => '醐',
  '' => '醑',
  '' => '醍',
  '' => '醏',
  '' => '錧',
  '' => '錞',
  '' => '錈',
  '' => '錟',
  '' => '錆',
  '' => '錏',
  '' => '鍺',
  '' => '錸',
  '' => '錼',
  '' => '錛',
  '' => '錣',
  '' => '錒',
  '' => '錁',
  '' => '鍆',
  '' => '錭',
  '' => '錎',
  '' => '錍',
  '' => '鋋',
  '' => '錝',
  '' => '鋺',
  '' => '錥',
  '' => '錓',
  '' => '鋹',
  '' => '鋷',
  '' => '錴',
  '' => '錂',
  '' => '錤',
  '' => '鋿',
  '' => '錩',
  '' => '錹',
  '' => '錵',
  '' => '錪',
  '' => '錔',
  '' => '錌',
  '@' => '錋',
  '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' => '殰',
  '[' => '氌',
  '\\' => '瀙',
  ']' => '瀧',
  '^' => '瀠',
  '_' => '瀖',
  '`' => '瀫',
  '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' => '鼸',
  '{' => '鼷',
  '|' => '鼶',
  '}' => '齃',
  '~' => '齏',
  '' => '齱',
  '' => '齰',
  '' => '齮',
  '' => '齯',
  '' => '囓',
  '' => '囍',
  '' => '孎',
  '' => '屭',
  '' => '攭',
  '' => '曭',
  '' => '曮',
  '' => '欓',
  '' => '灟',
  '' => '灡',
  '' => '灝',
  '' => '灠',
  '' => '爣',
  '' => '瓛',
  '' => '瓥',
  '' => '矕',
  '' => '礸',
  '' => '禷',
  '' => '禶',
  '' => '籪',
  '' => '纗',
  '' => '羉',
  '' => '艭',
  '' => '虃',
  '' => '蠸',
  '' => '蠷',
  '' => '蠵',
  '' => '衋',
  '' => '讔',
  '' => '讕',
  '' => '躞',
  '' => '躟',
  '' => '躠',
  '' => '躝',
  '' => '醾',
  '' => '醽',
  '' => '釂',
  '' => '鑫',
  '' => '鑨',
  '' => '鑩',
  '' => '雥',
  '' => '靆',
  '' => '靃',
  '' => '靇',
  '' => '韇',
  '' => '韥',
  '' => '驞',
  '' => '髕',
  '' => '魙',
  '' => '鱣',
  '' => '鱧',
  '' => '鱦',
  '' => '鱢',
  '' => '鱞',
  '' => '鱠',
  '' => '鸂',
  '' => '鷾',
  '' => '鸇',
  '' => '鸃',
  '' => '鸆',
  '' => '鸅',
  '' => '鸀',
  '' => '鸁',
  '' => '鸉',
  '' => '鷿',
  '' => '鷽',
  '' => '鸄',
  '' => '麠',
  '' => '鼞',
  '' => '齆',
  '' => '齴',
  '' => '齵',
  '' => '齶',
  '' => '囔',
  '' => '攮',
  '' => '斸',
  '' => '欘',
  '' => '欙',
  '' => '欗',
  '' => '欚',
  '' => '灢',
  '' => '爦',
  '' => '犪',
  '' => '矘',
  '' => '矙',
  '' => '礹',
  '' => '籩',
  '' => '籫',
  '' => '糶',
  '' => '纚',
  '@' => '纘',
  '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' => '鱵',
  '{' => '鸔',
  '|' => '鸓',
  '}' => '黶',
  '~' => '鼊',
  '' => '龤',
  '' => '灨',
  '' => '灥',
  '' => '糷',
  '' => '虪',
  '' => '蠾',
  '' => '蠽',
  '' => '蠿',
  '' => '讞',
  '' => '貜',
  '' => '躩',
  '' => '軉',
  '' => '靋',
  '' => '顳',
  '' => '顴',
  '' => '飌',
  '' => '饡',
  '' => '馫',
  '' => '驤',
  '' => '驦',
  '' => '驧',
  '' => '鬤',
  '' => '鸕',
  '' => '鸗',
  '' => '齈',
  '' => '戇',
  '' => '欞',
  '' => '爧',
  '' => '虌',
  '' => '躨',
  '' => '钂',
  '' => '钀',
  '' => '钁',
  '' => '驩',
  '' => '驨',
  '' => '鬮',
  '' => '鸙',
  '' => '爩',
  '' => '虋',
  '' => '讟',
  '' => '钃',
  '' => '鱹',
  '' => '麷',
  '' => '癵',
  '' => '驫',
  '' => '鱺',
  '' => '鸝',
  '' => '灩',
  '' => '灪',
  '' => '麤',
  '' => '齾',
  '' => '齉',
  '' => '龘',
  '' => '碁',
  '' => '銹',
  '' => '裏',
  '' => '墻',
  '' => '恒',
  '' => '粧',
  '' => '嫺',
  '' => '╔',
  '' => '╦',
  '' => '╗',
  '' => '╠',
  '' => '╬',
  '' => '╣',
  '' => '╚',
  '' => '╩',
  '' => '╝',
  '' => '╒',
  '' => '╤',
  '' => '╕',
  '' => '╞',
  '' => '╪',
  '' => '╡',
  '' => '╘',
  '' => '╧',
  '' => '╛',
  '' => '╓',
  '' => '╥',
  '' => '╖',
  '' => '╟',
  '' => '╫',
  '' => '╢',
  '' => '╙',
  '' => '╨',
  '' => '╜',
  '' => '║',
  '' => '═',
  '' => '╭',
  '' => '╮',
  '' => '╰',
  '' => '╯',
  '' => '▓',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ð',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Þ',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ð',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ý',
  '' => 'þ',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ą',
  '' => 'Ē',
  '' => 'Ģ',
  '' => 'Ī',
  '' => 'Ĩ',
  '' => 'Ķ',
  '' => '§',
  '' => 'Ļ',
  '' => 'Đ',
  '' => 'Š',
  '' => 'Ŧ',
  '' => 'Ž',
  '' => '­',
  '' => 'Ū',
  '' => 'Ŋ',
  '' => '°',
  '' => 'ą',
  '' => 'ē',
  '' => 'ģ',
  '' => 'ī',
  '' => 'ĩ',
  '' => 'ķ',
  '' => '·',
  '' => 'ļ',
  '' => 'đ',
  '' => 'š',
  '' => 'ŧ',
  '' => 'ž',
  '' => '―',
  '' => 'ū',
  '' => 'ŋ',
  '' => 'Ā',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Į',
  '' => 'Č',
  '' => 'É',
  '' => 'Ę',
  '' => 'Ë',
  '' => 'Ė',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ð',
  '' => 'Ņ',
  '' => 'Ō',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => 'Ũ',
  '' => 'Ø',
  '' => 'Ų',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Þ',
  '' => 'ß',
  '' => 'ā',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'į',
  '' => 'č',
  '' => 'é',
  '' => 'ę',
  '' => 'ë',
  '' => 'ė',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ð',
  '' => 'ņ',
  '' => 'ō',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => 'ũ',
  '' => 'ø',
  '' => 'ų',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ý',
  '' => 'þ',
  '' => 'ĸ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'ก',
  '' => 'ข',
  '' => 'ฃ',
  '' => 'ค',
  '' => 'ฅ',
  '' => 'ฆ',
  '' => 'ง',
  '' => 'จ',
  '' => 'ฉ',
  '' => 'ช',
  '' => 'ซ',
  '' => 'ฌ',
  '' => 'ญ',
  '' => 'ฎ',
  '' => 'ฏ',
  '' => 'ฐ',
  '' => 'ฑ',
  '' => 'ฒ',
  '' => 'ณ',
  '' => 'ด',
  '' => 'ต',
  '' => 'ถ',
  '' => 'ท',
  '' => 'ธ',
  '' => 'น',
  '' => 'บ',
  '' => 'ป',
  '' => 'ผ',
  '' => 'ฝ',
  '' => 'พ',
  '' => 'ฟ',
  '' => 'ภ',
  '' => 'ม',
  '' => 'ย',
  '' => 'ร',
  '' => 'ฤ',
  '' => 'ล',
  '' => 'ฦ',
  '' => 'ว',
  '' => 'ศ',
  '' => 'ษ',
  '' => 'ส',
  '' => 'ห',
  '' => 'ฬ',
  '' => 'อ',
  '' => 'ฮ',
  '' => 'ฯ',
  '' => 'ะ',
  '' => 'ั',
  '' => 'า',
  '' => 'ำ',
  '' => 'ิ',
  '' => 'ี',
  '' => 'ึ',
  '' => 'ื',
  '' => 'ุ',
  '' => 'ู',
  '' => 'ฺ',
  '' => '฿',
  '' => 'เ',
  '' => 'แ',
  '' => 'โ',
  '' => 'ใ',
  '' => 'ไ',
  '' => 'ๅ',
  '' => 'ๆ',
  '' => '็',
  '' => '่',
  '' => '้',
  '' => '๊',
  '' => '๋',
  '' => '์',
  '' => 'ํ',
  '' => '๎',
  '' => '๏',
  '' => '๐',
  '' => '๑',
  '' => '๒',
  '' => '๓',
  '' => '๔',
  '' => '๕',
  '' => '๖',
  '' => '๗',
  '' => '๘',
  '' => '๙',
  '' => '๚',
  '' => '๛',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '”',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '„',
  '' => '¦',
  '' => '§',
  '' => 'Ø',
  '' => '©',
  '' => 'Ŗ',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => 'Æ',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '“',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => 'ø',
  '' => '¹',
  '' => 'ŗ',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => 'æ',
  '' => 'Ą',
  '' => 'Į',
  '' => 'Ā',
  '' => 'Ć',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Ę',
  '' => 'Ē',
  '' => 'Č',
  '' => 'É',
  '' => 'Ź',
  '' => 'Ė',
  '' => 'Ģ',
  '' => 'Ķ',
  '' => 'Ī',
  '' => 'Ļ',
  '' => 'Š',
  '' => 'Ń',
  '' => 'Ņ',
  '' => 'Ó',
  '' => 'Ō',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ų',
  '' => 'Ł',
  '' => 'Ś',
  '' => 'Ū',
  '' => 'Ü',
  '' => 'Ż',
  '' => 'Ž',
  '' => 'ß',
  '' => 'ą',
  '' => 'į',
  '' => 'ā',
  '' => 'ć',
  '' => 'ä',
  '' => 'å',
  '' => 'ę',
  '' => 'ē',
  '' => 'č',
  '' => 'é',
  '' => 'ź',
  '' => 'ė',
  '' => 'ģ',
  '' => 'ķ',
  '' => 'ī',
  '' => 'ļ',
  '' => 'š',
  '' => 'ń',
  '' => 'ņ',
  '' => 'ó',
  '' => 'ō',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ų',
  '' => 'ł',
  '' => 'ś',
  '' => 'ū',
  '' => 'ü',
  '' => 'ż',
  '' => 'ž',
  '' => '’',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ḃ',
  '' => 'ḃ',
  '' => '£',
  '' => 'Ċ',
  '' => 'ċ',
  '' => 'Ḋ',
  '' => '§',
  '' => 'Ẁ',
  '' => '©',
  '' => 'Ẃ',
  '' => 'ḋ',
  '' => 'Ỳ',
  '' => '­',
  '' => '®',
  '' => 'Ÿ',
  '' => 'Ḟ',
  '' => 'ḟ',
  '' => 'Ġ',
  '' => 'ġ',
  '' => 'Ṁ',
  '' => 'ṁ',
  '' => '¶',
  '' => 'Ṗ',
  '' => 'ẁ',
  '' => 'ṗ',
  '' => 'ẃ',
  '' => 'Ṡ',
  '' => 'ỳ',
  '' => 'Ẅ',
  '' => 'ẅ',
  '' => 'ṡ',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ŵ',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => 'Ṫ',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Ŷ',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ŵ',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => 'ṫ',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ý',
  '' => 'ŷ',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '€',
  '' => '¥',
  '' => 'Š',
  '' => '§',
  '' => 'š',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => 'Ž',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => 'ž',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => 'Œ',
  '' => 'œ',
  '' => 'Ÿ',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ð',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Þ',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ð',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ý',
  '' => 'þ',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ą',
  '' => 'ą',
  '' => 'Ł',
  '' => '€',
  '' => '„',
  '' => 'Š',
  '' => '§',
  '' => 'š',
  '' => '©',
  '' => 'Ș',
  '' => '«',
  '' => 'Ź',
  '' => '­',
  '' => 'ź',
  '' => 'Ż',
  '' => '°',
  '' => '±',
  '' => 'Č',
  '' => 'ł',
  '' => 'Ž',
  '' => '”',
  '' => '¶',
  '' => '·',
  '' => 'ž',
  '' => 'č',
  '' => 'ș',
  '' => '»',
  '' => 'Œ',
  '' => 'œ',
  '' => 'Ÿ',
  '' => 'ż',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ă',
  '' => 'Ä',
  '' => 'Ć',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Đ',
  '' => 'Ń',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Ő',
  '' => 'Ö',
  '' => 'Ś',
  '' => 'Ű',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ę',
  '' => 'Ț',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ă',
  '' => 'ä',
  '' => 'ć',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'đ',
  '' => 'ń',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'ő',
  '' => 'ö',
  '' => 'ś',
  '' => 'ű',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ę',
  '' => 'ț',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ą',
  '' => '˘',
  '' => 'Ł',
  '' => '¤',
  '' => 'Ľ',
  '' => 'Ś',
  '' => '§',
  '' => '¨',
  '' => 'Š',
  '' => 'Ş',
  '' => 'Ť',
  '' => 'Ź',
  '' => '­',
  '' => 'Ž',
  '' => 'Ż',
  '' => '°',
  '' => 'ą',
  '' => '˛',
  '' => 'ł',
  '' => '´',
  '' => 'ľ',
  '' => 'ś',
  '' => 'ˇ',
  '' => '¸',
  '' => 'š',
  '' => 'ş',
  '' => 'ť',
  '' => 'ź',
  '' => '˝',
  '' => 'ž',
  '' => 'ż',
  '' => 'Ŕ',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ă',
  '' => 'Ä',
  '' => 'Ĺ',
  '' => 'Ć',
  '' => 'Ç',
  '' => 'Č',
  '' => 'É',
  '' => 'Ę',
  '' => 'Ë',
  '' => 'Ě',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ď',
  '' => 'Đ',
  '' => 'Ń',
  '' => 'Ň',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Ő',
  '' => 'Ö',
  '' => '×',
  '' => 'Ř',
  '' => 'Ů',
  '' => 'Ú',
  '' => 'Ű',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Ţ',
  '' => 'ß',
  '' => 'ŕ',
  '' => 'á',
  '' => 'â',
  '' => 'ă',
  '' => 'ä',
  '' => 'ĺ',
  '' => 'ć',
  '' => 'ç',
  '' => 'č',
  '' => 'é',
  '' => 'ę',
  '' => 'ë',
  '' => 'ě',
  '' => 'í',
  '' => 'î',
  '' => 'ď',
  '' => 'đ',
  '' => 'ń',
  '' => 'ň',
  '' => 'ó',
  '' => 'ô',
  '' => 'ő',
  '' => 'ö',
  '' => '÷',
  '' => 'ř',
  '' => 'ů',
  '' => 'ú',
  '' => 'ű',
  '' => 'ü',
  '' => 'ý',
  '' => 'ţ',
  '' => '˙',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ħ',
  '' => '˘',
  '' => '£',
  '' => '¤',
  '' => 'Ĥ',
  '' => '§',
  '' => '¨',
  '' => 'İ',
  '' => 'Ş',
  '' => 'Ğ',
  '' => 'Ĵ',
  '' => '­',
  '' => 'Ż',
  '' => '°',
  '' => 'ħ',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => 'ĥ',
  '' => '·',
  '' => '¸',
  '' => 'ı',
  '' => 'ş',
  '' => 'ğ',
  '' => 'ĵ',
  '' => '½',
  '' => 'ż',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ä',
  '' => 'Ċ',
  '' => 'Ĉ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Ġ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ĝ',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ŭ',
  '' => 'Ŝ',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ä',
  '' => 'ċ',
  '' => 'ĉ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'ġ',
  '' => 'ö',
  '' => '÷',
  '' => 'ĝ',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ŭ',
  '' => 'ŝ',
  '' => '˙',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ą',
  '' => 'ĸ',
  '' => 'Ŗ',
  '' => '¤',
  '' => 'Ĩ',
  '' => 'Ļ',
  '' => '§',
  '' => '¨',
  '' => 'Š',
  '' => 'Ē',
  '' => 'Ģ',
  '' => 'Ŧ',
  '' => '­',
  '' => 'Ž',
  '' => '¯',
  '' => '°',
  '' => 'ą',
  '' => '˛',
  '' => 'ŗ',
  '' => '´',
  '' => 'ĩ',
  '' => 'ļ',
  '' => 'ˇ',
  '' => '¸',
  '' => 'š',
  '' => 'ē',
  '' => 'ģ',
  '' => 'ŧ',
  '' => 'Ŋ',
  '' => 'ž',
  '' => 'ŋ',
  '' => 'Ā',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Į',
  '' => 'Č',
  '' => 'É',
  '' => 'Ę',
  '' => 'Ë',
  '' => 'Ė',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ī',
  '' => 'Đ',
  '' => 'Ņ',
  '' => 'Ō',
  '' => 'Ķ',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ų',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ũ',
  '' => 'Ū',
  '' => 'ß',
  '' => 'ā',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'į',
  '' => 'č',
  '' => 'é',
  '' => 'ę',
  '' => 'ë',
  '' => 'ė',
  '' => 'í',
  '' => 'î',
  '' => 'ī',
  '' => 'đ',
  '' => 'ņ',
  '' => 'ō',
  '' => 'ķ',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ų',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ũ',
  '' => 'ū',
  '' => '˙',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => 'Ё',
  '' => 'Ђ',
  '' => 'Ѓ',
  '' => 'Є',
  '' => 'Ѕ',
  '' => 'І',
  '' => 'Ї',
  '' => 'Ј',
  '' => 'Љ',
  '' => 'Њ',
  '' => 'Ћ',
  '' => 'Ќ',
  '' => '­',
  '' => 'Ў',
  '' => 'Џ',
  '' => 'А',
  '' => 'Б',
  '' => 'В',
  '' => 'Г',
  '' => 'Д',
  '' => 'Е',
  '' => 'Ж',
  '' => 'З',
  '' => 'И',
  '' => 'Й',
  '' => 'К',
  '' => 'Л',
  '' => 'М',
  '' => 'Н',
  '' => 'О',
  '' => 'П',
  '' => 'Р',
  '' => 'С',
  '' => 'Т',
  '' => 'У',
  '' => 'Ф',
  '' => 'Х',
  '' => 'Ц',
  '' => 'Ч',
  '' => 'Ш',
  '' => 'Щ',
  '' => 'Ъ',
  '' => 'Ы',
  '' => 'Ь',
  '' => 'Э',
  '' => 'Ю',
  '' => 'Я',
  '' => 'а',
  '' => 'б',
  '' => 'в',
  '' => 'г',
  '' => 'д',
  '' => 'е',
  '' => 'ж',
  '' => 'з',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ф',
  '' => 'х',
  '' => 'ц',
  '' => 'ч',
  '' => 'ш',
  '' => 'щ',
  '' => 'ъ',
  '' => 'ы',
  '' => 'ь',
  '' => 'э',
  '' => 'ю',
  '' => 'я',
  '' => '№',
  '' => 'ё',
  '' => 'ђ',
  '' => 'ѓ',
  '' => 'є',
  '' => 'ѕ',
  '' => 'і',
  '' => 'ї',
  '' => 'ј',
  '' => 'љ',
  '' => 'њ',
  '' => 'ћ',
  '' => 'ќ',
  '' => '§',
  '' => 'ў',
  '' => 'џ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '¤',
  '' => '،',
  '' => '­',
  '' => '؛',
  '' => '؟',
  '' => 'ء',
  '' => 'آ',
  '' => 'أ',
  '' => 'ؤ',
  '' => 'إ',
  '' => 'ئ',
  '' => 'ا',
  '' => 'ب',
  '' => 'ة',
  '' => 'ت',
  '' => 'ث',
  '' => 'ج',
  '' => 'ح',
  '' => 'خ',
  '' => 'د',
  '' => 'ذ',
  '' => 'ر',
  '' => 'ز',
  '' => 'س',
  '' => 'ش',
  '' => 'ص',
  '' => 'ض',
  '' => 'ط',
  '' => 'ظ',
  '' => 'ع',
  '' => 'غ',
  '' => 'ـ',
  '' => 'ف',
  '' => 'ق',
  '' => 'ك',
  '' => 'ل',
  '' => 'م',
  '' => 'ن',
  '' => 'ه',
  '' => 'و',
  '' => 'ى',
  '' => 'ي',
  '' => 'ً',
  '' => 'ٌ',
  '' => 'ٍ',
  '' => 'َ',
  '' => 'ُ',
  '' => 'ِ',
  '' => 'ّ',
  '' => 'ْ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '‘',
  '' => '’',
  '' => '£',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '―',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '΄',
  '' => '΅',
  '' => 'Ά',
  '' => '·',
  '' => 'Έ',
  '' => 'Ή',
  '' => 'Ί',
  '' => '»',
  '' => 'Ό',
  '' => '½',
  '' => 'Ύ',
  '' => 'Ώ',
  '' => 'ΐ',
  '' => 'Α',
  '' => 'Β',
  '' => 'Γ',
  '' => 'Δ',
  '' => 'Ε',
  '' => 'Ζ',
  '' => 'Η',
  '' => 'Θ',
  '' => 'Ι',
  '' => 'Κ',
  '' => 'Λ',
  '' => 'Μ',
  '' => 'Ν',
  '' => 'Ξ',
  '' => 'Ο',
  '' => 'Π',
  '' => 'Ρ',
  '' => 'Σ',
  '' => 'Τ',
  '' => 'Υ',
  '' => 'Φ',
  '' => 'Χ',
  '' => 'Ψ',
  '' => 'Ω',
  '' => 'Ϊ',
  '' => 'Ϋ',
  '' => 'ά',
  '' => 'έ',
  '' => 'ή',
  '' => 'ί',
  '' => 'ΰ',
  '' => 'α',
  '' => 'β',
  '' => 'γ',
  '' => 'δ',
  '' => 'ε',
  '' => 'ζ',
  '' => 'η',
  '' => 'θ',
  '' => 'ι',
  '' => 'κ',
  '' => 'λ',
  '' => 'μ',
  '' => 'ν',
  '' => 'ξ',
  '' => 'ο',
  '' => 'π',
  '' => 'ρ',
  '' => 'ς',
  '' => 'σ',
  '' => 'τ',
  '' => 'υ',
  '' => 'φ',
  '' => 'χ',
  '' => 'ψ',
  '' => 'ω',
  '' => 'ϊ',
  '' => 'ϋ',
  '' => 'ό',
  '' => 'ύ',
  '' => 'ώ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => '×',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => '÷',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '‗',
  '' => 'א',
  '' => 'ב',
  '' => 'ג',
  '' => 'ד',
  '' => 'ה',
  '' => 'ו',
  '' => 'ז',
  '' => 'ח',
  '' => 'ט',
  '' => 'י',
  '' => 'ך',
  '' => 'כ',
  '' => 'ל',
  '' => 'ם',
  '' => 'מ',
  '' => 'ן',
  '' => 'נ',
  '' => 'ס',
  '' => 'ע',
  '' => 'ף',
  '' => 'פ',
  '' => 'ץ',
  '' => 'צ',
  '' => 'ק',
  '' => 'ר',
  '' => 'ש',
  '' => 'ת',
  '' => '‎',
  '' => '‏',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ğ',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'İ',
  '' => 'Ş',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ğ',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ı',
  '' => 'ş',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '─',
  '' => '│',
  '' => '┌',
  '' => '┐',
  '' => '└',
  '' => '┘',
  '' => '├',
  '' => '┤',
  '' => '┬',
  '' => '┴',
  '' => '┼',
  '' => '▀',
  '' => '▄',
  '' => '█',
  '' => '▌',
  '' => '▐',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '⌠',
  '' => '■',
  '' => '∙',
  '' => '√',
  '' => '≈',
  '' => '≤',
  '' => '≥',
  '' => ' ',
  '' => '⌡',
  '' => '°',
  '' => '²',
  '' => '·',
  '' => '÷',
  '' => '═',
  '' => '║',
  '' => '╒',
  '' => 'ё',
  '' => '╓',
  '' => '╔',
  '' => '╕',
  '' => '╖',
  '' => '╗',
  '' => '╘',
  '' => '╙',
  '' => '╚',
  '' => '╛',
  '' => '╜',
  '' => '╝',
  '' => '╞',
  '' => '╟',
  '' => '╠',
  '' => '╡',
  '' => 'Ё',
  '' => '╢',
  '' => '╣',
  '' => '╤',
  '' => '╥',
  '' => '╦',
  '' => '╧',
  '' => '╨',
  '' => '╩',
  '' => '╪',
  '' => '╫',
  '' => '╬',
  '' => '©',
  '' => 'ю',
  '' => 'а',
  '' => 'б',
  '' => 'ц',
  '' => 'д',
  '' => 'е',
  '' => 'ф',
  '' => 'г',
  '' => 'х',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => 'я',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ж',
  '' => 'в',
  '' => 'ь',
  '' => 'ы',
  '' => 'з',
  '' => 'ш',
  '' => 'э',
  '' => 'щ',
  '' => 'ч',
  '' => 'ъ',
  '' => 'Ю',
  '' => 'А',
  '' => 'Б',
  '' => 'Ц',
  '' => 'Д',
  '' => 'Е',
  '' => 'Ф',
  '' => 'Г',
  '' => 'Х',
  '' => 'И',
  '' => 'Й',
  '' => 'К',
  '' => 'Л',
  '' => 'М',
  '' => 'Н',
  '' => 'О',
  '' => 'П',
  '' => 'Я',
  '' => 'Р',
  '' => 'С',
  '' => 'Т',
  '' => 'У',
  '' => 'Ж',
  '' => 'В',
  '' => 'Ь',
  '' => 'Ы',
  '' => 'З',
  '' => 'Ш',
  '' => 'Э',
  '' => 'Щ',
  '' => 'Ч',
  '' => 'Ъ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '─',
  '' => '│',
  '' => '┌',
  '' => '┐',
  '' => '└',
  '' => '┘',
  '' => '├',
  '' => '┤',
  '' => '┬',
  '' => '┴',
  '' => '┼',
  '' => '▀',
  '' => '▄',
  '' => '█',
  '' => '▌',
  '' => '▐',
  '' => '░',
  '' => '▒',
  '' => '▓',
  '' => '⌠',
  '' => '■',
  '' => '•',
  '' => '√',
  '' => '≈',
  '' => '≤',
  '' => '≥',
  '' => ' ',
  '' => '⌡',
  '' => '°',
  '' => '²',
  '' => '·',
  '' => '÷',
  '' => '═',
  '' => '║',
  '' => '╒',
  '' => 'ё',
  '' => 'є',
  '' => '╔',
  '' => 'і',
  '' => 'ї',
  '' => '╗',
  '' => '╘',
  '' => '╙',
  '' => '╚',
  '' => '╛',
  '' => 'ґ',
  '' => '╝',
  '' => '╞',
  '' => '╟',
  '' => '╠',
  '' => '╡',
  '' => 'Ё',
  '' => 'Ѓ',
  '' => '╣',
  '' => 'І',
  '' => 'Ї',
  '' => '╦',
  '' => '╧',
  '' => '╨',
  '' => '╩',
  '' => '╪',
  '' => 'Ґ',
  '' => '╬',
  '' => '©',
  '' => 'ю',
  '' => 'а',
  '' => 'б',
  '' => 'ц',
  '' => 'д',
  '' => 'е',
  '' => 'ф',
  '' => 'г',
  '' => 'х',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => 'я',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ж',
  '' => 'в',
  '' => 'ь',
  '' => 'ы',
  '' => 'з',
  '' => 'ш',
  '' => 'э',
  '' => 'щ',
  '' => 'ч',
  '' => 'ъ',
  '' => 'Ю',
  '' => 'А',
  '' => 'Б',
  '' => 'Ц',
  '' => 'Д',
  '' => 'Е',
  '' => 'Ф',
  '' => 'Г',
  '' => 'Х',
  '' => 'И',
  '' => 'Й',
  '' => 'К',
  '' => 'Л',
  '' => 'М',
  '' => 'Н',
  '' => 'О',
  '' => 'П',
  '' => 'Я',
  '' => 'Р',
  '' => 'С',
  '' => 'Т',
  '' => 'У',
  '' => 'Ж',
  '' => 'В',
  '' => 'Ь',
  '' => 'Ы',
  '' => 'З',
  '' => 'Ш',
  '' => 'Э',
  '' => 'Щ',
  '' => 'Ч',
  '' => 'Ъ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => '‰',
  '' => 'Š',
  '' => '‹',
  '' => 'Ś',
  '' => 'Ť',
  '' => 'Ž',
  '' => 'Ź',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '™',
  '' => 'š',
  '' => '›',
  '' => 'ś',
  '' => 'ť',
  '' => 'ž',
  '' => 'ź',
  '' => ' ',
  '' => 'ˇ',
  '' => '˘',
  '' => 'Ł',
  '' => '¤',
  '' => 'Ą',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'Ş',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => 'Ż',
  '' => '°',
  '' => '±',
  '' => '˛',
  '' => 'ł',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => 'ą',
  '' => 'ş',
  '' => '»',
  '' => 'Ľ',
  '' => '˝',
  '' => 'ľ',
  '' => 'ż',
  '' => 'Ŕ',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ă',
  '' => 'Ä',
  '' => 'Ĺ',
  '' => 'Ć',
  '' => 'Ç',
  '' => 'Č',
  '' => 'É',
  '' => 'Ę',
  '' => 'Ë',
  '' => 'Ě',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ď',
  '' => 'Đ',
  '' => 'Ń',
  '' => 'Ň',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Ő',
  '' => 'Ö',
  '' => '×',
  '' => 'Ř',
  '' => 'Ů',
  '' => 'Ú',
  '' => 'Ű',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Ţ',
  '' => 'ß',
  '' => 'ŕ',
  '' => 'á',
  '' => 'â',
  '' => 'ă',
  '' => 'ä',
  '' => 'ĺ',
  '' => 'ć',
  '' => 'ç',
  '' => 'č',
  '' => 'é',
  '' => 'ę',
  '' => 'ë',
  '' => 'ě',
  '' => 'í',
  '' => 'î',
  '' => 'ď',
  '' => 'đ',
  '' => 'ń',
  '' => 'ň',
  '' => 'ó',
  '' => 'ô',
  '' => 'ő',
  '' => 'ö',
  '' => '÷',
  '' => 'ř',
  '' => 'ů',
  '' => 'ú',
  '' => 'ű',
  '' => 'ü',
  '' => 'ý',
  '' => 'ţ',
  '' => '˙',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => 'Ђ',
  '' => 'Ѓ',
  '' => '‚',
  '' => 'ѓ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => '€',
  '' => '‰',
  '' => 'Љ',
  '' => '‹',
  '' => 'Њ',
  '' => 'Ќ',
  '' => 'Ћ',
  '' => 'Џ',
  '' => 'ђ',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '™',
  '' => 'љ',
  '' => '›',
  '' => 'њ',
  '' => 'ќ',
  '' => 'ћ',
  '' => 'џ',
  '' => ' ',
  '' => 'Ў',
  '' => 'ў',
  '' => 'Ј',
  '' => '¤',
  '' => 'Ґ',
  '' => '¦',
  '' => '§',
  '' => 'Ё',
  '' => '©',
  '' => 'Є',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => 'Ї',
  '' => '°',
  '' => '±',
  '' => 'І',
  '' => 'і',
  '' => 'ґ',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => 'ё',
  '' => '№',
  '' => 'є',
  '' => '»',
  '' => 'ј',
  '' => 'Ѕ',
  '' => 'ѕ',
  '' => 'ї',
  '' => 'А',
  '' => 'Б',
  '' => 'В',
  '' => 'Г',
  '' => 'Д',
  '' => 'Е',
  '' => 'Ж',
  '' => 'З',
  '' => 'И',
  '' => 'Й',
  '' => 'К',
  '' => 'Л',
  '' => 'М',
  '' => 'Н',
  '' => 'О',
  '' => 'П',
  '' => 'Р',
  '' => 'С',
  '' => 'Т',
  '' => 'У',
  '' => 'Ф',
  '' => 'Х',
  '' => 'Ц',
  '' => 'Ч',
  '' => 'Ш',
  '' => 'Щ',
  '' => 'Ъ',
  '' => 'Ы',
  '' => 'Ь',
  '' => 'Э',
  '' => 'Ю',
  '' => 'Я',
  '' => 'а',
  '' => 'б',
  '' => 'в',
  '' => 'г',
  '' => 'д',
  '' => 'е',
  '' => 'ж',
  '' => 'з',
  '' => 'и',
  '' => 'й',
  '' => 'к',
  '' => 'л',
  '' => 'м',
  '' => 'н',
  '' => 'о',
  '' => 'п',
  '' => 'р',
  '' => 'с',
  '' => 'т',
  '' => 'у',
  '' => 'ф',
  '' => 'х',
  '' => 'ц',
  '' => 'ч',
  '' => 'ш',
  '' => 'щ',
  '' => 'ъ',
  '' => 'ы',
  '' => 'ь',
  '' => 'э',
  '' => 'ю',
  '' => 'я',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => 'ˆ',
  '' => '‰',
  '' => 'Š',
  '' => '‹',
  '' => 'Œ',
  '' => 'Ž',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '˜',
  '' => '™',
  '' => 'š',
  '' => '›',
  '' => 'œ',
  '' => 'ž',
  '' => 'Ÿ',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ð',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ý',
  '' => 'Þ',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ð',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ý',
  '' => 'þ',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => '‰',
  '' => '‹',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '™',
  '' => '›',
  '' => ' ',
  '' => '΅',
  '' => 'Ά',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '―',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '΄',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => 'Έ',
  '' => 'Ή',
  '' => 'Ί',
  '' => '»',
  '' => 'Ό',
  '' => '½',
  '' => 'Ύ',
  '' => 'Ώ',
  '' => 'ΐ',
  '' => 'Α',
  '' => 'Β',
  '' => 'Γ',
  '' => 'Δ',
  '' => 'Ε',
  '' => 'Ζ',
  '' => 'Η',
  '' => 'Θ',
  '' => 'Ι',
  '' => 'Κ',
  '' => 'Λ',
  '' => 'Μ',
  '' => 'Ν',
  '' => 'Ξ',
  '' => 'Ο',
  '' => 'Π',
  '' => 'Ρ',
  '' => 'Σ',
  '' => 'Τ',
  '' => 'Υ',
  '' => 'Φ',
  '' => 'Χ',
  '' => 'Ψ',
  '' => 'Ω',
  '' => 'Ϊ',
  '' => 'Ϋ',
  '' => 'ά',
  '' => 'έ',
  '' => 'ή',
  '' => 'ί',
  '' => 'ΰ',
  '' => 'α',
  '' => 'β',
  '' => 'γ',
  '' => 'δ',
  '' => 'ε',
  '' => 'ζ',
  '' => 'η',
  '' => 'θ',
  '' => 'ι',
  '' => 'κ',
  '' => 'λ',
  '' => 'μ',
  '' => 'ν',
  '' => 'ξ',
  '' => 'ο',
  '' => 'π',
  '' => 'ρ',
  '' => 'ς',
  '' => 'σ',
  '' => 'τ',
  '' => 'υ',
  '' => 'φ',
  '' => 'χ',
  '' => 'ψ',
  '' => 'ω',
  '' => 'ϊ',
  '' => 'ϋ',
  '' => 'ό',
  '' => 'ύ',
  '' => 'ώ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => 'ˆ',
  '' => '‰',
  '' => 'Š',
  '' => '‹',
  '' => 'Œ',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '˜',
  '' => '™',
  '' => 'š',
  '' => '›',
  '' => 'œ',
  '' => 'Ÿ',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ã',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => 'Ì',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Ğ',
  '' => 'Ñ',
  '' => 'Ò',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'İ',
  '' => 'Ş',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ã',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ì',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'ğ',
  '' => 'ñ',
  '' => 'ò',
  '' => 'ó',
  '' => 'ô',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ı',
  '' => 'ş',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => 'ˆ',
  '' => '‰',
  '' => '‹',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '˜',
  '' => '™',
  '' => '›',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '₪',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => '×',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => '÷',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'ְ',
  '' => 'ֱ',
  '' => 'ֲ',
  '' => 'ֳ',
  '' => 'ִ',
  '' => 'ֵ',
  '' => 'ֶ',
  '' => 'ַ',
  '' => 'ָ',
  '' => 'ֹ',
  '' => 'ֻ',
  '' => 'ּ',
  '' => 'ֽ',
  '' => '־',
  '' => 'ֿ',
  '' => '׀',
  '' => 'ׁ',
  '' => 'ׂ',
  '' => '׃',
  '' => 'װ',
  '' => 'ױ',
  '' => 'ײ',
  '' => '׳',
  '' => '״',
  '' => 'א',
  '' => 'ב',
  '' => 'ג',
  '' => 'ד',
  '' => 'ה',
  '' => 'ו',
  '' => 'ז',
  '' => 'ח',
  '' => 'ט',
  '' => 'י',
  '' => 'ך',
  '' => 'כ',
  '' => 'ל',
  '' => 'ם',
  '' => 'מ',
  '' => 'ן',
  '' => 'נ',
  '' => 'ס',
  '' => 'ע',
  '' => 'ף',
  '' => 'פ',
  '' => 'ץ',
  '' => 'צ',
  '' => 'ק',
  '' => 'ר',
  '' => 'ש',
  '' => 'ת',
  '' => '‎',
  '' => '‏',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => 'پ',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => 'ˆ',
  '' => '‰',
  '' => 'ٹ',
  '' => '‹',
  '' => 'Œ',
  '' => 'چ',
  '' => 'ژ',
  '' => 'ڈ',
  '' => 'گ',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => 'ک',
  '' => '™',
  '' => 'ڑ',
  '' => '›',
  '' => 'œ',
  '' => '‌',
  '' => '‍',
  '' => 'ں',
  '' => ' ',
  '' => '،',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ھ',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => '؛',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '؟',
  '' => 'ہ',
  '' => 'ء',
  '' => 'آ',
  '' => 'أ',
  '' => 'ؤ',
  '' => 'إ',
  '' => 'ئ',
  '' => 'ا',
  '' => 'ب',
  '' => 'ة',
  '' => 'ت',
  '' => 'ث',
  '' => 'ج',
  '' => 'ح',
  '' => 'خ',
  '' => 'د',
  '' => 'ذ',
  '' => 'ر',
  '' => 'ز',
  '' => 'س',
  '' => 'ش',
  '' => 'ص',
  '' => 'ض',
  '' => '×',
  '' => 'ط',
  '' => 'ظ',
  '' => 'ع',
  '' => 'غ',
  '' => 'ـ',
  '' => 'ف',
  '' => 'ق',
  '' => 'ك',
  '' => 'à',
  '' => 'ل',
  '' => 'â',
  '' => 'م',
  '' => 'ن',
  '' => 'ه',
  '' => 'و',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => 'ى',
  '' => 'ي',
  '' => 'î',
  '' => 'ï',
  '' => 'ً',
  '' => 'ٌ',
  '' => 'ٍ',
  '' => 'َ',
  '' => 'ô',
  '' => 'ُ',
  '' => 'ِ',
  '' => '÷',
  '' => 'ّ',
  '' => 'ù',
  '' => 'ْ',
  '' => 'û',
  '' => 'ü',
  '' => '‎',
  '' => '‏',
  '' => 'ے',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => '‰',
  '' => '‹',
  '' => '¨',
  '' => 'ˇ',
  '' => '¸',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '™',
  '' => '›',
  '' => '¯',
  '' => '˛',
  '' => ' ',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¦',
  '' => '§',
  '' => 'Ø',
  '' => '©',
  '' => 'Ŗ',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => 'Æ',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => 'ø',
  '' => '¹',
  '' => 'ŗ',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => 'æ',
  '' => 'Ą',
  '' => 'Į',
  '' => 'Ā',
  '' => 'Ć',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Ę',
  '' => 'Ē',
  '' => 'Č',
  '' => 'É',
  '' => 'Ź',
  '' => 'Ė',
  '' => 'Ģ',
  '' => 'Ķ',
  '' => 'Ī',
  '' => 'Ļ',
  '' => 'Š',
  '' => 'Ń',
  '' => 'Ņ',
  '' => 'Ó',
  '' => 'Ō',
  '' => 'Õ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ų',
  '' => 'Ł',
  '' => 'Ś',
  '' => 'Ū',
  '' => 'Ü',
  '' => 'Ż',
  '' => 'Ž',
  '' => 'ß',
  '' => 'ą',
  '' => 'į',
  '' => 'ā',
  '' => 'ć',
  '' => 'ä',
  '' => 'å',
  '' => 'ę',
  '' => 'ē',
  '' => 'č',
  '' => 'é',
  '' => 'ź',
  '' => 'ė',
  '' => 'ģ',
  '' => 'ķ',
  '' => 'ī',
  '' => 'ļ',
  '' => 'š',
  '' => 'ń',
  '' => 'ņ',
  '' => 'ó',
  '' => 'ō',
  '' => 'õ',
  '' => 'ö',
  '' => '÷',
  '' => 'ų',
  '' => 'ł',
  '' => 'ś',
  '' => 'ū',
  '' => 'ü',
  '' => 'ż',
  '' => 'ž',
  '' => '˙',
);

$result =& $data;
unset($data);

return $result;
<?php

static $data = array (
  ' ' => ' ',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '	' => '	',
  '
' => '
',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  '' => '',
  ' ' => ' ',
  '!' => '!',
  '"' => '"',
  '#' => '#',
  '$' => '$',
  '%' => '%',
  '&' => '&',
  '\'' => '\'',
  '(' => '(',
  ')' => ')',
  '*' => '*',
  '+' => '+',
  ',' => ',',
  '-' => '-',
  '.' => '.',
  '/' => '/',
  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',
  '{' => '{',
  '|' => '|',
  '}' => '}',
  '~' => '~',
  '' => '',
  '' => '€',
  '' => '‚',
  '' => 'ƒ',
  '' => '„',
  '' => '…',
  '' => '†',
  '' => '‡',
  '' => 'ˆ',
  '' => '‰',
  '' => '‹',
  '' => 'Œ',
  '' => '‘',
  '' => '’',
  '' => '“',
  '' => '”',
  '' => '•',
  '' => '–',
  '' => '—',
  '' => '˜',
  '' => '™',
  '' => '›',
  '' => 'œ',
  '' => 'Ÿ',
  '' => ' ',
  '' => '¡',
  '' => '¢',
  '' => '£',
  '' => '¤',
  '' => '¥',
  '' => '¦',
  '' => '§',
  '' => '¨',
  '' => '©',
  '' => 'ª',
  '' => '«',
  '' => '¬',
  '' => '­',
  '' => '®',
  '' => '¯',
  '' => '°',
  '' => '±',
  '' => '²',
  '' => '³',
  '' => '´',
  '' => 'µ',
  '' => '¶',
  '' => '·',
  '' => '¸',
  '' => '¹',
  '' => 'º',
  '' => '»',
  '' => '¼',
  '' => '½',
  '' => '¾',
  '' => '¿',
  '' => 'À',
  '' => 'Á',
  '' => 'Â',
  '' => 'Ă',
  '' => 'Ä',
  '' => 'Å',
  '' => 'Æ',
  '' => 'Ç',
  '' => 'È',
  '' => 'É',
  '' => 'Ê',
  '' => 'Ë',
  '' => '̀',
  '' => 'Í',
  '' => 'Î',
  '' => 'Ï',
  '' => 'Đ',
  '' => 'Ñ',
  '' => '̉',
  '' => 'Ó',
  '' => 'Ô',
  '' => 'Ơ',
  '' => 'Ö',
  '' => '×',
  '' => 'Ø',
  '' => 'Ù',
  '' => 'Ú',
  '' => 'Û',
  '' => 'Ü',
  '' => 'Ư',
  '' => '̃',
  '' => 'ß',
  '' => 'à',
  '' => 'á',
  '' => 'â',
  '' => 'ă',
  '' => 'ä',
  '' => 'å',
  '' => 'æ',
  '' => 'ç',
  '' => 'è',
  '' => 'é',
  '' => 'ê',
  '' => 'ë',
  '' => '́',
  '' => 'í',
  '' => 'î',
  '' => 'ï',
  '' => 'đ',
  '' => 'ñ',
  '' => '̣',
  '' => 'ó',
  '' => 'ô',
  '' => 'ơ',
  '' => 'ö',
  '' => '÷',
  '' => 'ø',
  '' => 'ù',
  '' => 'ú',
  '' => 'û',
  '' => 'ü',
  '' => 'ư',
  '' => '₫',
  '' => 'ÿ',
);

$result =& $data;
unset($data);

return $result;
<?php

return array (
  'µ' => 'μ',
  '¼' => ' 1⁄4 ',
  '½' => ' 1⁄2 ',
  '¾' => ' 3⁄4 ',
  'Ĳ' => 'IJ',
  'ĳ' => 'ij',
  'Ŀ' => 'L·',
  'ŀ' => 'l·',
  'ŉ' => 'ʼn',
  'ſ' => 's',
  'Ǆ' => 'DŽ',
  'ǅ' => 'Dž',
  'ǆ' => 'dž',
  'Ǉ' => 'LJ',
  'ǈ' => 'Lj',
  'ǉ' => 'lj',
  'Ǌ' => 'NJ',
  'ǋ' => 'Nj',
  'ǌ' => 'nj',
  'Ǳ' => 'DZ',
  'ǲ' => 'Dz',
  'ǳ' => 'dz',
  'ϐ' => 'β',
  'ϑ' => 'θ',
  'ϒ' => 'Υ',
  'ϕ' => 'φ',
  'ϖ' => 'π',
  'ϰ' => 'κ',
  'ϱ' => 'ρ',
  'ϲ' => 'ς',
  'ϴ' => 'Θ',
  'ϵ' => 'ε',
  'Ϲ' => 'Σ',
  'և' => 'եւ',
  'ٵ' => 'اٴ',
  'ٶ' => 'وٴ',
  'ٷ' => 'ۇٴ',
  'ٸ' => 'يٴ',
  'ำ' => 'ํา',
  'ຳ' => 'ໍາ',
  'ໜ' => 'ຫນ',
  'ໝ' => 'ຫມ',
  'ཷ' => 'ྲཱྀ',
  'ཹ' => 'ླཱྀ',
  'ẚ' => 'aʾ',
  '․' => '.',
  '‥' => '..',
  '…' => '...',
  '″' => '′′',
  '‴' => '′′′',
  '‶' => '‵‵',
  '‷' => '‵‵‵',
  '‼' => '!!',
  '⁇' => '??',
  '⁈' => '?!',
  '⁉' => '!?',
  '⁗' => '′′′′',
  '₨' => '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',
  '℡' => 'TEL',
  'ℤ' => '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)',
  '⨌' => '∫∫∫∫',
  '⩴' => '::=',
  '⩵' => '==',
  '⩶' => '===',
  '⺟' => '母',
  '⻳' => '龟',
  '⼀' => '一',
  '⼁' => '丨',
  '⼂' => '丶',
  '⼃' => '丿',
  '⼄' => '乙',
  '⼅' => '亅',
  '⼆' => '二',
  '⼇' => '亠',
  '⼈' => '人',
  '⼉' => '儿',
  '⼊' => '入',
  '⼋' => '八',
  '⼌' => '冂',
  '⼍' => '冖',
  '⼎' => '冫',
  '⼏' => '几',
  '⼐' => '凵',
  '⼑' => '刀',
  '⼒' => '力',
  '⼓' => '勹',
  '⼔' => '匕',
  '⼕' => '匚',
  '⼖' => '匸',
  '⼗' => '十',
  '⼘' => '卜',
  '⼙' => '卩',
  '⼚' => '厂',
  '⼛' => '厶',
  '⼜' => '又',
  '⼝' => '口',
  '⼞' => '囗',
  '⼟' => '土',
  '⼠' => '士',
  '⼡' => '夂',
  '⼢' => '夊',
  '⼣' => '夕',
  '⼤' => '大',
  '⼥' => '女',
  '⼦' => '子',
  '⼧' => '宀',
  '⼨' => '寸',
  '⼩' => '小',
  '⼪' => '尢',
  '⼫' => '尸',
  '⼬' => '屮',
  '⼭' => '山',
  '⼮' => '巛',
  '⼯' => '工',
  '⼰' => '己',
  '⼱' => '巾',
  '⼲' => '干',
  '⼳' => '幺',
  '⼴' => '广',
  '⼵' => '廴',
  '⼶' => '廾',
  '⼷' => '弋',
  '⼸' => '弓',
  '⼹' => '彐',
  '⼺' => '彡',
  '⼻' => '彳',
  '⼼' => '心',
  '⼽' => '戈',
  '⼾' => '戶',
  '⼿' => '手',
  '⽀' => '支',
  '⽁' => '攴',
  '⽂' => '文',
  '⽃' => '斗',
  '⽄' => '斤',
  '⽅' => '方',
  '⽆' => '无',
  '⽇' => '日',
  '⽈' => '曰',
  '⽉' => '月',
  '⽊' => '木',
  '⽋' => '欠',
  '⽌' => '止',
  '⽍' => '歹',
  '⽎' => '殳',
  '⽏' => '毋',
  '⽐' => '比',
  '⽑' => '毛',
  '⽒' => '氏',
  '⽓' => '气',
  '⽔' => '水',
  '⽕' => '火',
  '⽖' => '爪',
  '⽗' => '父',
  '⽘' => '爻',
  '⽙' => '爿',
  '⽚' => '片',
  '⽛' => '牙',
  '⽜' => '牛',
  '⽝' => '犬',
  '⽞' => '玄',
  '⽟' => '玉',
  '⽠' => '瓜',
  '⽡' => '瓦',
  '⽢' => '甘',
  '⽣' => '生',
  '⽤' => '用',
  '⽥' => '田',
  '⽦' => '疋',
  '⽧' => '疒',
  '⽨' => '癶',
  '⽩' => '白',
  '⽪' => '皮',
  '⽫' => '皿',
  '⽬' => '目',
  '⽭' => '矛',
  '⽮' => '矢',
  '⽯' => '石',
  '⽰' => '示',
  '⽱' => '禸',
  '⽲' => '禾',
  '⽳' => '穴',
  '⽴' => '立',
  '⽵' => '竹',
  '⽶' => '米',
  '⽷' => '糸',
  '⽸' => '缶',
  '⽹' => '网',
  '⽺' => '羊',
  '⽻' => '羽',
  '⽼' => '老',
  '⽽' => '而',
  '⽾' => '耒',
  '⽿' => '耳',
  '⾀' => '聿',
  '⾁' => '肉',
  '⾂' => '臣',
  '⾃' => '自',
  '⾄' => '至',
  '⾅' => '臼',
  '⾆' => '舌',
  '⾇' => '舛',
  '⾈' => '舟',
  '⾉' => '艮',
  '⾊' => '色',
  '⾋' => '艸',
  '⾌' => '虍',
  '⾍' => '虫',
  '⾎' => '血',
  '⾏' => '行',
  '⾐' => '衣',
  '⾑' => '襾',
  '⾒' => '見',
  '⾓' => '角',
  '⾔' => '言',
  '⾕' => '谷',
  '⾖' => '豆',
  '⾗' => '豕',
  '⾘' => '豸',
  '⾙' => '貝',
  '⾚' => '赤',
  '⾛' => '走',
  '⾜' => '足',
  '⾝' => '身',
  '⾞' => '車',
  '⾟' => '辛',
  '⾠' => '辰',
  '⾡' => '辵',
  '⾢' => '邑',
  '⾣' => '酉',
  '⾤' => '釆',
  '⾥' => '里',
  '⾦' => '金',
  '⾧' => '長',
  '⾨' => '門',
  '⾩' => '阜',
  '⾪' => '隶',
  '⾫' => '隹',
  '⾬' => '雨',
  '⾭' => '靑',
  '⾮' => '非',
  '⾯' => '面',
  '⾰' => '革',
  '⾱' => '韋',
  '⾲' => '韭',
  '⾳' => '音',
  '⾴' => '頁',
  '⾵' => '風',
  '⾶' => '飛',
  '⾷' => '食',
  '⾸' => '首',
  '⾹' => '香',
  '⾺' => '馬',
  '⾻' => '骨',
  '⾼' => '高',
  '⾽' => '髟',
  '⾾' => '鬥',
  '⾿' => '鬯',
  '⿀' => '鬲',
  '⿁' => '鬼',
  '⿂' => '魚',
  '⿃' => '鳥',
  '⿄' => '鹵',
  '⿅' => '鹿',
  '⿆' => '麥',
  '⿇' => '麻',
  '⿈' => '黃',
  '⿉' => '黍',
  '⿊' => '黑',
  '⿋' => '黹',
  '⿌' => '黽',
  '⿍' => '鼎',
  '⿎' => '鼓',
  '⿏' => '鼠',
  '⿐' => '鼻',
  '⿑' => '齊',
  '⿒' => '齒',
  '⿓' => '龍',
  '⿔' => '龜',
  '⿕' => '龠',
  '　' => ' ',
  '〶' => '〒',
  '〸' => '十',
  '〹' => '卄',
  '〺' => '卅',
  'ㄱ' => 'ᄀ',
  'ㄲ' => 'ᄁ',
  'ㄳ' => 'ᆪ',
  'ㄴ' => 'ᄂ',
  'ㄵ' => 'ᆬ',
  'ㄶ' => 'ᆭ',
  'ㄷ' => 'ᄃ',
  'ㄸ' => 'ᄄ',
  'ㄹ' => 'ᄅ',
  'ㄺ' => 'ᆰ',
  'ㄻ' => 'ᆱ',
  'ㄼ' => 'ᆲ',
  'ㄽ' => 'ᆳ',
  'ㄾ' => 'ᆴ',
  'ㄿ' => 'ᆵ',
  'ㅀ' => 'ᄚ',
  'ㅁ' => 'ᄆ',
  'ㅂ' => 'ᄇ',
  'ㅃ' => 'ᄈ',
  'ㅄ' => 'ᄡ',
  'ㅅ' => 'ᄉ',
  'ㅆ' => 'ᄊ',
  'ㅇ' => 'ᄋ',
  'ㅈ' => 'ᄌ',
  'ㅉ' => 'ᄍ',
  'ㅊ' => 'ᄎ',
  'ㅋ' => 'ᄏ',
  'ㅌ' => 'ᄐ',
  'ㅍ' => 'ᄑ',
  'ㅎ' => 'ᄒ',
  'ㅏ' => 'ᅡ',
  'ㅐ' => 'ᅢ',
  'ㅑ' => 'ᅣ',
  'ㅒ' => 'ᅤ',
  'ㅓ' => 'ᅥ',
  'ㅔ' => 'ᅦ',
  'ㅕ' => 'ᅧ',
  'ㅖ' => 'ᅨ',
  'ㅗ' => 'ᅩ',
  'ㅘ' => 'ᅪ',
  'ㅙ' => 'ᅫ',
  'ㅚ' => 'ᅬ',
  'ㅛ' => 'ᅭ',
  'ㅜ' => 'ᅮ',
  'ㅝ' => 'ᅯ',
  'ㅞ' => 'ᅰ',
  'ㅟ' => 'ᅱ',
  'ㅠ' => 'ᅲ',
  'ㅡ' => 'ᅳ',
  'ㅢ' => 'ᅴ',
  'ㅣ' => 'ᅵ',
  'ㅤ' => 'ᅠ',
  'ㅥ' => 'ᄔ',
  'ㅦ' => 'ᄕ',
  'ㅧ' => 'ᇇ',
  'ㅨ' => 'ᇈ',
  'ㅩ' => 'ᇌ',
  'ㅪ' => 'ᇎ',
  'ㅫ' => 'ᇓ',
  'ㅬ' => 'ᇗ',
  'ㅭ' => 'ᇙ',
  'ㅮ' => 'ᄜ',
  'ㅯ' => 'ᇝ',
  'ㅰ' => 'ᇟ',
  'ㅱ' => 'ᄝ',
  'ㅲ' => 'ᄞ',
  'ㅳ' => 'ᄠ',
  'ㅴ' => 'ᄢ',
  'ㅵ' => 'ᄣ',
  'ㅶ' => 'ᄧ',
  'ㅷ' => 'ᄩ',
  'ㅸ' => 'ᄫ',
  'ㅹ' => 'ᄬ',
  'ㅺ' => 'ᄭ',
  'ㅻ' => 'ᄮ',
  'ㅼ' => 'ᄯ',
  'ㅽ' => 'ᄲ',
  'ㅾ' => 'ᄶ',
  'ㅿ' => 'ᅀ',
  'ㆀ' => 'ᅇ',
  'ㆁ' => 'ᅌ',
  'ㆂ' => 'ᇱ',
  'ㆃ' => 'ᇲ',
  'ㆄ' => 'ᅗ',
  'ㆅ' => 'ᅘ',
  'ㆆ' => 'ᅙ',
  'ㆇ' => 'ᆄ',
  'ㆈ' => 'ᆅ',
  'ㆉ' => 'ᆈ',
  'ㆊ' => 'ᆑ',
  'ㆋ' => 'ᆒ',
  'ㆌ' => 'ᆔ',
  'ㆍ' => 'ᆞ',
  'ㆎ' => 'ᆡ',
  '㈀' => '(ᄀ)',
  '㈁' => '(ᄂ)',
  '㈂' => '(ᄃ)',
  '㈃' => '(ᄅ)',
  '㈄' => '(ᄆ)',
  '㈅' => '(ᄇ)',
  '㈆' => '(ᄉ)',
  '㈇' => '(ᄋ)',
  '㈈' => '(ᄌ)',
  '㈉' => '(ᄎ)',
  '㈊' => '(ᄏ)',
  '㈋' => '(ᄐ)',
  '㈌' => '(ᄑ)',
  '㈍' => '(ᄒ)',
  '㈎' => '(가)',
  '㈏' => '(나)',
  '㈐' => '(다)',
  '㈑' => '(라)',
  '㈒' => '(마)',
  '㈓' => '(바)',
  '㈔' => '(사)',
  '㈕' => '(아)',
  '㈖' => '(자)',
  '㈗' => '(차)',
  '㈘' => '(카)',
  '㈙' => '(타)',
  '㈚' => '(파)',
  '㈛' => '(하)',
  '㈜' => '(주)',
  '㈝' => '(오전)',
  '㈞' => '(오후)',
  '㈠' => '(一)',
  '㈡' => '(二)',
  '㈢' => '(三)',
  '㈣' => '(四)',
  '㈤' => '(五)',
  '㈥' => '(六)',
  '㈦' => '(七)',
  '㈧' => '(八)',
  '㈨' => '(九)',
  '㈩' => '(十)',
  '㈪' => '(月)',
  '㈫' => '(火)',
  '㈬' => '(水)',
  '㈭' => '(木)',
  '㈮' => '(金)',
  '㈯' => '(土)',
  '㈰' => '(日)',
  '㈱' => '(株)',
  '㈲' => '(有)',
  '㈳' => '(社)',
  '㈴' => '(名)',
  '㈵' => '(特)',
  '㈶' => '(財)',
  '㈷' => '(祝)',
  '㈸' => '(労)',
  '㈹' => '(代)',
  '㈺' => '(呼)',
  '㈻' => '(学)',
  '㈼' => '(監)',
  '㈽' => '(企)',
  '㈾' => '(資)',
  '㈿' => '(協)',
  '㉀' => '(祭)',
  '㉁' => '(休)',
  '㉂' => '(自)',
  '㉃' => '(至)',
  '㉄' => '(問)',
  '㉅' => '(幼)',
  '㉆' => '(文)',
  '㉇' => '(箏)',
  '㉐' => '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',
  '㍸' => 'dm²',
  '㍹' => 'dm³',
  '㍺' => 'IU',
  '㍻' => '平成',
  '㍼' => '昭和',
  '㍽' => '大正',
  '㍾' => '明治',
  '㍿' => '株式会社',
  '㎀' => 'pA',
  '㎁' => 'nA',
  '㎂' => 'μA',
  '㎃' => 'mA',
  '㎄' => 'kA',
  '㎅' => 'KB',
  '㎆' => 'MB',
  '㎇' => 'GB',
  '㎈' => 'cal',
  '㎉' => 'kcal',
  '㎊' => 'pF',
  '㎋' => 'nF',
  '㎌' => 'μF',
  '㎍' => 'μg',
  '㎎' => 'mg',
  '㎏' => 'kg',
  '㎐' => 'Hz',
  '㎑' => 'kHz',
  '㎒' => 'MHz',
  '㎓' => 'GHz',
  '㎔' => 'THz',
  '㎕' => 'μℓ',
  '㎖' => 'mℓ',
  '㎗' => 'dℓ',
  '㎘' => 'kℓ',
  '㎙' => 'fm',
  '㎚' => 'nm',
  '㎛' => 'μm',
  '㎜' => 'mm',
  '㎝' => 'cm',
  '㎞' => 'km',
  '㎟' => 'mm²',
  '㎠' => 'cm²',
  '㎡' => 'm²',
  '㎢' => 'km²',
  '㎣' => 'mm³',
  '㎤' => 'cm³',
  '㎥' => 'm³',
  '㎦' => 'km³',
  '㎧' => 'm∕s',
  '㎨' => 'm∕s²',
  '㎩' => 'Pa',
  '㎪' => 'kPa',
  '㎫' => 'MPa',
  '㎬' => 'GPa',
  '㎭' => 'rad',
  '㎮' => 'rad∕s',
  '㎯' => 'rad∕s²',
  '㎰' => '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',
  '豈' => '豈',
  '更' => '更',
  '車' => '車',
  '賈' => '賈',
  '滑' => '滑',
  '串' => '串',
  '句' => '句',
  '龜' => '龜',
  '龜' => '龜',
  '契' => '契',
  '金' => '金',
  '喇' => '喇',
  '奈' => '奈',
  '懶' => '懶',
  '癩' => '癩',
  '羅' => '羅',
  '蘿' => '蘿',
  '螺' => '螺',
  '裸' => '裸',
  '邏' => '邏',
  '樂' => '樂',
  '洛' => '洛',
  '烙' => '烙',
  '珞' => '珞',
  '落' => '落',
  '酪' => '酪',
  '駱' => '駱',
  '亂' => '亂',
  '卵' => '卵',
  '欄' => '欄',
  '爛' => '爛',
  '蘭' => '蘭',
  '鸞' => '鸞',
  '嵐' => '嵐',
  '濫' => '濫',
  '藍' => '藍',
  '襤' => '襤',
  '拉' => '拉',
  '臘' => '臘',
  '蠟' => '蠟',
  '廊' => '廊',
  '朗' => '朗',
  '浪' => '浪',
  '狼' => '狼',
  '郎' => '郎',
  '來' => '來',
  '冷' => '冷',
  '勞' => '勞',
  '擄' => '擄',
  '櫓' => '櫓',
  '爐' => '爐',
  '盧' => '盧',
  '老' => '老',
  '蘆' => '蘆',
  '虜' => '虜',
  '路' => '路',
  '露' => '露',
  '魯' => '魯',
  '鷺' => '鷺',
  '碌' => '碌',
  '祿' => '祿',
  '綠' => '綠',
  '菉' => '菉',
  '錄' => '錄',
  '鹿' => '鹿',
  '論' => '論',
  '壟' => '壟',
  '弄' => '弄',
  '籠' => '籠',
  '聾' => '聾',
  '牢' => '牢',
  '磊' => '磊',
  '賂' => '賂',
  '雷' => '雷',
  '壘' => '壘',
  '屢' => '屢',
  '樓' => '樓',
  '淚' => '淚',
  '漏' => '漏',
  '累' => '累',
  '縷' => '縷',
  '陋' => '陋',
  '勒' => '勒',
  '肋' => '肋',
  '凜' => '凜',
  '凌' => '凌',
  '稜' => '稜',
  '綾' => '綾',
  '菱' => '菱',
  '陵' => '陵',
  '讀' => '讀',
  '拏' => '拏',
  '樂' => '樂',
  '諾' => '諾',
  '丹' => '丹',
  '寧' => '寧',
  '怒' => '怒',
  '率' => '率',
  '異' => '異',
  '北' => '北',
  '磻' => '磻',
  '便' => '便',
  '復' => '復',
  '不' => '不',
  '泌' => '泌',
  '數' => '數',
  '索' => '索',
  '參' => '參',
  '塞' => '塞',
  '省' => '省',
  '葉' => '葉',
  '說' => '說',
  '殺' => '殺',
  '辰' => '辰',
  '沈' => '沈',
  '拾' => '拾',
  '若' => '若',
  '掠' => '掠',
  '略' => '略',
  '亮' => '亮',
  '兩' => '兩',
  '凉' => '凉',
  '梁' => '梁',
  '糧' => '糧',
  '良' => '良',
  '諒' => '諒',
  '量' => '量',
  '勵' => '勵',
  '呂' => '呂',
  '女' => '女',
  '廬' => '廬',
  '旅' => '旅',
  '濾' => '濾',
  '礪' => '礪',
  '閭' => '閭',
  '驪' => '驪',
  '麗' => '麗',
  '黎' => '黎',
  '力' => '力',
  '曆' => '曆',
  '歷' => '歷',
  '轢' => '轢',
  '年' => '年',
  '憐' => '憐',
  '戀' => '戀',
  '撚' => '撚',
  '漣' => '漣',
  '煉' => '煉',
  '璉' => '璉',
  '秊' => '秊',
  '練' => '練',
  '聯' => '聯',
  '輦' => '輦',
  '蓮' => '蓮',
  '連' => '連',
  '鍊' => '鍊',
  '列' => '列',
  '劣' => '劣',
  '咽' => '咽',
  '烈' => '烈',
  '裂' => '裂',
  '說' => '說',
  '廉' => '廉',
  '念' => '念',
  '捻' => '捻',
  '殮' => '殮',
  '簾' => '簾',
  '獵' => '獵',
  '令' => '令',
  '囹' => '囹',
  '寧' => '寧',
  '嶺' => '嶺',
  '怜' => '怜',
  '玲' => '玲',
  '瑩' => '瑩',
  '羚' => '羚',
  '聆' => '聆',
  '鈴' => '鈴',
  '零' => '零',
  '靈' => '靈',
  '領' => '領',
  '例' => '例',
  '禮' => '禮',
  '醴' => '醴',
  '隸' => '隸',
  '惡' => '惡',
  '了' => '了',
  '僚' => '僚',
  '寮' => '寮',
  '尿' => '尿',
  '料' => '料',
  '樂' => '樂',
  '燎' => '燎',
  '療' => '療',
  '蓼' => '蓼',
  '遼' => '遼',
  '龍' => '龍',
  '暈' => '暈',
  '阮' => '阮',
  '劉' => '劉',
  '杻' => '杻',
  '柳' => '柳',
  '流' => '流',
  '溜' => '溜',
  '琉' => '琉',
  '留' => '留',
  '硫' => '硫',
  '紐' => '紐',
  '類' => '類',
  '六' => '六',
  '戮' => '戮',
  '陸' => '陸',
  '倫' => '倫',
  '崙' => '崙',
  '淪' => '淪',
  '輪' => '輪',
  '律' => '律',
  '慄' => '慄',
  '栗' => '栗',
  '率' => '率',
  '隆' => '隆',
  '利' => '利',
  '吏' => '吏',
  '履' => '履',
  '易' => '易',
  '李' => '李',
  '梨' => '梨',
  '泥' => '泥',
  '理' => '理',
  '痢' => '痢',
  '罹' => '罹',
  '裏' => '裏',
  '裡' => '裡',
  '里' => '里',
  '離' => '離',
  '匿' => '匿',
  '溺' => '溺',
  '吝' => '吝',
  '燐' => '燐',
  '璘' => '璘',
  '藺' => '藺',
  '隣' => '隣',
  '鱗' => '鱗',
  '麟' => '麟',
  '林' => '林',
  '淋' => '淋',
  '臨' => '臨',
  '立' => '立',
  '笠' => '笠',
  '粒' => '粒',
  '狀' => '狀',
  '炙' => '炙',
  '識' => '識',
  '什' => '什',
  '茶' => '茶',
  '刺' => '刺',
  '切' => '切',
  '度' => '度',
  '拓' => '拓',
  '糖' => '糖',
  '宅' => '宅',
  '洞' => '洞',
  '暴' => '暴',
  '輻' => '輻',
  '行' => '行',
  '降' => '降',
  '見' => '見',
  '廓' => '廓',
  '兀' => '兀',
  '嗀' => '嗀',
  '﨎' => '' . "\0" . '',
  '﨏' => '' . "\0" . '',
  '塚' => '塚',
  '﨑' => '' . "\0" . '',
  '晴' => '晴',
  '﨓' => '' . "\0" . '',
  '﨔' => '' . "\0" . '',
  '凞' => '凞',
  '猪' => '猪',
  '益' => '益',
  '礼' => '礼',
  '神' => '神',
  '祥' => '祥',
  '福' => '福',
  '靖' => '靖',
  '精' => '精',
  '羽' => '羽',
  '﨟' => '' . "\0" . '',
  '蘒' => '蘒',
  '﨡' => '' . "\0" . '',
  '諸' => '諸',
  '﨣' => '' . "\0" . '',
  '﨤' => '' . "\0" . '',
  '逸' => '逸',
  '都' => '都',
  '﨧' => '' . "\0" . '',
  '﨨' => '' . "\0" . '',
  '﨩' => '' . "\0" . '',
  '飯' => '飯',
  '飼' => '飼',
  '館' => '館',
  '鶴' => '鶴',
  '郞' => '郞',
  '隷' => '隷',
  '侮' => '侮',
  '僧' => '僧',
  '免' => '免',
  '勉' => '勉',
  '勤' => '勤',
  '卑' => '卑',
  '喝' => '喝',
  '嘆' => '嘆',
  '器' => '器',
  '塀' => '塀',
  '墨' => '墨',
  '層' => '層',
  '屮' => '屮',
  '悔' => '悔',
  '慨' => '慨',
  '憎' => '憎',
  '懲' => '懲',
  '敏' => '敏',
  '既' => '既',
  '暑' => '暑',
  '梅' => '梅',
  '海' => '海',
  '渚' => '渚',
  '漢' => '漢',
  '煮' => '煮',
  '爫' => '爫',
  '琢' => '琢',
  '碑' => '碑',
  '社' => '社',
  '祉' => '祉',
  '祈' => '祈',
  '祐' => '祐',
  '祖' => '祖',
  '祝' => '祝',
  '禍' => '禍',
  '禎' => '禎',
  '穀' => '穀',
  '突' => '突',
  '節' => '節',
  '練' => '練',
  '縉' => '縉',
  '繁' => '繁',
  '署' => '署',
  '者' => '者',
  '臭' => '臭',
  '艹' => '艹',
  '艹' => '艹',
  '著' => '著',
  '褐' => '褐',
  '視' => '視',
  '謁' => '謁',
  '謹' => '謹',
  '賓' => '賓',
  '贈' => '贈',
  '辶' => '辶',
  '逸' => '逸',
  '難' => '難',
  '響' => '響',
  '頻' => '頻',
  '恵' => '恵',
  '𤋮' => '𤋮',
  '舘' => '舘',
  '並' => '並',
  '况' => '况',
  '全' => '全',
  '侀' => '侀',
  '充' => '充',
  '冀' => '冀',
  '勇' => '勇',
  '勺' => '勺',
  '喝' => '喝',
  '啕' => '啕',
  '喙' => '喙',
  '嗢' => '嗢',
  '塚' => '塚',
  '墳' => '墳',
  '奄' => '奄',
  '奔' => '奔',
  '婢' => '婢',
  '嬨' => '嬨',
  '廒' => '廒',
  '廙' => '廙',
  '彩' => '彩',
  '徭' => '徭',
  '惘' => '惘',
  '慎' => '慎',
  '愈' => '愈',
  '憎' => '憎',
  '慠' => '慠',
  '懲' => '懲',
  '戴' => '戴',
  '揄' => '揄',
  '搜' => '搜',
  '摒' => '摒',
  '敖' => '敖',
  '晴' => '晴',
  '朗' => '朗',
  '望' => '望',
  '杖' => '杖',
  '歹' => '歹',
  '殺' => '殺',
  '流' => '流',
  '滛' => '滛',
  '滋' => '滋',
  '漢' => '漢',
  '瀞' => '瀞',
  '煮' => '煮',
  '瞧' => '瞧',
  '爵' => '爵',
  '犯' => '犯',
  '猪' => '猪',
  '瑱' => '瑱',
  '甆' => '甆',
  '画' => '画',
  '瘝' => '瘝',
  '瘟' => '瘟',
  '益' => '益',
  '盛' => '盛',
  '直' => '直',
  '睊' => '睊',
  '着' => '着',
  '磌' => '磌',
  '窱' => '窱',
  '節' => '節',
  '类' => '类',
  '絛' => '絛',
  '練' => '練',
  '缾' => '缾',
  '者' => '者',
  '荒' => '荒',
  '華' => '華',
  '蝹' => '蝹',
  '襁' => '襁',
  '覆' => '覆',
  '視' => '視',
  '調' => '調',
  '諸' => '諸',
  '請' => '請',
  '謁' => '謁',
  '諾' => '諾',
  '諭' => '諭',
  '謹' => '謹',
  '變' => '變',
  '贈' => '贈',
  '輸' => '輸',
  '遲' => '遲',
  '醙' => '醙',
  '鉶' => '鉶',
  '陼' => '陼',
  '難' => '難',
  '靖' => '靖',
  '韛' => '韛',
  '響' => '響',
  '頋' => '頋',
  '頻' => '頻',
  '鬒' => '鬒',
  '龜' => '龜',
  '𢡊' => '𢡊',
  '𢡄' => '𢡄',
  '𣏕' => '𣏕',
  '㮝' => '㮝',
  '䀘' => '䀘',
  '䀹' => '䀹',
  '𥉉' => '𥉉',
  '𥳐' => '𥳐',
  '𧻓' => '𧻓',
  '齃' => '齃',
  '龎' => '龎',
  'ﬀ' => 'ff',
  'ﬁ' => 'fi',
  'ﬂ' => 'fl',
  'ﬃ' => 'ffi',
  'ﬄ' => 'ffl',
  'ﬅ' => 'ſt',
  'ﬆ' => 'st',
  'ﬓ' => 'մն',
  'ﬔ' => 'մե',
  'ﬕ' => 'մի',
  'ﬖ' => 'վն',
  'ﬗ' => 'մխ',
  'ﬠ' => 'ע',
  'ﬡ' => 'א',
  'ﬢ' => 'ד',
  'ﬣ' => 'ה',
  'ﬤ' => 'כ',
  'ﬥ' => 'ל',
  'ﬦ' => 'ם',
  'ﬧ' => 'ר',
  'ﬨ' => 'ת',
  '﬩' => '+',
  'ﭏ' => 'אל',
  '﹉' => '‾',
  '﹊' => '‾',
  '﹋' => '‾',
  '﹌' => '‾',
  '﹍' => '_',
  '﹎' => '_',
  '﹏' => '_',
  '﹐' => ',',
  '﹑' => '、',
  '﹒' => '.',
  '﹔' => ';',
  '﹕' => ':',
  '﹖' => '?',
  '﹗' => '!',
  '﹘' => '—',
  '﹙' => '(',
  '﹚' => ')',
  '﹛' => '{',
  '﹜' => '}',
  '﹝' => '〔',
  '﹞' => '〕',
  '﹟' => '#',
  '﹠' => '&',
  '﹡' => '*',
  '﹢' => '+',
  '﹣' => '-',
  '﹤' => '<',
  '﹥' => '>',
  '﹦' => '=',
  '﹨' => '\\',
  '﹩' => '$',
  '﹪' => '%',
  '﹫' => '@',
  '！' => '!',
  '＂' => '"',
  '＃' => '#',
  '＄' => '$',
  '％' => '%',
  '＆' => '&',
  '＇' => '\'',
  '（' => '(',
  '）' => ')',
  '＊' => '*',
  '＋' => '+',
  '，' => ',',
  '－' => '-',
  '．' => '.',
  '／' => '/',
  '０' => '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',
  '［' => '[',
  '＼' => '\\',
  '］' => ']',
  '＾' => '^',
  '＿' => '_',
  '｀' => '`',
  'ａ' => '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',
  '𝑖' => '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',
  '🆐' => 'DJ',
  '🈀' => 'ほか',
  '🈁' => 'ココ',
  '🈂' => 'サ',
  '🈐' => '手',
  '🈑' => '字',
  '🈒' => '双',
  '🈓' => 'デ',
  '🈔' => '二',
  '🈕' => '多',
  '🈖' => '解',
  '🈗' => '天',
  '🈘' => '交',
  '🈙' => '映',
  '🈚' => '無',
  '🈛' => '料',
  '🈜' => '前',
  '🈝' => '後',
  '🈞' => '再',
  '🈟' => '新',
  '🈠' => '初',
  '🈡' => '終',
  '🈢' => '生',
  '🈣' => '販',
  '🈤' => '声',
  '🈥' => '吹',
  '🈦' => '演',
  '🈧' => '投',
  '🈨' => '捕',
  '🈩' => '一',
  '🈪' => '三',
  '🈫' => '遊',
  '🈬' => '左',
  '🈭' => '中',
  '🈮' => '右',
  '🈯' => '指',
  '🈰' => '走',
  '🈱' => '打',
  '🈲' => '禁',
  '🈳' => '空',
  '🈴' => '合',
  '🈵' => '満',
  '🈶' => '有',
  '🈷' => '月',
  '🈸' => '申',
  '🈹' => '割',
  '🈺' => '営',
  '🈻' => '配',
  '🉀' => '〔本〕',
  '🉁' => '〔三〕',
  '🉂' => '〔二〕',
  '🉃' => '〔安〕',
  '🉄' => '〔点〕',
  '🉅' => '〔打〕',
  '🉆' => '〔盗〕',
  '🉇' => '〔勝〕',
  '🉈' => '〔敗〕',
  '🉐' => '(得)',
  '🉑' => '(可)',
  '🯰' => '0',
  '🯱' => '1',
  '🯲' => '2',
  '🯳' => '3',
  '🯴' => '4',
  '🯵' => '5',
  '🯶' => '6',
  '🯷' => '7',
  '🯸' => '8',
  '🯹' => '9',
  '丽' => '丽',
  '丸' => '丸',
  '乁' => '乁',
  '𠄢' => '𠄢',
  '你' => '你',
  '侮' => '侮',
  '侻' => '侻',
  '倂' => '倂',
  '偺' => '偺',
  '備' => '備',
  '僧' => '僧',
  '像' => '像',
  '㒞' => '㒞',
  '𠘺' => '𠘺',
  '免' => '免',
  '兔' => '兔',
  '兤' => '兤',
  '具' => '具',
  '𠔜' => '𠔜',
  '㒹' => '㒹',
  '內' => '內',
  '再' => '再',
  '𠕋' => '𠕋',
  '冗' => '冗',
  '冤' => '冤',
  '仌' => '仌',
  '冬' => '冬',
  '况' => '况',
  '𩇟' => '𩇟',
  '凵' => '凵',
  '刃' => '刃',
  '㓟' => '㓟',
  '刻' => '刻',
  '剆' => '剆',
  '割' => '割',
  '剷' => '剷',
  '㔕' => '㔕',
  '勇' => '勇',
  '勉' => '勉',
  '勤' => '勤',
  '勺' => '勺',
  '包' => '包',
  '匆' => '匆',
  '北' => '北',
  '卉' => '卉',
  '卑' => '卑',
  '博' => '博',
  '即' => '即',
  '卽' => '卽',
  '卿' => '卿',
  '卿' => '卿',
  '卿' => '卿',
  '𠨬' => '𠨬',
  '灰' => '灰',
  '及' => '及',
  '叟' => '叟',
  '𠭣' => '𠭣',
  '叫' => '叫',
  '叱' => '叱',
  '吆' => '吆',
  '咞' => '咞',
  '吸' => '吸',
  '呈' => '呈',
  '周' => '周',
  '咢' => '咢',
  '哶' => '哶',
  '唐' => '唐',
  '啓' => '啓',
  '啣' => '啣',
  '善' => '善',
  '善' => '善',
  '喙' => '喙',
  '喫' => '喫',
  '喳' => '喳',
  '嗂' => '嗂',
  '圖' => '圖',
  '嘆' => '嘆',
  '圗' => '圗',
  '噑' => '噑',
  '噴' => '噴',
  '切' => '切',
  '壮' => '壮',
  '城' => '城',
  '埴' => '埴',
  '堍' => '堍',
  '型' => '型',
  '堲' => '堲',
  '報' => '報',
  '墬' => '墬',
  '𡓤' => '𡓤',
  '売' => '売',
  '壷' => '壷',
  '夆' => '夆',
  '多' => '多',
  '夢' => '夢',
  '奢' => '奢',
  '𡚨' => '𡚨',
  '𡛪' => '𡛪',
  '姬' => '姬',
  '娛' => '娛',
  '娧' => '娧',
  '姘' => '姘',
  '婦' => '婦',
  '㛮' => '㛮',
  '㛼' => '㛼',
  '嬈' => '嬈',
  '嬾' => '嬾',
  '嬾' => '嬾',
  '𡧈' => '𡧈',
  '寃' => '寃',
  '寘' => '寘',
  '寧' => '寧',
  '寳' => '寳',
  '𡬘' => '𡬘',
  '寿' => '寿',
  '将' => '将',
  '当' => '当',
  '尢' => '尢',
  '㞁' => '㞁',
  '屠' => '屠',
  '屮' => '屮',
  '峀' => '峀',
  '岍' => '岍',
  '𡷤' => '𡷤',
  '嵃' => '嵃',
  '𡷦' => '𡷦',
  '嵮' => '嵮',
  '嵫' => '嵫',
  '嵼' => '嵼',
  '巡' => '巡',
  '巢' => '巢',
  '㠯' => '㠯',
  '巽' => '巽',
  '帨' => '帨',
  '帽' => '帽',
  '幩' => '幩',
  '㡢' => '㡢',
  '𢆃' => '𢆃',
  '㡼' => '㡼',
  '庰' => '庰',
  '庳' => '庳',
  '庶' => '庶',
  '廊' => '廊',
  '𪎒' => '𪎒',
  '廾' => '廾',
  '𢌱' => '𢌱',
  '𢌱' => '𢌱',
  '舁' => '舁',
  '弢' => '弢',
  '弢' => '弢',
  '㣇' => '㣇',
  '𣊸' => '𣊸',
  '𦇚' => '𦇚',
  '形' => '形',
  '彫' => '彫',
  '㣣' => '㣣',
  '徚' => '徚',
  '忍' => '忍',
  '志' => '志',
  '忹' => '忹',
  '悁' => '悁',
  '㤺' => '㤺',
  '㤜' => '㤜',
  '悔' => '悔',
  '𢛔' => '𢛔',
  '惇' => '惇',
  '慈' => '慈',
  '慌' => '慌',
  '慎' => '慎',
  '慌' => '慌',
  '慺' => '慺',
  '憎' => '憎',
  '憲' => '憲',
  '憤' => '憤',
  '憯' => '憯',
  '懞' => '懞',
  '懲' => '懲',
  '懶' => '懶',
  '成' => '成',
  '戛' => '戛',
  '扝' => '扝',
  '抱' => '抱',
  '拔' => '拔',
  '捐' => '捐',
  '𢬌' => '𢬌',
  '挽' => '挽',
  '拼' => '拼',
  '捨' => '捨',
  '掃' => '掃',
  '揤' => '揤',
  '𢯱' => '𢯱',
  '搢' => '搢',
  '揅' => '揅',
  '掩' => '掩',
  '㨮' => '㨮',
  '摩' => '摩',
  '摾' => '摾',
  '撝' => '撝',
  '摷' => '摷',
  '㩬' => '㩬',
  '敏' => '敏',
  '敬' => '敬',
  '𣀊' => '𣀊',
  '旣' => '旣',
  '書' => '書',
  '晉' => '晉',
  '㬙' => '㬙',
  '暑' => '暑',
  '㬈' => '㬈',
  '㫤' => '㫤',
  '冒' => '冒',
  '冕' => '冕',
  '最' => '最',
  '暜' => '暜',
  '肭' => '肭',
  '䏙' => '䏙',
  '朗' => '朗',
  '望' => '望',
  '朡' => '朡',
  '杞' => '杞',
  '杓' => '杓',
  '𣏃' => '𣏃',
  '㭉' => '㭉',
  '柺' => '柺',
  '枅' => '枅',
  '桒' => '桒',
  '梅' => '梅',
  '𣑭' => '𣑭',
  '梎' => '梎',
  '栟' => '栟',
  '椔' => '椔',
  '㮝' => '㮝',
  '楂' => '楂',
  '榣' => '榣',
  '槪' => '槪',
  '檨' => '檨',
  '𣚣' => '𣚣',
  '櫛' => '櫛',
  '㰘' => '㰘',
  '次' => '次',
  '𣢧' => '𣢧',
  '歔' => '歔',
  '㱎' => '㱎',
  '歲' => '歲',
  '殟' => '殟',
  '殺' => '殺',
  '殻' => '殻',
  '𣪍' => '𣪍',
  '𡴋' => '𡴋',
  '𣫺' => '𣫺',
  '汎' => '汎',
  '𣲼' => '𣲼',
  '沿' => '沿',
  '泍' => '泍',
  '汧' => '汧',
  '洖' => '洖',
  '派' => '派',
  '海' => '海',
  '流' => '流',
  '浩' => '浩',
  '浸' => '浸',
  '涅' => '涅',
  '𣴞' => '𣴞',
  '洴' => '洴',
  '港' => '港',
  '湮' => '湮',
  '㴳' => '㴳',
  '滋' => '滋',
  '滇' => '滇',
  '𣻑' => '𣻑',
  '淹' => '淹',
  '潮' => '潮',
  '𣽞' => '𣽞',
  '𣾎' => '𣾎',
  '濆' => '濆',
  '瀹' => '瀹',
  '瀞' => '瀞',
  '瀛' => '瀛',
  '㶖' => '㶖',
  '灊' => '灊',
  '災' => '災',
  '灷' => '灷',
  '炭' => '炭',
  '𠔥' => '𠔥',
  '煅' => '煅',
  '𤉣' => '𤉣',
  '熜' => '熜',
  '𤎫' => '𤎫',
  '爨' => '爨',
  '爵' => '爵',
  '牐' => '牐',
  '𤘈' => '𤘈',
  '犀' => '犀',
  '犕' => '犕',
  '𤜵' => '𤜵',
  '𤠔' => '𤠔',
  '獺' => '獺',
  '王' => '王',
  '㺬' => '㺬',
  '玥' => '玥',
  '㺸' => '㺸',
  '㺸' => '㺸',
  '瑇' => '瑇',
  '瑜' => '瑜',
  '瑱' => '瑱',
  '璅' => '璅',
  '瓊' => '瓊',
  '㼛' => '㼛',
  '甤' => '甤',
  '𤰶' => '𤰶',
  '甾' => '甾',
  '𤲒' => '𤲒',
  '異' => '異',
  '𢆟' => '𢆟',
  '瘐' => '瘐',
  '𤾡' => '𤾡',
  '𤾸' => '𤾸',
  '𥁄' => '𥁄',
  '㿼' => '㿼',
  '䀈' => '䀈',
  '直' => '直',
  '𥃳' => '𥃳',
  '𥃲' => '𥃲',
  '𥄙' => '𥄙',
  '𥄳' => '𥄳',
  '眞' => '眞',
  '真' => '真',
  '真' => '真',
  '睊' => '睊',
  '䀹' => '䀹',
  '瞋' => '瞋',
  '䁆' => '䁆',
  '䂖' => '䂖',
  '𥐝' => '𥐝',
  '硎' => '硎',
  '碌' => '碌',
  '磌' => '磌',
  '䃣' => '䃣',
  '𥘦' => '𥘦',
  '祖' => '祖',
  '𥚚' => '𥚚',
  '𥛅' => '𥛅',
  '福' => '福',
  '秫' => '秫',
  '䄯' => '䄯',
  '穀' => '穀',
  '穊' => '穊',
  '穏' => '穏',
  '𥥼' => '𥥼',
  '𥪧' => '𥪧',
  '𥪧' => '𥪧',
  '竮' => '竮',
  '䈂' => '䈂',
  '𥮫' => '𥮫',
  '篆' => '篆',
  '築' => '築',
  '䈧' => '䈧',
  '𥲀' => '𥲀',
  '糒' => '糒',
  '䊠' => '䊠',
  '糨' => '糨',
  '糣' => '糣',
  '紀' => '紀',
  '𥾆' => '𥾆',
  '絣' => '絣',
  '䌁' => '䌁',
  '緇' => '緇',
  '縂' => '縂',
  '繅' => '繅',
  '䌴' => '䌴',
  '𦈨' => '𦈨',
  '𦉇' => '𦉇',
  '䍙' => '䍙',
  '𦋙' => '𦋙',
  '罺' => '罺',
  '𦌾' => '𦌾',
  '羕' => '羕',
  '翺' => '翺',
  '者' => '者',
  '𦓚' => '𦓚',
  '𦔣' => '𦔣',
  '聠' => '聠',
  '𦖨' => '𦖨',
  '聰' => '聰',
  '𣍟' => '𣍟',
  '䏕' => '䏕',
  '育' => '育',
  '脃' => '脃',
  '䐋' => '䐋',
  '脾' => '脾',
  '媵' => '媵',
  '𦞧' => '𦞧',
  '𦞵' => '𦞵',
  '𣎓' => '𣎓',
  '𣎜' => '𣎜',
  '舁' => '舁',
  '舄' => '舄',
  '辞' => '辞',
  '䑫' => '䑫',
  '芑' => '芑',
  '芋' => '芋',
  '芝' => '芝',
  '劳' => '劳',
  '花' => '花',
  '芳' => '芳',
  '芽' => '芽',
  '苦' => '苦',
  '𦬼' => '𦬼',
  '若' => '若',
  '茝' => '茝',
  '荣' => '荣',
  '莭' => '莭',
  '茣' => '茣',
  '莽' => '莽',
  '菧' => '菧',
  '著' => '著',
  '荓' => '荓',
  '菊' => '菊',
  '菌' => '菌',
  '菜' => '菜',
  '𦰶' => '𦰶',
  '𦵫' => '𦵫',
  '𦳕' => '𦳕',
  '䔫' => '䔫',
  '蓱' => '蓱',
  '蓳' => '蓳',
  '蔖' => '蔖',
  '𧏊' => '𧏊',
  '蕤' => '蕤',
  '𦼬' => '𦼬',
  '䕝' => '䕝',
  '䕡' => '䕡',
  '𦾱' => '𦾱',
  '𧃒' => '𧃒',
  '䕫' => '䕫',
  '虐' => '虐',
  '虜' => '虜',
  '虧' => '虧',
  '虩' => '虩',
  '蚩' => '蚩',
  '蚈' => '蚈',
  '蜎' => '蜎',
  '蛢' => '蛢',
  '蝹' => '蝹',
  '蜨' => '蜨',
  '蝫' => '蝫',
  '螆' => '螆',
  '䗗' => '䗗',
  '蟡' => '蟡',
  '蠁' => '蠁',
  '䗹' => '䗹',
  '衠' => '衠',
  '衣' => '衣',
  '𧙧' => '𧙧',
  '裗' => '裗',
  '裞' => '裞',
  '䘵' => '䘵',
  '裺' => '裺',
  '㒻' => '㒻',
  '𧢮' => '𧢮',
  '𧥦' => '𧥦',
  '䚾' => '䚾',
  '䛇' => '䛇',
  '誠' => '誠',
  '諭' => '諭',
  '變' => '變',
  '豕' => '豕',
  '𧲨' => '𧲨',
  '貫' => '貫',
  '賁' => '賁',
  '贛' => '贛',
  '起' => '起',
  '𧼯' => '𧼯',
  '𠠄' => '𠠄',
  '跋' => '跋',
  '趼' => '趼',
  '跰' => '跰',
  '𠣞' => '𠣞',
  '軔' => '軔',
  '輸' => '輸',
  '𨗒' => '𨗒',
  '𨗭' => '𨗭',
  '邔' => '邔',
  '郱' => '郱',
  '鄑' => '鄑',
  '𨜮' => '𨜮',
  '鄛' => '鄛',
  '鈸' => '鈸',
  '鋗' => '鋗',
  '鋘' => '鋘',
  '鉼' => '鉼',
  '鏹' => '鏹',
  '鐕' => '鐕',
  '𨯺' => '𨯺',
  '開' => '開',
  '䦕' => '䦕',
  '閷' => '閷',
  '𨵷' => '𨵷',
  '䧦' => '䧦',
  '雃' => '雃',
  '嶲' => '嶲',
  '霣' => '霣',
  '𩅅' => '𩅅',
  '𩈚' => '𩈚',
  '䩮' => '䩮',
  '䩶' => '䩶',
  '韠' => '韠',
  '𩐊' => '𩐊',
  '䪲' => '䪲',
  '𩒖' => '𩒖',
  '頋' => '頋',
  '頋' => '頋',
  '頩' => '頩',
  '𩖶' => '𩖶',
  '飢' => '飢',
  '䬳' => '䬳',
  '餩' => '餩',
  '馧' => '馧',
  '駂' => '駂',
  '駾' => '駾',
  '䯎' => '䯎',
  '𩬰' => '𩬰',
  '鬒' => '鬒',
  '鱀' => '鱀',
  '鳽' => '鳽',
  '䳎' => '䳎',
  '䳭' => '䳭',
  '鵧' => '鵧',
  '𪃎' => '𪃎',
  '䳸' => '䳸',
  '𪄅' => '𪄅',
  '𪈎' => '𪈎',
  '𪊑' => '𪊑',
  '麻' => '麻',
  '䵖' => '䵖',
  '黹' => '黹',
  '黾' => '黾',
  '鼅' => '鼅',
  '鼏' => '鼏',
  '鼖' => '鼖',
  '鼻' => '鼻',
  '𪘀' => '𪘀',
  'Æ' => 'AE',
  'Ð' => 'D',
  'Ø' => 'O',
  'Þ' => 'TH',
  'ß' => 'ss',
  'æ' => 'ae',
  'ð' => 'd',
  'ø' => 'o',
  'þ' => 'th',
  'Đ' => 'D',
  'đ' => 'd',
  'Ħ' => 'H',
  'ħ' => 'h',
  'ı' => 'i',
  'ĸ' => 'q',
  'Ł' => 'L',
  'ł' => 'l',
  'Ŋ' => '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',
  'Ǥ' => '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',
  'ẜ' => 's',
  'ẝ' => 's',
  'ẞ' => 'SS',
  'Ỻ' => 'LL',
  'ỻ' => 'll',
  'Ỽ' => 'V',
  'ỽ' => 'v',
  'Ỿ' => 'Y',
  'ỿ' => 'y',
  'Ⱡ' => 'L',
  'ⱡ' => 'l',
  'Ɫ' => 'L',
  'Ᵽ' => 'P',
  'Ɽ' => 'R',
  'ⱥ' => 'a',
  'ⱦ' => 't',
  'Ⱨ' => 'H',
  'ⱨ' => 'h',
  'Ⱪ' => 'K',
  'ⱪ' => 'k',
  'Ⱬ' => 'Z',
  'ⱬ' => 'z',
  'Ɱ' => 'M',
  'ⱱ' => 'v',
  'Ⱳ' => 'W',
  'ⱳ' => 'w',
  'ⱴ' => 'v',
  'ⱸ' => 'e',
  'ⱺ' => 'o',
  'Ȿ' => 'S',
  'Ɀ' => 'Z',
  'ꜰ' => 'F',
  'ꜱ' => 'S',
  'Ꜳ' => 'AA',
  'ꜳ' => 'aa',
  'Ꜵ' => 'AO',
  'ꜵ' => 'ao',
  'Ꜷ' => 'AU',
  'ꜷ' => 'au',
  'Ꜹ' => 'AV',
  'ꜹ' => 'av',
  'Ꜻ' => 'AV',
  'ꜻ' => 'av',
  'Ꜽ' => 'AY',
  'ꜽ' => 'ay',
  'Ꝁ' => 'K',
  'ꝁ' => 'k',
  'Ꝃ' => 'K',
  'ꝃ' => 'k',
  'Ꝅ' => 'K',
  'ꝅ' => 'k',
  'Ꝇ' => 'L',
  'ꝇ' => 'l',
  'Ꝉ' => 'L',
  'ꝉ' => 'l',
  'Ꝋ' => 'O',
  'ꝋ' => 'o',
  'Ꝍ' => 'O',
  'ꝍ' => 'o',
  'Ꝏ' => 'OO',
  'ꝏ' => 'oo',
  'Ꝑ' => 'P',
  'ꝑ' => 'p',
  'Ꝓ' => 'P',
  'ꝓ' => 'p',
  'Ꝕ' => 'P',
  'ꝕ' => 'p',
  'Ꝗ' => 'Q',
  'ꝗ' => 'q',
  'Ꝙ' => 'Q',
  'ꝙ' => 'q',
  'Ꝟ' => 'V',
  'ꝟ' => 'v',
  'Ꝡ' => 'VY',
  'ꝡ' => 'vy',
  'Ꝥ' => 'TH',
  'ꝥ' => 'th',
  'Ꝧ' => 'TH',
  'ꝧ' => 'th',
  'ꝱ' => 'd',
  'ꝲ' => 'l',
  'ꝳ' => 'm',
  'ꝴ' => 'n',
  'ꝵ' => 'r',
  'ꝶ' => 'R',
  'ꝷ' => 't',
  'Ꝺ' => 'D',
  'ꝺ' => 'd',
  'Ꝼ' => 'F',
  'ꝼ' => 'f',
  'Ꞇ' => 'T',
  'ꞇ' => 't',
  'Ꞑ' => 'N',
  'ꞑ' => 'n',
  'Ꞓ' => 'C',
  'ꞓ' => 'c',
  'Ꞡ' => 'G',
  'ꞡ' => 'g',
  'Ꞣ' => 'K',
  'ꞣ' => 'k',
  'Ꞥ' => 'N',
  'ꞥ' => 'n',
  'Ꞧ' => 'R',
  'ꞧ' => 'r',
  'Ꞩ' => 'S',
  'ꞩ' => 's',
  'Ɦ' => 'H',
  '©' => '(C)',
  '®' => '(R)',
  '₠' => 'CE',
  '₢' => 'Cr',
  '₣' => 'Fr.',
  '₤' => 'L.',
  '₧' => 'Pts',
  '₹' => 'Rs',
  '₺' => 'TL',
  '℗' => '(P)',
  '℘' => 'P',
  '℞' => 'Rx',
  '〇' => '0',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  'ʹ' => '\'',
  'ʺ' => '"',
  'ʻ' => '\'',
  'ʼ' => '\'',
  'ʽ' => '\'',
  'ˈ' => '\'',
  'ˋ' => '`',
  '‘' => '\'',
  '’' => '\'',
  '‚' => ',',
  '‛' => '\'',
  '“' => '"',
  '”' => '"',
  '„' => ',,',
  '‟' => '"',
  '′' => '\'',
  '〝' => '"',
  '〞' => '"',
  '«' => '<<',
  '»' => '>>',
  '‹' => '<',
  '›' => '>',
  '­' => '-',
  '‐' => '-',
  '‑' => '-',
  '‒' => '-',
  '–' => '-',
  '—' => '-',
  '―' => '-',
  '︱' => '-',
  '︲' => '-',
  '¡' => '!',
  '¿' => '?',
  '˂' => '<',
  '˃' => '>',
  '˄' => '^',
  'ˆ' => '^',
  'ː' => ':',
  '˜' => '~',
  '‖' => '||',
  '⁄' => '/',
  '⁅' => '[',
  '⁆' => ']',
  '⁎' => '*',
  '、' => ',',
  '。' => '.',
  '〈' => '<',
  '〉' => '>',
  '《' => '<<',
  '》' => '>>',
  '〔' => '[',
  '〕' => ']',
  '〘' => '[',
  '〙' => ']',
  '〚' => '[',
  '〛' => ']',
  '︐' => ',',
  '︑' => ',',
  '︒' => '.',
  '︓' => ':',
  '︔' => ';',
  '︕' => '!',
  '︖' => '?',
  '︙' => '...',
  '︰' => '..',
  '︵' => '(',
  '︶' => ')',
  '︷' => '{',
  '︸' => '}',
  '︹' => '[',
  '︺' => ']',
  '︽' => '<<',
  '︾' => '>>',
  '︿' => '<',
  '﹀' => '>',
  '﹇' => '[',
  '﹈' => ']',
  '±' => '+/-',
  '×' => '*',
  '÷' => '/',
  '˖' => '+',
  '˗' => '-',
  '−' => '-',
  '∕' => '/',
  '∖' => '\\',
  '∣' => '|',
  '∥' => '||',
  '≪' => '<<',
  '≫' => '>>',
  '⦅' => '((',
  '⦆' => '))',
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Intl\Grapheme as p;

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); }
}
if (!function_exists('grapheme_str_split')) {
    function grapheme_str_split($string, $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Intl\Grapheme as p;

if (!function_exists('grapheme_str_split')) {
    function grapheme_str_split(string $string, int $length = 1): array|false { return p\Grapheme::grapheme_str_split($string, $length); }
}

if (extension_loaded('intl')) {
    return;
}

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); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\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
 * - grapheme_str_split - Splits a string into an array of individual or chunks of graphemes
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @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');
    }

    public static function grapheme_str_split($s, $len = 1)
    {
        if (0 > $len || 1073741823 < $len) {
            if (80000 > \PHP_VERSION_ID) {
                return false;
            }

            throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.');
        }

        if ('' === $s) {
            return [];
        }

        if (!preg_match_all('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', $s, $matches)) {
            return false;
        }

        if (1 === $len) {
            return $matches[0];
        }

        $chunks = array_chunk($matches[0], $len);

        foreach ($chunks as &$chunk) {
            $chunk = implode('', $chunk);
        }

        return $chunks;
    }

    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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Intl\Idn as p;

if (extension_loaded('intl')) {
    return;
}

if (\PHP_VERSION_ID >= 80000) {
    return require __DIR__.'/bootstrap80.php';
}

if (!defined('U_IDNA_PROHIBITED_ERROR')) {
    define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
    define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
    define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
    define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
    define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
    define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
    define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
    define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
    define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
    define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
    define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
    define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
    define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
    define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
    define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
    define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
    define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
    define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
    define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
    define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
    define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_2003')) {
    define('INTL_IDNA_VARIANT_2003', 0);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
    define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
    define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
    define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
    define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
    define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
    define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
    define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
    define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
    define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
    define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
    define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
    define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
    define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
    define('IDNA_ERROR_CONTEXTJ', 4096);
}

if (\PHP_VERSION_ID < 70400) {
    if (!function_exists('idn_to_ascii')) {
        function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
    }
    if (!function_exists('idn_to_utf8')) {
        function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
    }
} else {
    if (!function_exists('idn_to_ascii')) {
        function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
    }
    if (!function_exists('idn_to_utf8')) {
        function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Intl\Idn as p;

if (!defined('U_IDNA_PROHIBITED_ERROR')) {
    define('U_IDNA_PROHIBITED_ERROR', 66560);
}
if (!defined('U_IDNA_ERROR_START')) {
    define('U_IDNA_ERROR_START', 66560);
}
if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
    define('U_IDNA_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
    define('U_IDNA_CHECK_BIDI_ERROR', 66562);
}
if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
    define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
}
if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
    define('U_IDNA_ACE_PREFIX_ERROR', 66564);
}
if (!defined('U_IDNA_VERIFICATION_ERROR')) {
    define('U_IDNA_VERIFICATION_ERROR', 66565);
}
if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
    define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
}
if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
    define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
}
if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
    define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
}
if (!defined('U_IDNA_ERROR_LIMIT')) {
    define('U_IDNA_ERROR_LIMIT', 66569);
}
if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
    define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
}
if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
    define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
}
if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
    define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
}
if (!defined('IDNA_DEFAULT')) {
    define('IDNA_DEFAULT', 0);
}
if (!defined('IDNA_ALLOW_UNASSIGNED')) {
    define('IDNA_ALLOW_UNASSIGNED', 1);
}
if (!defined('IDNA_USE_STD3_RULES')) {
    define('IDNA_USE_STD3_RULES', 2);
}
if (!defined('IDNA_CHECK_BIDI')) {
    define('IDNA_CHECK_BIDI', 4);
}
if (!defined('IDNA_CHECK_CONTEXTJ')) {
    define('IDNA_CHECK_CONTEXTJ', 8);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
    define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
}
if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
    define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
}
if (!defined('INTL_IDNA_VARIANT_UTS46')) {
    define('INTL_IDNA_VARIANT_UTS46', 1);
}
if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
    define('IDNA_ERROR_EMPTY_LABEL', 1);
}
if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
    define('IDNA_ERROR_LABEL_TOO_LONG', 2);
}
if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
    define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
}
if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
    define('IDNA_ERROR_LEADING_HYPHEN', 8);
}
if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
    define('IDNA_ERROR_TRAILING_HYPHEN', 16);
}
if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
    define('IDNA_ERROR_HYPHEN_3_4', 32);
}
if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
    define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
}
if (!defined('IDNA_ERROR_DISALLOWED')) {
    define('IDNA_ERROR_DISALLOWED', 128);
}
if (!defined('IDNA_ERROR_PUNYCODE')) {
    define('IDNA_ERROR_PUNYCODE', 256);
}
if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
    define('IDNA_ERROR_LABEL_HAS_DOT', 512);
}
if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
    define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
}
if (!defined('IDNA_ERROR_BIDI')) {
    define('IDNA_ERROR_BIDI', 2048);
}
if (!defined('IDNA_ERROR_CONTEXTJ')) {
    define('IDNA_ERROR_CONTEXTJ', 4096);
}

if (!function_exists('idn_to_ascii')) {
    function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}
if (!function_exists('idn_to_utf8')) {
    function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Intl\Idn;

use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex;

/**
 * @see https://www.unicode.org/reports/tr46/
 *
 * @internal
 */
final class Idn
{
    public const ERROR_EMPTY_LABEL = 1;
    public const ERROR_LABEL_TOO_LONG = 2;
    public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
    public const ERROR_LEADING_HYPHEN = 8;
    public const ERROR_TRAILING_HYPHEN = 0x10;
    public const ERROR_HYPHEN_3_4 = 0x20;
    public const ERROR_LEADING_COMBINING_MARK = 0x40;
    public const ERROR_DISALLOWED = 0x80;
    public const ERROR_PUNYCODE = 0x100;
    public const ERROR_LABEL_HAS_DOT = 0x200;
    public const ERROR_INVALID_ACE_LABEL = 0x400;
    public const ERROR_BIDI = 0x800;
    public const ERROR_CONTEXTJ = 0x1000;
    public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
    public const ERROR_CONTEXTO_DIGITS = 0x4000;

    public const INTL_IDNA_VARIANT_2003 = 0;
    public const INTL_IDNA_VARIANT_UTS46 = 1;

    public const IDNA_DEFAULT = 0;
    public const IDNA_ALLOW_UNASSIGNED = 1;
    public const IDNA_USE_STD3_RULES = 2;
    public const IDNA_CHECK_BIDI = 4;
    public const IDNA_CHECK_CONTEXTJ = 8;
    public const IDNA_NONTRANSITIONAL_TO_ASCII = 16;
    public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;

    public const MAX_DOMAIN_SIZE = 253;
    public const MAX_LABEL_SIZE = 63;

    public const BASE = 36;
    public const TMIN = 1;
    public const TMAX = 26;
    public const SKEW = 38;
    public const DAMP = 700;
    public const INITIAL_BIAS = 72;
    public const INITIAL_N = 128;
    public const DELIMITER = '-';
    public const MAX_INT = 2147483647;

    /**
     * Contains the numeric value of a basic code point (for use in representing integers) in the
     * range 0 to BASE-1, or -1 if b is does not represent a value.
     *
     * @var array<int, int>
     */
    private static $basicToDigit = [
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,

        -1,  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, 25, -1, -1, -1, -1, -1,

        -1,  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, 25, -1, -1, -1, -1, -1,

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    ];

    /**
     * @var array<int, int>
     */
    private static $virama;

    /**
     * @var array<int, string>
     */
    private static $mapped;

    /**
     * @var array<int, bool>
     */
    private static $ignored;

    /**
     * @var array<int, string>
     */
    private static $deviation;

    /**
     * @var array<int, bool>
     */
    private static $disallowed;

    /**
     * @var array<int, string>
     */
    private static $disallowed_STD3_mapped;

    /**
     * @var array<int, bool>
     */
    private static $disallowed_STD3_valid;

    /**
     * @var bool
     */
    private static $mappingTableLoaded = false;

    /**
     * @see https://www.unicode.org/reports/tr46/#ToASCII
     *
     * @param string $domainName
     * @param int    $options
     * @param int    $variant
     * @param array  $idna_info
     *
     * @return string|false
     */
    public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
    {
        if (\PHP_VERSION_ID > 80400 && '' === $domainName) {
            throw new \ValueError('idn_to_ascii(): Argument #1 ($domain) cannot be empty');
        }

        if (self::INTL_IDNA_VARIANT_2003 === $variant) {
            @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
        }

        $options = [
            'CheckHyphens' => true,
            'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
            'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
            'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
            'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII),
            'VerifyDnsLength' => true,
        ];
        $info = new Info();
        $labels = self::process((string) $domainName, $options, $info);

        foreach ($labels as $i => $label) {
            // Only convert labels to punycode that contain non-ASCII code points
            if (1 === preg_match('/[^\x00-\x7F]/', $label)) {
                try {
                    $label = 'xn--'.self::punycodeEncode($label);
                } catch (\Exception $e) {
                    $info->errors |= self::ERROR_PUNYCODE;
                }

                $labels[$i] = $label;
            }
        }

        if ($options['VerifyDnsLength']) {
            self::validateDomainAndLabelLength($labels, $info);
        }

        $idna_info = [
            'result' => implode('.', $labels),
            'isTransitionalDifferent' => $info->transitionalDifferent,
            'errors' => $info->errors,
        ];

        return 0 === $info->errors ? $idna_info['result'] : false;
    }

    /**
     * @see https://www.unicode.org/reports/tr46/#ToUnicode
     *
     * @param string $domainName
     * @param int    $options
     * @param int    $variant
     * @param array  $idna_info
     *
     * @return string|false
     */
    public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
    {
        if (\PHP_VERSION_ID > 80400 && '' === $domainName) {
            throw new \ValueError('idn_to_utf8(): Argument #1 ($domain) cannot be empty');
        }

        if (self::INTL_IDNA_VARIANT_2003 === $variant) {
            @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
        }

        $info = new Info();
        $labels = self::process((string) $domainName, [
            'CheckHyphens' => true,
            'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
            'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
            'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
            'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE),
        ], $info);
        $idna_info = [
            'result' => implode('.', $labels),
            'isTransitionalDifferent' => $info->transitionalDifferent,
            'errors' => $info->errors,
        ];

        return 0 === $info->errors ? $idna_info['result'] : false;
    }

    /**
     * @param string $label
     *
     * @return bool
     */
    private static function isValidContextJ(array $codePoints, $label)
    {
        if (!isset(self::$virama)) {
            self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php';
        }

        $offset = 0;

        foreach ($codePoints as $i => $codePoint) {
            if (0x200C !== $codePoint && 0x200D !== $codePoint) {
                continue;
            }

            if (!isset($codePoints[$i - 1])) {
                return false;
            }

            // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True;
            if (isset(self::$virama[$codePoints[$i - 1]])) {
                continue;
            }

            // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then
            // True;
            // Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\u200C[Joining_Type:T]*)[Joining_Type:{R,D}]
            if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \PREG_OFFSET_CAPTURE, $offset)) {
                $offset += \strlen($matches[1][0]);

                continue;
            }

            return false;
        }

        return true;
    }

    /**
     * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap
     *
     * @param string              $input
     * @param array<string, bool> $options
     *
     * @return string
     */
    private static function mapCodePoints($input, array $options, Info $info)
    {
        $str = '';
        $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
        $transitional = $options['Transitional_Processing'];

        foreach (self::utf8Decode($input) as $codePoint) {
            $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);

            switch ($data['status']) {
                case 'disallowed':
                case 'valid':
                    $str .= mb_chr($codePoint, 'utf-8');

                    break;

                case 'ignored':
                    // Do nothing.
                    break;

                case 'mapped':
                    $str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping'];

                    break;

                case 'deviation':
                    $info->transitionalDifferent = true;
                    $str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8'));

                    break;
            }
        }

        return $str;
    }

    /**
     * @see https://www.unicode.org/reports/tr46/#Processing
     *
     * @param string              $domain
     * @param array<string, bool> $options
     *
     * @return array<int, string>
     */
    private static function process($domain, array $options, Info $info)
    {
        // If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and
        // we need to respect the VerifyDnsLength option.
        $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'];

        if ($checkForEmptyLabels && '' === $domain) {
            $info->errors |= self::ERROR_EMPTY_LABEL;

            return [$domain];
        }

        // Step 1. Map each code point in the domain name string
        $domain = self::mapCodePoints($domain, $options, $info);

        // Step 2. Normalize the domain name string to Unicode Normalization Form C.
        if (!\Normalizer::isNormalized($domain, \Normalizer::FORM_C)) {
            $domain = \Normalizer::normalize($domain, \Normalizer::FORM_C);
        }

        // Step 3. Break the string into labels at U+002E (.) FULL STOP.
        $labels = explode('.', $domain);
        $lastLabelIndex = \count($labels) - 1;

        // Step 4. Convert and validate each label in the domain name string.
        foreach ($labels as $i => $label) {
            $validationOptions = $options;

            if ('xn--' === substr($label, 0, 4)) {
                // Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F),
                // record that there was an error, and continue with the next label.
                if (preg_match('/[^\x00-\x7F]/', $label)) {
                    $info->errors |= self::ERROR_PUNYCODE;

                    continue;
                }

                // Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If
                // that conversion fails, record that there was an error, and continue
                // with the next label. Otherwise replace the original label in the string by the results of the
                // conversion.
                try {
                    $label = self::punycodeDecode(substr($label, 4));
                } catch (\Exception $e) {
                    $info->errors |= self::ERROR_PUNYCODE;

                    continue;
                }

                $validationOptions['Transitional_Processing'] = false;
                $labels[$i] = $label;
            }

            self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex);
        }

        if ($info->bidiDomain && !$info->validBidiDomain) {
            $info->errors |= self::ERROR_BIDI;
        }

        // Any input domain name string that does not record an error has been successfully
        // processed according to this specification. Conversely, if an input domain_name string
        // causes an error, then the processing of the input domain_name string fails. Determining
        // what to do with error input is up to the caller, and not in the scope of this document.
        return $labels;
    }

    /**
     * @see https://tools.ietf.org/html/rfc5893#section-2
     *
     * @param string $label
     */
    private static function validateBidiLabel($label, Info $info)
    {
        if (1 === preg_match(Regex::RTL_LABEL, $label)) {
            $info->bidiDomain = true;

            // Step 1. The first character must be a character with Bidi property L, R, or AL.
            // If it has the R or AL property, it is an RTL label
            if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) {
                $info->validBidiDomain = false;

                return;
            }

            // Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES,
            // CS, ET, ON, BN, or NSM are allowed.
            if (1 === preg_match(Regex::BIDI_STEP_2, $label)) {
                $info->validBidiDomain = false;

                return;
            }

            // Step 3. In an RTL label, the end of the label must be a character with Bidi property
            // R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM.
            if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) {
                $info->validBidiDomain = false;

                return;
            }

            // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa.
            if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) {
                $info->validBidiDomain = false;

                return;
            }

            return;
        }

        // We are a LTR label
        // Step 1. The first character must be a character with Bidi property L, R, or AL.
        // If it has the L property, it is an LTR label.
        if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) {
            $info->validBidiDomain = false;

            return;
        }

        // Step 5. In an LTR label, only characters with the Bidi properties L, EN,
        // ES, CS, ET, ON, BN, or NSM are allowed.
        if (1 === preg_match(Regex::BIDI_STEP_5, $label)) {
            $info->validBidiDomain = false;

            return;
        }

        // Step 6.In an LTR label, the end of the label must be a character with Bidi property L or
        // EN, followed by zero or more characters with Bidi property NSM.
        if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) {
            $info->validBidiDomain = false;

            return;
        }
    }

    /**
     * @param array<int, string> $labels
     */
    private static function validateDomainAndLabelLength(array $labels, Info $info)
    {
        $maxDomainSize = self::MAX_DOMAIN_SIZE;
        $length = \count($labels);

        // Number of "." delimiters.
        $domainLength = $length - 1;

        // If the last label is empty and it is not the first label, then it is the root label.
        // Increase the max size by 1, making it 254, to account for the root label's "."
        // delimiter. This also means we don't need to check the last label's length for being too
        // long.
        if ($length > 1 && '' === $labels[$length - 1]) {
            ++$maxDomainSize;
            --$length;
        }

        for ($i = 0; $i < $length; ++$i) {
            $bytes = \strlen($labels[$i]);
            $domainLength += $bytes;

            if ($bytes > self::MAX_LABEL_SIZE) {
                $info->errors |= self::ERROR_LABEL_TOO_LONG;
            }
        }

        if ($domainLength > $maxDomainSize) {
            $info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG;
        }
    }

    /**
     * @see https://www.unicode.org/reports/tr46/#Validity_Criteria
     *
     * @param string              $label
     * @param array<string, bool> $options
     * @param bool                $canBeEmpty
     */
    private static function validateLabel($label, Info $info, array $options, $canBeEmpty)
    {
        if ('' === $label) {
            if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) {
                $info->errors |= self::ERROR_EMPTY_LABEL;
            }

            return;
        }

        // Step 1. The label must be in Unicode Normalization Form C.
        if (!\Normalizer::isNormalized($label, \Normalizer::FORM_C)) {
            $info->errors |= self::ERROR_INVALID_ACE_LABEL;
        }

        $codePoints = self::utf8Decode($label);

        if ($options['CheckHyphens']) {
            // Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
            // in both the thrid and fourth positions.
            if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) {
                $info->errors |= self::ERROR_HYPHEN_3_4;
            }

            // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D
            // HYPHEN-MINUS character.
            if ('-' === substr($label, 0, 1)) {
                $info->errors |= self::ERROR_LEADING_HYPHEN;
            }

            if ('-' === substr($label, -1, 1)) {
                $info->errors |= self::ERROR_TRAILING_HYPHEN;
            }
        } elseif ('xn--' === substr($label, 0, 4)) {
            $info->errors |= self::ERROR_PUNYCODE;
        }

        // Step 4. The label must not contain a U+002E (.) FULL STOP.
        if (false !== strpos($label, '.')) {
            $info->errors |= self::ERROR_LABEL_HAS_DOT;
        }

        // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark.
        if (1 === preg_match(Regex::COMBINING_MARK, $label)) {
            $info->errors |= self::ERROR_LEADING_COMBINING_MARK;
        }

        // Step 6. Each code point in the label must only have certain status values according to
        // Section 5, IDNA Mapping Table:
        $transitional = $options['Transitional_Processing'];
        $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];

        foreach ($codePoints as $codePoint) {
            $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
            $status = $data['status'];

            if ('valid' === $status || (!$transitional && 'deviation' === $status)) {
                continue;
            }

            $info->errors |= self::ERROR_DISALLOWED;

            break;
        }

        // Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in
        // The Unicode Code Points and Internationalized Domain Names for Applications (IDNA)
        // [IDNA2008].
        if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) {
            $info->errors |= self::ERROR_CONTEXTJ;
        }

        // Step 8. If CheckBidi, and if the domain name is a  Bidi domain name, then the label must
        // satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2.
        if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) {
            self::validateBidiLabel($label, $info);
        }
    }

    /**
     * @see https://tools.ietf.org/html/rfc3492#section-6.2
     *
     * @param string $input
     *
     * @return string
     */
    private static function punycodeDecode($input)
    {
        $n = self::INITIAL_N;
        $out = 0;
        $i = 0;
        $bias = self::INITIAL_BIAS;
        $lastDelimIndex = strrpos($input, self::DELIMITER);
        $b = false === $lastDelimIndex ? 0 : $lastDelimIndex;
        $inputLength = \strlen($input);
        $output = [];
        $bytes = array_map('ord', str_split($input));

        for ($j = 0; $j < $b; ++$j) {
            if ($bytes[$j] > 0x7F) {
                throw new \Exception('Invalid input');
            }

            $output[$out++] = $input[$j];
        }

        if ($b > 0) {
            ++$b;
        }

        for ($in = $b; $in < $inputLength; ++$out) {
            $oldi = $i;
            $w = 1;

            for ($k = self::BASE; /* no condition */; $k += self::BASE) {
                if ($in >= $inputLength) {
                    throw new \Exception('Invalid input');
                }

                $digit = self::$basicToDigit[$bytes[$in++] & 0xFF];

                if ($digit < 0) {
                    throw new \Exception('Invalid input');
                }

                if ($digit > intdiv(self::MAX_INT - $i, $w)) {
                    throw new \Exception('Integer overflow');
                }

                $i += $digit * $w;

                if ($k <= $bias) {
                    $t = self::TMIN;
                } elseif ($k >= $bias + self::TMAX) {
                    $t = self::TMAX;
                } else {
                    $t = $k - $bias;
                }

                if ($digit < $t) {
                    break;
                }

                $baseMinusT = self::BASE - $t;

                if ($w > intdiv(self::MAX_INT, $baseMinusT)) {
                    throw new \Exception('Integer overflow');
                }

                $w *= $baseMinusT;
            }

            $outPlusOne = $out + 1;
            $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);

            if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {
                throw new \Exception('Integer overflow');
            }

            $n += intdiv($i, $outPlusOne);
            $i %= $outPlusOne;
            array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]);
        }

        return implode('', $output);
    }

    /**
     * @see https://tools.ietf.org/html/rfc3492#section-6.3
     *
     * @param string $input
     *
     * @return string
     */
    private static function punycodeEncode($input)
    {
        $n = self::INITIAL_N;
        $delta = 0;
        $out = 0;
        $bias = self::INITIAL_BIAS;
        $inputLength = 0;
        $output = '';
        $iter = self::utf8Decode($input);

        foreach ($iter as $codePoint) {
            ++$inputLength;

            if ($codePoint < 0x80) {
                $output .= \chr($codePoint);
                ++$out;
            }
        }

        $h = $out;
        $b = $out;

        if ($b > 0) {
            $output .= self::DELIMITER;
            ++$out;
        }

        while ($h < $inputLength) {
            $m = self::MAX_INT;

            foreach ($iter as $codePoint) {
                if ($codePoint >= $n && $codePoint < $m) {
                    $m = $codePoint;
                }
            }

            if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {
                throw new \Exception('Integer overflow');
            }

            $delta += ($m - $n) * ($h + 1);
            $n = $m;

            foreach ($iter as $codePoint) {
                if ($codePoint < $n && 0 === ++$delta) {
                    throw new \Exception('Integer overflow');
                }

                if ($codePoint === $n) {
                    $q = $delta;

                    for ($k = self::BASE; /* no condition */; $k += self::BASE) {
                        if ($k <= $bias) {
                            $t = self::TMIN;
                        } elseif ($k >= $bias + self::TMAX) {
                            $t = self::TMAX;
                        } else {
                            $t = $k - $bias;
                        }

                        if ($q < $t) {
                            break;
                        }

                        $qMinusT = $q - $t;
                        $baseMinusT = self::BASE - $t;
                        $output .= self::encodeDigit($t + $qMinusT % $baseMinusT, false);
                        ++$out;
                        $q = intdiv($qMinusT, $baseMinusT);
                    }

                    $output .= self::encodeDigit($q, false);
                    ++$out;
                    $bias = self::adaptBias($delta, $h + 1, $h === $b);
                    $delta = 0;
                    ++$h;
                }
            }

            ++$delta;
            ++$n;
        }

        return $output;
    }

    /**
     * @see https://tools.ietf.org/html/rfc3492#section-6.1
     *
     * @param int  $delta
     * @param int  $numPoints
     * @param bool $firstTime
     *
     * @return int
     */
    private static function adaptBias($delta, $numPoints, $firstTime)
    {
        // xxx >> 1 is a faster way of doing intdiv(xxx, 2)
        $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1;
        $delta += intdiv($delta, $numPoints);
        $k = 0;

        while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) {
            $delta = intdiv($delta, self::BASE - self::TMIN);
            $k += self::BASE;
        }

        return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW);
    }

    /**
     * @param int  $d
     * @param bool $flag
     *
     * @return string
     */
    private static function encodeDigit($d, $flag)
    {
        return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5));
    }

    /**
     * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any
     * invalid byte sequences will be replaced by a U+FFFD replacement code point.
     *
     * @see https://encoding.spec.whatwg.org/#utf-8-decoder
     *
     * @param string $input
     *
     * @return array<int, int>
     */
    private static function utf8Decode($input)
    {
        $bytesSeen = 0;
        $bytesNeeded = 0;
        $lowerBoundary = 0x80;
        $upperBoundary = 0xBF;
        $codePoint = 0;
        $codePoints = [];
        $length = \strlen($input);

        for ($i = 0; $i < $length; ++$i) {
            $byte = \ord($input[$i]);

            if (0 === $bytesNeeded) {
                if ($byte >= 0x00 && $byte <= 0x7F) {
                    $codePoints[] = $byte;

                    continue;
                }

                if ($byte >= 0xC2 && $byte <= 0xDF) {
                    $bytesNeeded = 1;
                    $codePoint = $byte & 0x1F;
                } elseif ($byte >= 0xE0 && $byte <= 0xEF) {
                    if (0xE0 === $byte) {
                        $lowerBoundary = 0xA0;
                    } elseif (0xED === $byte) {
                        $upperBoundary = 0x9F;
                    }

                    $bytesNeeded = 2;
                    $codePoint = $byte & 0xF;
                } elseif ($byte >= 0xF0 && $byte <= 0xF4) {
                    if (0xF0 === $byte) {
                        $lowerBoundary = 0x90;
                    } elseif (0xF4 === $byte) {
                        $upperBoundary = 0x8F;
                    }

                    $bytesNeeded = 3;
                    $codePoint = $byte & 0x7;
                } else {
                    $codePoints[] = 0xFFFD;
                }

                continue;
            }

            if ($byte < $lowerBoundary || $byte > $upperBoundary) {
                $codePoint = 0;
                $bytesNeeded = 0;
                $bytesSeen = 0;
                $lowerBoundary = 0x80;
                $upperBoundary = 0xBF;
                --$i;
                $codePoints[] = 0xFFFD;

                continue;
            }

            $lowerBoundary = 0x80;
            $upperBoundary = 0xBF;
            $codePoint = ($codePoint << 6) | ($byte & 0x3F);

            if (++$bytesSeen !== $bytesNeeded) {
                continue;
            }

            $codePoints[] = $codePoint;
            $codePoint = 0;
            $bytesNeeded = 0;
            $bytesSeen = 0;
        }

        // String unexpectedly ended, so append a U+FFFD code point.
        if (0 !== $bytesNeeded) {
            $codePoints[] = 0xFFFD;
        }

        return $codePoints;
    }

    /**
     * @param int  $codePoint
     * @param bool $useSTD3ASCIIRules
     *
     * @return array{status: string, mapping?: string}
     */
    private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules)
    {
        if (!self::$mappingTableLoaded) {
            self::$mappingTableLoaded = true;
            self::$mapped = require __DIR__.'/Resources/unidata/mapped.php';
            self::$ignored = require __DIR__.'/Resources/unidata/ignored.php';
            self::$deviation = require __DIR__.'/Resources/unidata/deviation.php';
            self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php';
            self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php';
            self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php';
        }

        if (isset(self::$mapped[$codePoint])) {
            return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]];
        }

        if (isset(self::$ignored[$codePoint])) {
            return ['status' => 'ignored'];
        }

        if (isset(self::$deviation[$codePoint])) {
            return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]];
        }

        if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) {
            return ['status' => 'disallowed'];
        }

        $isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]);

        if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) {
            $status = 'disallowed';

            if (!$useSTD3ASCIIRules) {
                $status = $isDisallowedMapped ? 'mapped' : 'valid';
            }

            if ($isDisallowedMapped) {
                return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]];
            }

            return ['status' => $status];
        }

        return ['status' => 'valid'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Intl\Idn;

/**
 * @internal
 */
class Info
{
    public $bidiDomain = false;
    public $errors = 0;
    public $validBidiDomain = true;
    public $transitionalDifferent = false;
}
<?php

return array (
  223 => 'ss',
  962 => 'σ',
  8204 => '',
  8205 => '',
);
<?php

return array (
  888 => true,
  889 => true,
  896 => true,
  897 => true,
  898 => true,
  899 => true,
  907 => true,
  909 => true,
  930 => true,
  1216 => true,
  1328 => true,
  1367 => true,
  1368 => true,
  1419 => true,
  1420 => true,
  1424 => true,
  1480 => true,
  1481 => true,
  1482 => true,
  1483 => true,
  1484 => true,
  1485 => true,
  1486 => true,
  1487 => true,
  1515 => true,
  1516 => true,
  1517 => true,
  1518 => true,
  1525 => true,
  1526 => true,
  1527 => true,
  1528 => true,
  1529 => true,
  1530 => true,
  1531 => true,
  1532 => true,
  1533 => true,
  1534 => true,
  1535 => true,
  1536 => true,
  1537 => true,
  1538 => true,
  1539 => true,
  1540 => true,
  1541 => true,
  1564 => true,
  1565 => true,
  1757 => true,
  1806 => true,
  1807 => true,
  1867 => true,
  1868 => true,
  1970 => true,
  1971 => true,
  1972 => true,
  1973 => true,
  1974 => true,
  1975 => true,
  1976 => true,
  1977 => true,
  1978 => true,
  1979 => true,
  1980 => true,
  1981 => true,
  1982 => true,
  1983 => true,
  2043 => true,
  2044 => true,
  2094 => true,
  2095 => true,
  2111 => true,
  2140 => true,
  2141 => true,
  2143 => true,
  2229 => true,
  2248 => true,
  2249 => true,
  2250 => true,
  2251 => true,
  2252 => true,
  2253 => true,
  2254 => true,
  2255 => true,
  2256 => true,
  2257 => true,
  2258 => true,
  2274 => true,
  2436 => true,
  2445 => true,
  2446 => true,
  2449 => true,
  2450 => true,
  2473 => true,
  2481 => true,
  2483 => true,
  2484 => true,
  2485 => true,
  2490 => true,
  2491 => true,
  2501 => true,
  2502 => true,
  2505 => true,
  2506 => true,
  2511 => true,
  2512 => true,
  2513 => true,
  2514 => true,
  2515 => true,
  2516 => true,
  2517 => true,
  2518 => true,
  2520 => true,
  2521 => true,
  2522 => true,
  2523 => true,
  2526 => true,
  2532 => true,
  2533 => true,
  2559 => true,
  2560 => true,
  2564 => true,
  2571 => true,
  2572 => true,
  2573 => true,
  2574 => true,
  2577 => true,
  2578 => true,
  2601 => true,
  2609 => true,
  2612 => true,
  2615 => true,
  2618 => true,
  2619 => true,
  2621 => true,
  2627 => true,
  2628 => true,
  2629 => true,
  2630 => true,
  2633 => true,
  2634 => true,
  2638 => true,
  2639 => true,
  2640 => true,
  2642 => true,
  2643 => true,
  2644 => true,
  2645 => true,
  2646 => true,
  2647 => true,
  2648 => true,
  2653 => true,
  2655 => true,
  2656 => true,
  2657 => true,
  2658 => true,
  2659 => true,
  2660 => true,
  2661 => true,
  2679 => true,
  2680 => true,
  2681 => true,
  2682 => true,
  2683 => true,
  2684 => true,
  2685 => true,
  2686 => true,
  2687 => true,
  2688 => true,
  2692 => true,
  2702 => true,
  2706 => true,
  2729 => true,
  2737 => true,
  2740 => true,
  2746 => true,
  2747 => true,
  2758 => true,
  2762 => true,
  2766 => true,
  2767 => true,
  2769 => true,
  2770 => true,
  2771 => true,
  2772 => true,
  2773 => true,
  2774 => true,
  2775 => true,
  2776 => true,
  2777 => true,
  2778 => true,
  2779 => true,
  2780 => true,
  2781 => true,
  2782 => true,
  2783 => true,
  2788 => true,
  2789 => true,
  2802 => true,
  2803 => true,
  2804 => true,
  2805 => true,
  2806 => true,
  2807 => true,
  2808 => true,
  2816 => true,
  2820 => true,
  2829 => true,
  2830 => true,
  2833 => true,
  2834 => true,
  2857 => true,
  2865 => true,
  2868 => true,
  2874 => true,
  2875 => true,
  2885 => true,
  2886 => true,
  2889 => true,
  2890 => true,
  2894 => true,
  2895 => true,
  2896 => true,
  2897 => true,
  2898 => true,
  2899 => true,
  2900 => true,
  2904 => true,
  2905 => true,
  2906 => true,
  2907 => true,
  2910 => true,
  2916 => true,
  2917 => true,
  2936 => true,
  2937 => true,
  2938 => true,
  2939 => true,
  2940 => true,
  2941 => true,
  2942 => true,
  2943 => true,
  2944 => true,
  2945 => true,
  2948 => true,
  2955 => true,
  2956 => true,
  2957 => true,
  2961 => true,
  2966 => true,
  2967 => true,
  2968 => true,
  2971 => true,
  2973 => true,
  2976 => true,
  2977 => true,
  2978 => true,
  2981 => true,
  2982 => true,
  2983 => true,
  2987 => true,
  2988 => true,
  2989 => true,
  3002 => true,
  3003 => true,
  3004 => true,
  3005 => true,
  3011 => true,
  3012 => true,
  3013 => true,
  3017 => true,
  3022 => true,
  3023 => true,
  3025 => true,
  3026 => true,
  3027 => true,
  3028 => true,
  3029 => true,
  3030 => true,
  3032 => true,
  3033 => true,
  3034 => true,
  3035 => true,
  3036 => true,
  3037 => true,
  3038 => true,
  3039 => true,
  3040 => true,
  3041 => true,
  3042 => true,
  3043 => true,
  3044 => true,
  3045 => true,
  3067 => true,
  3068 => true,
  3069 => true,
  3070 => true,
  3071 => true,
  3085 => true,
  3089 => true,
  3113 => true,
  3130 => true,
  3131 => true,
  3132 => true,
  3141 => true,
  3145 => true,
  3150 => true,
  3151 => true,
  3152 => true,
  3153 => true,
  3154 => true,
  3155 => true,
  3156 => true,
  3159 => true,
  3163 => true,
  3164 => true,
  3165 => true,
  3166 => true,
  3167 => true,
  3172 => true,
  3173 => true,
  3184 => true,
  3185 => true,
  3186 => true,
  3187 => true,
  3188 => true,
  3189 => true,
  3190 => true,
  3213 => true,
  3217 => true,
  3241 => true,
  3252 => true,
  3258 => true,
  3259 => true,
  3269 => true,
  3273 => true,
  3278 => true,
  3279 => true,
  3280 => true,
  3281 => true,
  3282 => true,
  3283 => true,
  3284 => true,
  3287 => true,
  3288 => true,
  3289 => true,
  3290 => true,
  3291 => true,
  3292 => true,
  3293 => true,
  3295 => true,
  3300 => true,
  3301 => true,
  3312 => true,
  3315 => true,
  3316 => true,
  3317 => true,
  3318 => true,
  3319 => true,
  3320 => true,
  3321 => true,
  3322 => true,
  3323 => true,
  3324 => true,
  3325 => true,
  3326 => true,
  3327 => true,
  3341 => true,
  3345 => true,
  3397 => true,
  3401 => true,
  3408 => true,
  3409 => true,
  3410 => true,
  3411 => true,
  3428 => true,
  3429 => true,
  3456 => true,
  3460 => true,
  3479 => true,
  3480 => true,
  3481 => true,
  3506 => true,
  3516 => true,
  3518 => true,
  3519 => true,
  3527 => true,
  3528 => true,
  3529 => true,
  3531 => true,
  3532 => true,
  3533 => true,
  3534 => true,
  3541 => true,
  3543 => true,
  3552 => true,
  3553 => true,
  3554 => true,
  3555 => true,
  3556 => true,
  3557 => true,
  3568 => true,
  3569 => true,
  3573 => true,
  3574 => true,
  3575 => true,
  3576 => true,
  3577 => true,
  3578 => true,
  3579 => true,
  3580 => true,
  3581 => true,
  3582 => true,
  3583 => true,
  3584 => true,
  3643 => true,
  3644 => true,
  3645 => true,
  3646 => true,
  3715 => true,
  3717 => true,
  3723 => true,
  3748 => true,
  3750 => true,
  3774 => true,
  3775 => true,
  3781 => true,
  3783 => true,
  3790 => true,
  3791 => true,
  3802 => true,
  3803 => true,
  3912 => true,
  3949 => true,
  3950 => true,
  3951 => true,
  3952 => true,
  3992 => true,
  4029 => true,
  4045 => true,
  4294 => true,
  4296 => true,
  4297 => true,
  4298 => true,
  4299 => true,
  4300 => true,
  4302 => true,
  4303 => true,
  4447 => true,
  4448 => true,
  4681 => true,
  4686 => true,
  4687 => true,
  4695 => true,
  4697 => true,
  4702 => true,
  4703 => true,
  4745 => true,
  4750 => true,
  4751 => true,
  4785 => true,
  4790 => true,
  4791 => true,
  4799 => true,
  4801 => true,
  4806 => true,
  4807 => true,
  4823 => true,
  4881 => true,
  4886 => true,
  4887 => true,
  4955 => true,
  4956 => true,
  4989 => true,
  4990 => true,
  4991 => true,
  5018 => true,
  5019 => true,
  5020 => true,
  5021 => true,
  5022 => true,
  5023 => true,
  5110 => true,
  5111 => true,
  5118 => true,
  5119 => true,
  5760 => true,
  5789 => true,
  5790 => true,
  5791 => true,
  5881 => true,
  5882 => true,
  5883 => true,
  5884 => true,
  5885 => true,
  5886 => true,
  5887 => true,
  5901 => true,
  5909 => true,
  5910 => true,
  5911 => true,
  5912 => true,
  5913 => true,
  5914 => true,
  5915 => true,
  5916 => true,
  5917 => true,
  5918 => true,
  5919 => true,
  5943 => true,
  5944 => true,
  5945 => true,
  5946 => true,
  5947 => true,
  5948 => true,
  5949 => true,
  5950 => true,
  5951 => true,
  5972 => true,
  5973 => true,
  5974 => true,
  5975 => true,
  5976 => true,
  5977 => true,
  5978 => true,
  5979 => true,
  5980 => true,
  5981 => true,
  5982 => true,
  5983 => true,
  5997 => true,
  6001 => true,
  6004 => true,
  6005 => true,
  6006 => true,
  6007 => true,
  6008 => true,
  6009 => true,
  6010 => true,
  6011 => true,
  6012 => true,
  6013 => true,
  6014 => true,
  6015 => true,
  6068 => true,
  6069 => true,
  6110 => true,
  6111 => true,
  6122 => true,
  6123 => true,
  6124 => true,
  6125 => true,
  6126 => true,
  6127 => true,
  6138 => true,
  6139 => true,
  6140 => true,
  6141 => true,
  6142 => true,
  6143 => true,
  6150 => true,
  6158 => true,
  6159 => true,
  6170 => true,
  6171 => true,
  6172 => true,
  6173 => true,
  6174 => true,
  6175 => true,
  6265 => true,
  6266 => true,
  6267 => true,
  6268 => true,
  6269 => true,
  6270 => true,
  6271 => true,
  6315 => true,
  6316 => true,
  6317 => true,
  6318 => true,
  6319 => true,
  6390 => true,
  6391 => true,
  6392 => true,
  6393 => true,
  6394 => true,
  6395 => true,
  6396 => true,
  6397 => true,
  6398 => true,
  6399 => true,
  6431 => true,
  6444 => true,
  6445 => true,
  6446 => true,
  6447 => true,
  6460 => true,
  6461 => true,
  6462 => true,
  6463 => true,
  6465 => true,
  6466 => true,
  6467 => true,
  6510 => true,
  6511 => true,
  6517 => true,
  6518 => true,
  6519 => true,
  6520 => true,
  6521 => true,
  6522 => true,
  6523 => true,
  6524 => true,
  6525 => true,
  6526 => true,
  6527 => true,
  6572 => true,
  6573 => true,
  6574 => true,
  6575 => true,
  6602 => true,
  6603 => true,
  6604 => true,
  6605 => true,
  6606 => true,
  6607 => true,
  6619 => true,
  6620 => true,
  6621 => true,
  6684 => true,
  6685 => true,
  6751 => true,
  6781 => true,
  6782 => true,
  6794 => true,
  6795 => true,
  6796 => true,
  6797 => true,
  6798 => true,
  6799 => true,
  6810 => true,
  6811 => true,
  6812 => true,
  6813 => true,
  6814 => true,
  6815 => true,
  6830 => true,
  6831 => true,
  6988 => true,
  6989 => true,
  6990 => true,
  6991 => true,
  7037 => true,
  7038 => true,
  7039 => true,
  7156 => true,
  7157 => true,
  7158 => true,
  7159 => true,
  7160 => true,
  7161 => true,
  7162 => true,
  7163 => true,
  7224 => true,
  7225 => true,
  7226 => true,
  7242 => true,
  7243 => true,
  7244 => true,
  7305 => true,
  7306 => true,
  7307 => true,
  7308 => true,
  7309 => true,
  7310 => true,
  7311 => true,
  7355 => true,
  7356 => true,
  7368 => true,
  7369 => true,
  7370 => true,
  7371 => true,
  7372 => true,
  7373 => true,
  7374 => true,
  7375 => true,
  7419 => true,
  7420 => true,
  7421 => true,
  7422 => true,
  7423 => true,
  7674 => true,
  7958 => true,
  7959 => true,
  7966 => true,
  7967 => true,
  8006 => true,
  8007 => true,
  8014 => true,
  8015 => true,
  8024 => true,
  8026 => true,
  8028 => true,
  8030 => true,
  8062 => true,
  8063 => true,
  8117 => true,
  8133 => true,
  8148 => true,
  8149 => true,
  8156 => true,
  8176 => true,
  8177 => true,
  8181 => true,
  8191 => true,
  8206 => true,
  8207 => true,
  8228 => true,
  8229 => true,
  8230 => true,
  8232 => true,
  8233 => true,
  8234 => true,
  8235 => true,
  8236 => true,
  8237 => true,
  8238 => true,
  8289 => true,
  8290 => true,
  8291 => true,
  8293 => true,
  8294 => true,
  8295 => true,
  8296 => true,
  8297 => true,
  8298 => true,
  8299 => true,
  8300 => true,
  8301 => true,
  8302 => true,
  8303 => true,
  8306 => true,
  8307 => true,
  8335 => true,
  8349 => true,
  8350 => true,
  8351 => true,
  8384 => true,
  8385 => true,
  8386 => true,
  8387 => true,
  8388 => true,
  8389 => true,
  8390 => true,
  8391 => true,
  8392 => true,
  8393 => true,
  8394 => true,
  8395 => true,
  8396 => true,
  8397 => true,
  8398 => true,
  8399 => true,
  8433 => true,
  8434 => true,
  8435 => true,
  8436 => true,
  8437 => true,
  8438 => true,
  8439 => true,
  8440 => true,
  8441 => true,
  8442 => true,
  8443 => true,
  8444 => true,
  8445 => true,
  8446 => true,
  8447 => true,
  8498 => true,
  8579 => true,
  8588 => true,
  8589 => true,
  8590 => true,
  8591 => true,
  9255 => true,
  9256 => true,
  9257 => true,
  9258 => true,
  9259 => true,
  9260 => true,
  9261 => true,
  9262 => true,
  9263 => true,
  9264 => true,
  9265 => true,
  9266 => true,
  9267 => true,
  9268 => true,
  9269 => true,
  9270 => true,
  9271 => true,
  9272 => true,
  9273 => true,
  9274 => true,
  9275 => true,
  9276 => true,
  9277 => true,
  9278 => true,
  9279 => true,
  9291 => true,
  9292 => true,
  9293 => true,
  9294 => true,
  9295 => true,
  9296 => true,
  9297 => true,
  9298 => true,
  9299 => true,
  9300 => true,
  9301 => true,
  9302 => true,
  9303 => true,
  9304 => true,
  9305 => true,
  9306 => true,
  9307 => true,
  9308 => true,
  9309 => true,
  9310 => true,
  9311 => true,
  9352 => true,
  9353 => true,
  9354 => true,
  9355 => true,
  9356 => true,
  9357 => true,
  9358 => true,
  9359 => true,
  9360 => true,
  9361 => true,
  9362 => true,
  9363 => true,
  9364 => true,
  9365 => true,
  9366 => true,
  9367 => true,
  9368 => true,
  9369 => true,
  9370 => true,
  9371 => true,
  11124 => true,
  11125 => true,
  11158 => true,
  11311 => true,
  11359 => true,
  11508 => true,
  11509 => true,
  11510 => true,
  11511 => true,
  11512 => true,
  11558 => true,
  11560 => true,
  11561 => true,
  11562 => true,
  11563 => true,
  11564 => true,
  11566 => true,
  11567 => true,
  11624 => true,
  11625 => true,
  11626 => true,
  11627 => true,
  11628 => true,
  11629 => true,
  11630 => true,
  11633 => true,
  11634 => true,
  11635 => true,
  11636 => true,
  11637 => true,
  11638 => true,
  11639 => true,
  11640 => true,
  11641 => true,
  11642 => true,
  11643 => true,
  11644 => true,
  11645 => true,
  11646 => true,
  11671 => true,
  11672 => true,
  11673 => true,
  11674 => true,
  11675 => true,
  11676 => true,
  11677 => true,
  11678 => true,
  11679 => true,
  11687 => true,
  11695 => true,
  11703 => true,
  11711 => true,
  11719 => true,
  11727 => true,
  11735 => true,
  11743 => true,
  11930 => true,
  12020 => true,
  12021 => true,
  12022 => true,
  12023 => true,
  12024 => true,
  12025 => true,
  12026 => true,
  12027 => true,
  12028 => true,
  12029 => true,
  12030 => true,
  12031 => true,
  12246 => true,
  12247 => true,
  12248 => true,
  12249 => true,
  12250 => true,
  12251 => true,
  12252 => true,
  12253 => true,
  12254 => true,
  12255 => true,
  12256 => true,
  12257 => true,
  12258 => true,
  12259 => true,
  12260 => true,
  12261 => true,
  12262 => true,
  12263 => true,
  12264 => true,
  12265 => true,
  12266 => true,
  12267 => true,
  12268 => true,
  12269 => true,
  12270 => true,
  12271 => true,
  12272 => true,
  12273 => true,
  12274 => true,
  12275 => true,
  12276 => true,
  12277 => true,
  12278 => true,
  12279 => true,
  12280 => true,
  12281 => true,
  12282 => true,
  12283 => true,
  12284 => true,
  12285 => true,
  12286 => true,
  12287 => true,
  12352 => true,
  12439 => true,
  12440 => true,
  12544 => true,
  12545 => true,
  12546 => true,
  12547 => true,
  12548 => true,
  12592 => true,
  12644 => true,
  12687 => true,
  12772 => true,
  12773 => true,
  12774 => true,
  12775 => true,
  12776 => true,
  12777 => true,
  12778 => true,
  12779 => true,
  12780 => true,
  12781 => true,
  12782 => true,
  12783 => true,
  12831 => true,
  13250 => true,
  13255 => true,
  13272 => true,
  40957 => true,
  40958 => true,
  40959 => true,
  42125 => true,
  42126 => true,
  42127 => true,
  42183 => true,
  42184 => true,
  42185 => true,
  42186 => true,
  42187 => true,
  42188 => true,
  42189 => true,
  42190 => true,
  42191 => true,
  42540 => true,
  42541 => true,
  42542 => true,
  42543 => true,
  42544 => true,
  42545 => true,
  42546 => true,
  42547 => true,
  42548 => true,
  42549 => true,
  42550 => true,
  42551 => true,
  42552 => true,
  42553 => true,
  42554 => true,
  42555 => true,
  42556 => true,
  42557 => true,
  42558 => true,
  42559 => true,
  42744 => true,
  42745 => true,
  42746 => true,
  42747 => true,
  42748 => true,
  42749 => true,
  42750 => true,
  42751 => true,
  42944 => true,
  42945 => true,
  43053 => true,
  43054 => true,
  43055 => true,
  43066 => true,
  43067 => true,
  43068 => true,
  43069 => true,
  43070 => true,
  43071 => true,
  43128 => true,
  43129 => true,
  43130 => true,
  43131 => true,
  43132 => true,
  43133 => true,
  43134 => true,
  43135 => true,
  43206 => true,
  43207 => true,
  43208 => true,
  43209 => true,
  43210 => true,
  43211 => true,
  43212 => true,
  43213 => true,
  43226 => true,
  43227 => true,
  43228 => true,
  43229 => true,
  43230 => true,
  43231 => true,
  43348 => true,
  43349 => true,
  43350 => true,
  43351 => true,
  43352 => true,
  43353 => true,
  43354 => true,
  43355 => true,
  43356 => true,
  43357 => true,
  43358 => true,
  43389 => true,
  43390 => true,
  43391 => true,
  43470 => true,
  43482 => true,
  43483 => true,
  43484 => true,
  43485 => true,
  43519 => true,
  43575 => true,
  43576 => true,
  43577 => true,
  43578 => true,
  43579 => true,
  43580 => true,
  43581 => true,
  43582 => true,
  43583 => true,
  43598 => true,
  43599 => true,
  43610 => true,
  43611 => true,
  43715 => true,
  43716 => true,
  43717 => true,
  43718 => true,
  43719 => true,
  43720 => true,
  43721 => true,
  43722 => true,
  43723 => true,
  43724 => true,
  43725 => true,
  43726 => true,
  43727 => true,
  43728 => true,
  43729 => true,
  43730 => true,
  43731 => true,
  43732 => true,
  43733 => true,
  43734 => true,
  43735 => true,
  43736 => true,
  43737 => true,
  43738 => true,
  43767 => true,
  43768 => true,
  43769 => true,
  43770 => true,
  43771 => true,
  43772 => true,
  43773 => true,
  43774 => true,
  43775 => true,
  43776 => true,
  43783 => true,
  43784 => true,
  43791 => true,
  43792 => true,
  43799 => true,
  43800 => true,
  43801 => true,
  43802 => true,
  43803 => true,
  43804 => true,
  43805 => true,
  43806 => true,
  43807 => true,
  43815 => true,
  43823 => true,
  43884 => true,
  43885 => true,
  43886 => true,
  43887 => true,
  44014 => true,
  44015 => true,
  44026 => true,
  44027 => true,
  44028 => true,
  44029 => true,
  44030 => true,
  44031 => true,
  55204 => true,
  55205 => true,
  55206 => true,
  55207 => true,
  55208 => true,
  55209 => true,
  55210 => true,
  55211 => true,
  55212 => true,
  55213 => true,
  55214 => true,
  55215 => true,
  55239 => true,
  55240 => true,
  55241 => true,
  55242 => true,
  55292 => true,
  55293 => true,
  55294 => true,
  55295 => true,
  64110 => true,
  64111 => true,
  64263 => true,
  64264 => true,
  64265 => true,
  64266 => true,
  64267 => true,
  64268 => true,
  64269 => true,
  64270 => true,
  64271 => true,
  64272 => true,
  64273 => true,
  64274 => true,
  64280 => true,
  64281 => true,
  64282 => true,
  64283 => true,
  64284 => true,
  64311 => true,
  64317 => true,
  64319 => true,
  64322 => true,
  64325 => true,
  64450 => true,
  64451 => true,
  64452 => true,
  64453 => true,
  64454 => true,
  64455 => true,
  64456 => true,
  64457 => true,
  64458 => true,
  64459 => true,
  64460 => true,
  64461 => true,
  64462 => true,
  64463 => true,
  64464 => true,
  64465 => true,
  64466 => true,
  64832 => true,
  64833 => true,
  64834 => true,
  64835 => true,
  64836 => true,
  64837 => true,
  64838 => true,
  64839 => true,
  64840 => true,
  64841 => true,
  64842 => true,
  64843 => true,
  64844 => true,
  64845 => true,
  64846 => true,
  64847 => true,
  64912 => true,
  64913 => true,
  64968 => true,
  64969 => true,
  64970 => true,
  64971 => true,
  64972 => true,
  64973 => true,
  64974 => true,
  64975 => true,
  65022 => true,
  65023 => true,
  65042 => true,
  65049 => true,
  65050 => true,
  65051 => true,
  65052 => true,
  65053 => true,
  65054 => true,
  65055 => true,
  65072 => true,
  65106 => true,
  65107 => true,
  65127 => true,
  65132 => true,
  65133 => true,
  65134 => true,
  65135 => true,
  65141 => true,
  65277 => true,
  65278 => true,
  65280 => true,
  65440 => true,
  65471 => true,
  65472 => true,
  65473 => true,
  65480 => true,
  65481 => true,
  65488 => true,
  65489 => true,
  65496 => true,
  65497 => true,
  65501 => true,
  65502 => true,
  65503 => true,
  65511 => true,
  65519 => true,
  65520 => true,
  65521 => true,
  65522 => true,
  65523 => true,
  65524 => true,
  65525 => true,
  65526 => true,
  65527 => true,
  65528 => true,
  65529 => true,
  65530 => true,
  65531 => true,
  65532 => true,
  65533 => true,
  65534 => true,
  65535 => true,
  65548 => true,
  65575 => true,
  65595 => true,
  65598 => true,
  65614 => true,
  65615 => true,
  65787 => true,
  65788 => true,
  65789 => true,
  65790 => true,
  65791 => true,
  65795 => true,
  65796 => true,
  65797 => true,
  65798 => true,
  65844 => true,
  65845 => true,
  65846 => true,
  65935 => true,
  65949 => true,
  65950 => true,
  65951 => true,
  66205 => true,
  66206 => true,
  66207 => true,
  66257 => true,
  66258 => true,
  66259 => true,
  66260 => true,
  66261 => true,
  66262 => true,
  66263 => true,
  66264 => true,
  66265 => true,
  66266 => true,
  66267 => true,
  66268 => true,
  66269 => true,
  66270 => true,
  66271 => true,
  66300 => true,
  66301 => true,
  66302 => true,
  66303 => true,
  66340 => true,
  66341 => true,
  66342 => true,
  66343 => true,
  66344 => true,
  66345 => true,
  66346 => true,
  66347 => true,
  66348 => true,
  66379 => true,
  66380 => true,
  66381 => true,
  66382 => true,
  66383 => true,
  66427 => true,
  66428 => true,
  66429 => true,
  66430 => true,
  66431 => true,
  66462 => true,
  66500 => true,
  66501 => true,
  66502 => true,
  66503 => true,
  66718 => true,
  66719 => true,
  66730 => true,
  66731 => true,
  66732 => true,
  66733 => true,
  66734 => true,
  66735 => true,
  66772 => true,
  66773 => true,
  66774 => true,
  66775 => true,
  66812 => true,
  66813 => true,
  66814 => true,
  66815 => true,
  66856 => true,
  66857 => true,
  66858 => true,
  66859 => true,
  66860 => true,
  66861 => true,
  66862 => true,
  66863 => true,
  66916 => true,
  66917 => true,
  66918 => true,
  66919 => true,
  66920 => true,
  66921 => true,
  66922 => true,
  66923 => true,
  66924 => true,
  66925 => true,
  66926 => true,
  67383 => true,
  67384 => true,
  67385 => true,
  67386 => true,
  67387 => true,
  67388 => true,
  67389 => true,
  67390 => true,
  67391 => true,
  67414 => true,
  67415 => true,
  67416 => true,
  67417 => true,
  67418 => true,
  67419 => true,
  67420 => true,
  67421 => true,
  67422 => true,
  67423 => true,
  67590 => true,
  67591 => true,
  67593 => true,
  67638 => true,
  67641 => true,
  67642 => true,
  67643 => true,
  67645 => true,
  67646 => true,
  67670 => true,
  67743 => true,
  67744 => true,
  67745 => true,
  67746 => true,
  67747 => true,
  67748 => true,
  67749 => true,
  67750 => true,
  67827 => true,
  67830 => true,
  67831 => true,
  67832 => true,
  67833 => true,
  67834 => true,
  67868 => true,
  67869 => true,
  67870 => true,
  67898 => true,
  67899 => true,
  67900 => true,
  67901 => true,
  67902 => true,
  68024 => true,
  68025 => true,
  68026 => true,
  68027 => true,
  68048 => true,
  68049 => true,
  68100 => true,
  68103 => true,
  68104 => true,
  68105 => true,
  68106 => true,
  68107 => true,
  68116 => true,
  68120 => true,
  68150 => true,
  68151 => true,
  68155 => true,
  68156 => true,
  68157 => true,
  68158 => true,
  68169 => true,
  68170 => true,
  68171 => true,
  68172 => true,
  68173 => true,
  68174 => true,
  68175 => true,
  68185 => true,
  68186 => true,
  68187 => true,
  68188 => true,
  68189 => true,
  68190 => true,
  68191 => true,
  68327 => true,
  68328 => true,
  68329 => true,
  68330 => true,
  68343 => true,
  68344 => true,
  68345 => true,
  68346 => true,
  68347 => true,
  68348 => true,
  68349 => true,
  68350 => true,
  68351 => true,
  68406 => true,
  68407 => true,
  68408 => true,
  68438 => true,
  68439 => true,
  68467 => true,
  68468 => true,
  68469 => true,
  68470 => true,
  68471 => true,
  68498 => true,
  68499 => true,
  68500 => true,
  68501 => true,
  68502 => true,
  68503 => true,
  68504 => true,
  68509 => true,
  68510 => true,
  68511 => true,
  68512 => true,
  68513 => true,
  68514 => true,
  68515 => true,
  68516 => true,
  68517 => true,
  68518 => true,
  68519 => true,
  68520 => true,
  68787 => true,
  68788 => true,
  68789 => true,
  68790 => true,
  68791 => true,
  68792 => true,
  68793 => true,
  68794 => true,
  68795 => true,
  68796 => true,
  68797 => true,
  68798 => true,
  68799 => true,
  68851 => true,
  68852 => true,
  68853 => true,
  68854 => true,
  68855 => true,
  68856 => true,
  68857 => true,
  68904 => true,
  68905 => true,
  68906 => true,
  68907 => true,
  68908 => true,
  68909 => true,
  68910 => true,
  68911 => true,
  69247 => true,
  69290 => true,
  69294 => true,
  69295 => true,
  69416 => true,
  69417 => true,
  69418 => true,
  69419 => true,
  69420 => true,
  69421 => true,
  69422 => true,
  69423 => true,
  69580 => true,
  69581 => true,
  69582 => true,
  69583 => true,
  69584 => true,
  69585 => true,
  69586 => true,
  69587 => true,
  69588 => true,
  69589 => true,
  69590 => true,
  69591 => true,
  69592 => true,
  69593 => true,
  69594 => true,
  69595 => true,
  69596 => true,
  69597 => true,
  69598 => true,
  69599 => true,
  69623 => true,
  69624 => true,
  69625 => true,
  69626 => true,
  69627 => true,
  69628 => true,
  69629 => true,
  69630 => true,
  69631 => true,
  69710 => true,
  69711 => true,
  69712 => true,
  69713 => true,
  69744 => true,
  69745 => true,
  69746 => true,
  69747 => true,
  69748 => true,
  69749 => true,
  69750 => true,
  69751 => true,
  69752 => true,
  69753 => true,
  69754 => true,
  69755 => true,
  69756 => true,
  69757 => true,
  69758 => true,
  69821 => true,
  69826 => true,
  69827 => true,
  69828 => true,
  69829 => true,
  69830 => true,
  69831 => true,
  69832 => true,
  69833 => true,
  69834 => true,
  69835 => true,
  69836 => true,
  69837 => true,
  69838 => true,
  69839 => true,
  69865 => true,
  69866 => true,
  69867 => true,
  69868 => true,
  69869 => true,
  69870 => true,
  69871 => true,
  69882 => true,
  69883 => true,
  69884 => true,
  69885 => true,
  69886 => true,
  69887 => true,
  69941 => true,
  69960 => true,
  69961 => true,
  69962 => true,
  69963 => true,
  69964 => true,
  69965 => true,
  69966 => true,
  69967 => true,
  70007 => true,
  70008 => true,
  70009 => true,
  70010 => true,
  70011 => true,
  70012 => true,
  70013 => true,
  70014 => true,
  70015 => true,
  70112 => true,
  70133 => true,
  70134 => true,
  70135 => true,
  70136 => true,
  70137 => true,
  70138 => true,
  70139 => true,
  70140 => true,
  70141 => true,
  70142 => true,
  70143 => true,
  70162 => true,
  70279 => true,
  70281 => true,
  70286 => true,
  70302 => true,
  70314 => true,
  70315 => true,
  70316 => true,
  70317 => true,
  70318 => true,
  70319 => true,
  70379 => true,
  70380 => true,
  70381 => true,
  70382 => true,
  70383 => true,
  70394 => true,
  70395 => true,
  70396 => true,
  70397 => true,
  70398 => true,
  70399 => true,
  70404 => true,
  70413 => true,
  70414 => true,
  70417 => true,
  70418 => true,
  70441 => true,
  70449 => true,
  70452 => true,
  70458 => true,
  70469 => true,
  70470 => true,
  70473 => true,
  70474 => true,
  70478 => true,
  70479 => true,
  70481 => true,
  70482 => true,
  70483 => true,
  70484 => true,
  70485 => true,
  70486 => true,
  70488 => true,
  70489 => true,
  70490 => true,
  70491 => true,
  70492 => true,
  70500 => true,
  70501 => true,
  70509 => true,
  70510 => true,
  70511 => true,
  70748 => true,
  70754 => true,
  70755 => true,
  70756 => true,
  70757 => true,
  70758 => true,
  70759 => true,
  70760 => true,
  70761 => true,
  70762 => true,
  70763 => true,
  70764 => true,
  70765 => true,
  70766 => true,
  70767 => true,
  70768 => true,
  70769 => true,
  70770 => true,
  70771 => true,
  70772 => true,
  70773 => true,
  70774 => true,
  70775 => true,
  70776 => true,
  70777 => true,
  70778 => true,
  70779 => true,
  70780 => true,
  70781 => true,
  70782 => true,
  70783 => true,
  70856 => true,
  70857 => true,
  70858 => true,
  70859 => true,
  70860 => true,
  70861 => true,
  70862 => true,
  70863 => true,
  71094 => true,
  71095 => true,
  71237 => true,
  71238 => true,
  71239 => true,
  71240 => true,
  71241 => true,
  71242 => true,
  71243 => true,
  71244 => true,
  71245 => true,
  71246 => true,
  71247 => true,
  71258 => true,
  71259 => true,
  71260 => true,
  71261 => true,
  71262 => true,
  71263 => true,
  71277 => true,
  71278 => true,
  71279 => true,
  71280 => true,
  71281 => true,
  71282 => true,
  71283 => true,
  71284 => true,
  71285 => true,
  71286 => true,
  71287 => true,
  71288 => true,
  71289 => true,
  71290 => true,
  71291 => true,
  71292 => true,
  71293 => true,
  71294 => true,
  71295 => true,
  71353 => true,
  71354 => true,
  71355 => true,
  71356 => true,
  71357 => true,
  71358 => true,
  71359 => true,
  71451 => true,
  71452 => true,
  71468 => true,
  71469 => true,
  71470 => true,
  71471 => true,
  71923 => true,
  71924 => true,
  71925 => true,
  71926 => true,
  71927 => true,
  71928 => true,
  71929 => true,
  71930 => true,
  71931 => true,
  71932 => true,
  71933 => true,
  71934 => true,
  71943 => true,
  71944 => true,
  71946 => true,
  71947 => true,
  71956 => true,
  71959 => true,
  71990 => true,
  71993 => true,
  71994 => true,
  72007 => true,
  72008 => true,
  72009 => true,
  72010 => true,
  72011 => true,
  72012 => true,
  72013 => true,
  72014 => true,
  72015 => true,
  72104 => true,
  72105 => true,
  72152 => true,
  72153 => true,
  72165 => true,
  72166 => true,
  72167 => true,
  72168 => true,
  72169 => true,
  72170 => true,
  72171 => true,
  72172 => true,
  72173 => true,
  72174 => true,
  72175 => true,
  72176 => true,
  72177 => true,
  72178 => true,
  72179 => true,
  72180 => true,
  72181 => true,
  72182 => true,
  72183 => true,
  72184 => true,
  72185 => true,
  72186 => true,
  72187 => true,
  72188 => true,
  72189 => true,
  72190 => true,
  72191 => true,
  72264 => true,
  72265 => true,
  72266 => true,
  72267 => true,
  72268 => true,
  72269 => true,
  72270 => true,
  72271 => true,
  72355 => true,
  72356 => true,
  72357 => true,
  72358 => true,
  72359 => true,
  72360 => true,
  72361 => true,
  72362 => true,
  72363 => true,
  72364 => true,
  72365 => true,
  72366 => true,
  72367 => true,
  72368 => true,
  72369 => true,
  72370 => true,
  72371 => true,
  72372 => true,
  72373 => true,
  72374 => true,
  72375 => true,
  72376 => true,
  72377 => true,
  72378 => true,
  72379 => true,
  72380 => true,
  72381 => true,
  72382 => true,
  72383 => true,
  72713 => true,
  72759 => true,
  72774 => true,
  72775 => true,
  72776 => true,
  72777 => true,
  72778 => true,
  72779 => true,
  72780 => true,
  72781 => true,
  72782 => true,
  72783 => true,
  72813 => true,
  72814 => true,
  72815 => true,
  72848 => true,
  72849 => true,
  72872 => true,
  72967 => true,
  72970 => true,
  73015 => true,
  73016 => true,
  73017 => true,
  73019 => true,
  73022 => true,
  73032 => true,
  73033 => true,
  73034 => true,
  73035 => true,
  73036 => true,
  73037 => true,
  73038 => true,
  73039 => true,
  73050 => true,
  73051 => true,
  73052 => true,
  73053 => true,
  73054 => true,
  73055 => true,
  73062 => true,
  73065 => true,
  73103 => true,
  73106 => true,
  73113 => true,
  73114 => true,
  73115 => true,
  73116 => true,
  73117 => true,
  73118 => true,
  73119 => true,
  73649 => true,
  73650 => true,
  73651 => true,
  73652 => true,
  73653 => true,
  73654 => true,
  73655 => true,
  73656 => true,
  73657 => true,
  73658 => true,
  73659 => true,
  73660 => true,
  73661 => true,
  73662 => true,
  73663 => true,
  73714 => true,
  73715 => true,
  73716 => true,
  73717 => true,
  73718 => true,
  73719 => true,
  73720 => true,
  73721 => true,
  73722 => true,
  73723 => true,
  73724 => true,
  73725 => true,
  73726 => true,
  74863 => true,
  74869 => true,
  74870 => true,
  74871 => true,
  74872 => true,
  74873 => true,
  74874 => true,
  74875 => true,
  74876 => true,
  74877 => true,
  74878 => true,
  74879 => true,
  78895 => true,
  78896 => true,
  78897 => true,
  78898 => true,
  78899 => true,
  78900 => true,
  78901 => true,
  78902 => true,
  78903 => true,
  78904 => true,
  92729 => true,
  92730 => true,
  92731 => true,
  92732 => true,
  92733 => true,
  92734 => true,
  92735 => true,
  92767 => true,
  92778 => true,
  92779 => true,
  92780 => true,
  92781 => true,
  92910 => true,
  92911 => true,
  92918 => true,
  92919 => true,
  92920 => true,
  92921 => true,
  92922 => true,
  92923 => true,
  92924 => true,
  92925 => true,
  92926 => true,
  92927 => true,
  92998 => true,
  92999 => true,
  93000 => true,
  93001 => true,
  93002 => true,
  93003 => true,
  93004 => true,
  93005 => true,
  93006 => true,
  93007 => true,
  93018 => true,
  93026 => true,
  93048 => true,
  93049 => true,
  93050 => true,
  93051 => true,
  93052 => true,
  94027 => true,
  94028 => true,
  94029 => true,
  94030 => true,
  94088 => true,
  94089 => true,
  94090 => true,
  94091 => true,
  94092 => true,
  94093 => true,
  94094 => true,
  94181 => true,
  94182 => true,
  94183 => true,
  94184 => true,
  94185 => true,
  94186 => true,
  94187 => true,
  94188 => true,
  94189 => true,
  94190 => true,
  94191 => true,
  94194 => true,
  94195 => true,
  94196 => true,
  94197 => true,
  94198 => true,
  94199 => true,
  94200 => true,
  94201 => true,
  94202 => true,
  94203 => true,
  94204 => true,
  94205 => true,
  94206 => true,
  94207 => true,
  100344 => true,
  100345 => true,
  100346 => true,
  100347 => true,
  100348 => true,
  100349 => true,
  100350 => true,
  100351 => true,
  110931 => true,
  110932 => true,
  110933 => true,
  110934 => true,
  110935 => true,
  110936 => true,
  110937 => true,
  110938 => true,
  110939 => true,
  110940 => true,
  110941 => true,
  110942 => true,
  110943 => true,
  110944 => true,
  110945 => true,
  110946 => true,
  110947 => true,
  110952 => true,
  110953 => true,
  110954 => true,
  110955 => true,
  110956 => true,
  110957 => true,
  110958 => true,
  110959 => true,
  113771 => true,
  113772 => true,
  113773 => true,
  113774 => true,
  113775 => true,
  113789 => true,
  113790 => true,
  113791 => true,
  113801 => true,
  113802 => true,
  113803 => true,
  113804 => true,
  113805 => true,
  113806 => true,
  113807 => true,
  113818 => true,
  113819 => true,
  119030 => true,
  119031 => true,
  119032 => true,
  119033 => true,
  119034 => true,
  119035 => true,
  119036 => true,
  119037 => true,
  119038 => true,
  119039 => true,
  119079 => true,
  119080 => true,
  119155 => true,
  119156 => true,
  119157 => true,
  119158 => true,
  119159 => true,
  119160 => true,
  119161 => true,
  119162 => true,
  119273 => true,
  119274 => true,
  119275 => true,
  119276 => true,
  119277 => true,
  119278 => true,
  119279 => true,
  119280 => true,
  119281 => true,
  119282 => true,
  119283 => true,
  119284 => true,
  119285 => true,
  119286 => true,
  119287 => true,
  119288 => true,
  119289 => true,
  119290 => true,
  119291 => true,
  119292 => true,
  119293 => true,
  119294 => true,
  119295 => true,
  119540 => true,
  119541 => true,
  119542 => true,
  119543 => true,
  119544 => true,
  119545 => true,
  119546 => true,
  119547 => true,
  119548 => true,
  119549 => true,
  119550 => true,
  119551 => true,
  119639 => true,
  119640 => true,
  119641 => true,
  119642 => true,
  119643 => true,
  119644 => true,
  119645 => true,
  119646 => true,
  119647 => true,
  119893 => true,
  119965 => true,
  119968 => true,
  119969 => true,
  119971 => true,
  119972 => true,
  119975 => true,
  119976 => true,
  119981 => true,
  119994 => true,
  119996 => true,
  120004 => true,
  120070 => true,
  120075 => true,
  120076 => true,
  120085 => true,
  120093 => true,
  120122 => true,
  120127 => true,
  120133 => true,
  120135 => true,
  120136 => true,
  120137 => true,
  120145 => true,
  120486 => true,
  120487 => true,
  120780 => true,
  120781 => true,
  121484 => true,
  121485 => true,
  121486 => true,
  121487 => true,
  121488 => true,
  121489 => true,
  121490 => true,
  121491 => true,
  121492 => true,
  121493 => true,
  121494 => true,
  121495 => true,
  121496 => true,
  121497 => true,
  121498 => true,
  121504 => true,
  122887 => true,
  122905 => true,
  122906 => true,
  122914 => true,
  122917 => true,
  123181 => true,
  123182 => true,
  123183 => true,
  123198 => true,
  123199 => true,
  123210 => true,
  123211 => true,
  123212 => true,
  123213 => true,
  123642 => true,
  123643 => true,
  123644 => true,
  123645 => true,
  123646 => true,
  125125 => true,
  125126 => true,
  125260 => true,
  125261 => true,
  125262 => true,
  125263 => true,
  125274 => true,
  125275 => true,
  125276 => true,
  125277 => true,
  126468 => true,
  126496 => true,
  126499 => true,
  126501 => true,
  126502 => true,
  126504 => true,
  126515 => true,
  126520 => true,
  126522 => true,
  126524 => true,
  126525 => true,
  126526 => true,
  126527 => true,
  126528 => true,
  126529 => true,
  126531 => true,
  126532 => true,
  126533 => true,
  126534 => true,
  126536 => true,
  126538 => true,
  126540 => true,
  126544 => true,
  126547 => true,
  126549 => true,
  126550 => true,
  126552 => true,
  126554 => true,
  126556 => true,
  126558 => true,
  126560 => true,
  126563 => true,
  126565 => true,
  126566 => true,
  126571 => true,
  126579 => true,
  126584 => true,
  126589 => true,
  126591 => true,
  126602 => true,
  126620 => true,
  126621 => true,
  126622 => true,
  126623 => true,
  126624 => true,
  126628 => true,
  126634 => true,
  127020 => true,
  127021 => true,
  127022 => true,
  127023 => true,
  127124 => true,
  127125 => true,
  127126 => true,
  127127 => true,
  127128 => true,
  127129 => true,
  127130 => true,
  127131 => true,
  127132 => true,
  127133 => true,
  127134 => true,
  127135 => true,
  127151 => true,
  127152 => true,
  127168 => true,
  127184 => true,
  127222 => true,
  127223 => true,
  127224 => true,
  127225 => true,
  127226 => true,
  127227 => true,
  127228 => true,
  127229 => true,
  127230 => true,
  127231 => true,
  127232 => true,
  127491 => true,
  127492 => true,
  127493 => true,
  127494 => true,
  127495 => true,
  127496 => true,
  127497 => true,
  127498 => true,
  127499 => true,
  127500 => true,
  127501 => true,
  127502 => true,
  127503 => true,
  127548 => true,
  127549 => true,
  127550 => true,
  127551 => true,
  127561 => true,
  127562 => true,
  127563 => true,
  127564 => true,
  127565 => true,
  127566 => true,
  127567 => true,
  127570 => true,
  127571 => true,
  127572 => true,
  127573 => true,
  127574 => true,
  127575 => true,
  127576 => true,
  127577 => true,
  127578 => true,
  127579 => true,
  127580 => true,
  127581 => true,
  127582 => true,
  127583 => true,
  128728 => true,
  128729 => true,
  128730 => true,
  128731 => true,
  128732 => true,
  128733 => true,
  128734 => true,
  128735 => true,
  128749 => true,
  128750 => true,
  128751 => true,
  128765 => true,
  128766 => true,
  128767 => true,
  128884 => true,
  128885 => true,
  128886 => true,
  128887 => true,
  128888 => true,
  128889 => true,
  128890 => true,
  128891 => true,
  128892 => true,
  128893 => true,
  128894 => true,
  128895 => true,
  128985 => true,
  128986 => true,
  128987 => true,
  128988 => true,
  128989 => true,
  128990 => true,
  128991 => true,
  129004 => true,
  129005 => true,
  129006 => true,
  129007 => true,
  129008 => true,
  129009 => true,
  129010 => true,
  129011 => true,
  129012 => true,
  129013 => true,
  129014 => true,
  129015 => true,
  129016 => true,
  129017 => true,
  129018 => true,
  129019 => true,
  129020 => true,
  129021 => true,
  129022 => true,
  129023 => true,
  129036 => true,
  129037 => true,
  129038 => true,
  129039 => true,
  129096 => true,
  129097 => true,
  129098 => true,
  129099 => true,
  129100 => true,
  129101 => true,
  129102 => true,
  129103 => true,
  129114 => true,
  129115 => true,
  129116 => true,
  129117 => true,
  129118 => true,
  129119 => true,
  129160 => true,
  129161 => true,
  129162 => true,
  129163 => true,
  129164 => true,
  129165 => true,
  129166 => true,
  129167 => true,
  129198 => true,
  129199 => true,
  129401 => true,
  129484 => true,
  129620 => true,
  129621 => true,
  129622 => true,
  129623 => true,
  129624 => true,
  129625 => true,
  129626 => true,
  129627 => true,
  129628 => true,
  129629 => true,
  129630 => true,
  129631 => true,
  129646 => true,
  129647 => true,
  129653 => true,
  129654 => true,
  129655 => true,
  129659 => true,
  129660 => true,
  129661 => true,
  129662 => true,
  129663 => true,
  129671 => true,
  129672 => true,
  129673 => true,
  129674 => true,
  129675 => true,
  129676 => true,
  129677 => true,
  129678 => true,
  129679 => true,
  129705 => true,
  129706 => true,
  129707 => true,
  129708 => true,
  129709 => true,
  129710 => true,
  129711 => true,
  129719 => true,
  129720 => true,
  129721 => true,
  129722 => true,
  129723 => true,
  129724 => true,
  129725 => true,
  129726 => true,
  129727 => true,
  129731 => true,
  129732 => true,
  129733 => true,
  129734 => true,
  129735 => true,
  129736 => true,
  129737 => true,
  129738 => true,
  129739 => true,
  129740 => true,
  129741 => true,
  129742 => true,
  129743 => true,
  129939 => true,
  131070 => true,
  131071 => true,
  177973 => true,
  177974 => true,
  177975 => true,
  177976 => true,
  177977 => true,
  177978 => true,
  177979 => true,
  177980 => true,
  177981 => true,
  177982 => true,
  177983 => true,
  178206 => true,
  178207 => true,
  183970 => true,
  183971 => true,
  183972 => true,
  183973 => true,
  183974 => true,
  183975 => true,
  183976 => true,
  183977 => true,
  183978 => true,
  183979 => true,
  183980 => true,
  183981 => true,
  183982 => true,
  183983 => true,
  194664 => true,
  194676 => true,
  194847 => true,
  194911 => true,
  195007 => true,
  196606 => true,
  196607 => true,
  262142 => true,
  262143 => true,
  327678 => true,
  327679 => true,
  393214 => true,
  393215 => true,
  458750 => true,
  458751 => true,
  524286 => true,
  524287 => true,
  589822 => true,
  589823 => true,
  655358 => true,
  655359 => true,
  720894 => true,
  720895 => true,
  786430 => true,
  786431 => true,
  851966 => true,
  851967 => true,
  917502 => true,
  917503 => true,
  917504 => true,
  917505 => true,
  917506 => true,
  917507 => true,
  917508 => true,
  917509 => true,
  917510 => true,
  917511 => true,
  917512 => true,
  917513 => true,
  917514 => true,
  917515 => true,
  917516 => true,
  917517 => true,
  917518 => true,
  917519 => true,
  917520 => true,
  917521 => true,
  917522 => true,
  917523 => true,
  917524 => true,
  917525 => true,
  917526 => true,
  917527 => true,
  917528 => true,
  917529 => true,
  917530 => true,
  917531 => true,
  917532 => true,
  917533 => true,
  917534 => true,
  917535 => true,
  983038 => true,
  983039 => true,
  1048574 => true,
  1048575 => true,
  1114110 => true,
  1114111 => true,
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;

/**
 * @internal
 */
final class DisallowedRanges
{
    /**
     * @param int $codePoint
     *
     * @return bool
     */
    public static function inRange($codePoint)
    {
        if ($codePoint >= 128 && $codePoint <= 159) {
            return true;
        }

        if ($codePoint >= 2155 && $codePoint <= 2207) {
            return true;
        }

        if ($codePoint >= 3676 && $codePoint <= 3712) {
            return true;
        }

        if ($codePoint >= 3808 && $codePoint <= 3839) {
            return true;
        }

        if ($codePoint >= 4059 && $codePoint <= 4095) {
            return true;
        }

        if ($codePoint >= 4256 && $codePoint <= 4293) {
            return true;
        }

        if ($codePoint >= 6849 && $codePoint <= 6911) {
            return true;
        }

        if ($codePoint >= 11859 && $codePoint <= 11903) {
            return true;
        }

        if ($codePoint >= 42955 && $codePoint <= 42996) {
            return true;
        }

        if ($codePoint >= 55296 && $codePoint <= 57343) {
            return true;
        }

        if ($codePoint >= 57344 && $codePoint <= 63743) {
            return true;
        }

        if ($codePoint >= 64218 && $codePoint <= 64255) {
            return true;
        }

        if ($codePoint >= 64976 && $codePoint <= 65007) {
            return true;
        }

        if ($codePoint >= 65630 && $codePoint <= 65663) {
            return true;
        }

        if ($codePoint >= 65953 && $codePoint <= 65999) {
            return true;
        }

        if ($codePoint >= 66046 && $codePoint <= 66175) {
            return true;
        }

        if ($codePoint >= 66518 && $codePoint <= 66559) {
            return true;
        }

        if ($codePoint >= 66928 && $codePoint <= 67071) {
            return true;
        }

        if ($codePoint >= 67432 && $codePoint <= 67583) {
            return true;
        }

        if ($codePoint >= 67760 && $codePoint <= 67807) {
            return true;
        }

        if ($codePoint >= 67904 && $codePoint <= 67967) {
            return true;
        }

        if ($codePoint >= 68256 && $codePoint <= 68287) {
            return true;
        }

        if ($codePoint >= 68528 && $codePoint <= 68607) {
            return true;
        }

        if ($codePoint >= 68681 && $codePoint <= 68735) {
            return true;
        }

        if ($codePoint >= 68922 && $codePoint <= 69215) {
            return true;
        }

        if ($codePoint >= 69298 && $codePoint <= 69375) {
            return true;
        }

        if ($codePoint >= 69466 && $codePoint <= 69551) {
            return true;
        }

        if ($codePoint >= 70207 && $codePoint <= 70271) {
            return true;
        }

        if ($codePoint >= 70517 && $codePoint <= 70655) {
            return true;
        }

        if ($codePoint >= 70874 && $codePoint <= 71039) {
            return true;
        }

        if ($codePoint >= 71134 && $codePoint <= 71167) {
            return true;
        }

        if ($codePoint >= 71370 && $codePoint <= 71423) {
            return true;
        }

        if ($codePoint >= 71488 && $codePoint <= 71679) {
            return true;
        }

        if ($codePoint >= 71740 && $codePoint <= 71839) {
            return true;
        }

        if ($codePoint >= 72026 && $codePoint <= 72095) {
            return true;
        }

        if ($codePoint >= 72441 && $codePoint <= 72703) {
            return true;
        }

        if ($codePoint >= 72887 && $codePoint <= 72959) {
            return true;
        }

        if ($codePoint >= 73130 && $codePoint <= 73439) {
            return true;
        }

        if ($codePoint >= 73465 && $codePoint <= 73647) {
            return true;
        }

        if ($codePoint >= 74650 && $codePoint <= 74751) {
            return true;
        }

        if ($codePoint >= 75076 && $codePoint <= 77823) {
            return true;
        }

        if ($codePoint >= 78905 && $codePoint <= 82943) {
            return true;
        }

        if ($codePoint >= 83527 && $codePoint <= 92159) {
            return true;
        }

        if ($codePoint >= 92784 && $codePoint <= 92879) {
            return true;
        }

        if ($codePoint >= 93072 && $codePoint <= 93759) {
            return true;
        }

        if ($codePoint >= 93851 && $codePoint <= 93951) {
            return true;
        }

        if ($codePoint >= 94112 && $codePoint <= 94175) {
            return true;
        }

        if ($codePoint >= 101590 && $codePoint <= 101631) {
            return true;
        }

        if ($codePoint >= 101641 && $codePoint <= 110591) {
            return true;
        }

        if ($codePoint >= 110879 && $codePoint <= 110927) {
            return true;
        }

        if ($codePoint >= 111356 && $codePoint <= 113663) {
            return true;
        }

        if ($codePoint >= 113828 && $codePoint <= 118783) {
            return true;
        }

        if ($codePoint >= 119366 && $codePoint <= 119519) {
            return true;
        }

        if ($codePoint >= 119673 && $codePoint <= 119807) {
            return true;
        }

        if ($codePoint >= 121520 && $codePoint <= 122879) {
            return true;
        }

        if ($codePoint >= 122923 && $codePoint <= 123135) {
            return true;
        }

        if ($codePoint >= 123216 && $codePoint <= 123583) {
            return true;
        }

        if ($codePoint >= 123648 && $codePoint <= 124927) {
            return true;
        }

        if ($codePoint >= 125143 && $codePoint <= 125183) {
            return true;
        }

        if ($codePoint >= 125280 && $codePoint <= 126064) {
            return true;
        }

        if ($codePoint >= 126133 && $codePoint <= 126208) {
            return true;
        }

        if ($codePoint >= 126270 && $codePoint <= 126463) {
            return true;
        }

        if ($codePoint >= 126652 && $codePoint <= 126703) {
            return true;
        }

        if ($codePoint >= 126706 && $codePoint <= 126975) {
            return true;
        }

        if ($codePoint >= 127406 && $codePoint <= 127461) {
            return true;
        }

        if ($codePoint >= 127590 && $codePoint <= 127743) {
            return true;
        }

        if ($codePoint >= 129202 && $codePoint <= 129279) {
            return true;
        }

        if ($codePoint >= 129751 && $codePoint <= 129791) {
            return true;
        }

        if ($codePoint >= 129995 && $codePoint <= 130031) {
            return true;
        }

        if ($codePoint >= 130042 && $codePoint <= 131069) {
            return true;
        }

        if ($codePoint >= 173790 && $codePoint <= 173823) {
            return true;
        }

        if ($codePoint >= 191457 && $codePoint <= 194559) {
            return true;
        }

        if ($codePoint >= 195102 && $codePoint <= 196605) {
            return true;
        }

        if ($codePoint >= 201547 && $codePoint <= 262141) {
            return true;
        }

        if ($codePoint >= 262144 && $codePoint <= 327677) {
            return true;
        }

        if ($codePoint >= 327680 && $codePoint <= 393213) {
            return true;
        }

        if ($codePoint >= 393216 && $codePoint <= 458749) {
            return true;
        }

        if ($codePoint >= 458752 && $codePoint <= 524285) {
            return true;
        }

        if ($codePoint >= 524288 && $codePoint <= 589821) {
            return true;
        }

        if ($codePoint >= 589824 && $codePoint <= 655357) {
            return true;
        }

        if ($codePoint >= 655360 && $codePoint <= 720893) {
            return true;
        }

        if ($codePoint >= 720896 && $codePoint <= 786429) {
            return true;
        }

        if ($codePoint >= 786432 && $codePoint <= 851965) {
            return true;
        }

        if ($codePoint >= 851968 && $codePoint <= 917501) {
            return true;
        }

        if ($codePoint >= 917536 && $codePoint <= 917631) {
            return true;
        }

        if ($codePoint >= 917632 && $codePoint <= 917759) {
            return true;
        }

        if ($codePoint >= 918000 && $codePoint <= 983037) {
            return true;
        }

        if ($codePoint >= 983040 && $codePoint <= 1048573) {
            return true;
        }

        if ($codePoint >= 1048576 && $codePoint <= 1114109) {
            return true;
        }

        return false;
    }
}
<?php

return array (
  160 => ' ',
  168 => ' ̈',
  175 => ' ̄',
  180 => ' ́',
  184 => ' ̧',
  728 => ' ̆',
  729 => ' ̇',
  730 => ' ̊',
  731 => ' ̨',
  732 => ' ̃',
  733 => ' ̋',
  890 => ' ι',
  894 => ';',
  900 => ' ́',
  901 => ' ̈́',
  8125 => ' ̓',
  8127 => ' ̓',
  8128 => ' ͂',
  8129 => ' ̈͂',
  8141 => ' ̓̀',
  8142 => ' ̓́',
  8143 => ' ̓͂',
  8157 => ' ̔̀',
  8158 => ' ̔́',
  8159 => ' ̔͂',
  8173 => ' ̈̀',
  8174 => ' ̈́',
  8175 => '`',
  8189 => ' ́',
  8190 => ' ̔',
  8192 => ' ',
  8193 => ' ',
  8194 => ' ',
  8195 => ' ',
  8196 => ' ',
  8197 => ' ',
  8198 => ' ',
  8199 => ' ',
  8200 => ' ',
  8201 => ' ',
  8202 => ' ',
  8215 => ' ̳',
  8239 => ' ',
  8252 => '!!',
  8254 => ' ̅',
  8263 => '??',
  8264 => '?!',
  8265 => '!?',
  8287 => ' ',
  8314 => '+',
  8316 => '=',
  8317 => '(',
  8318 => ')',
  8330 => '+',
  8332 => '=',
  8333 => '(',
  8334 => ')',
  8448 => 'a/c',
  8449 => 'a/s',
  8453 => 'c/o',
  8454 => 'c/u',
  9332 => '(1)',
  9333 => '(2)',
  9334 => '(3)',
  9335 => '(4)',
  9336 => '(5)',
  9337 => '(6)',
  9338 => '(7)',
  9339 => '(8)',
  9340 => '(9)',
  9341 => '(10)',
  9342 => '(11)',
  9343 => '(12)',
  9344 => '(13)',
  9345 => '(14)',
  9346 => '(15)',
  9347 => '(16)',
  9348 => '(17)',
  9349 => '(18)',
  9350 => '(19)',
  9351 => '(20)',
  9372 => '(a)',
  9373 => '(b)',
  9374 => '(c)',
  9375 => '(d)',
  9376 => '(e)',
  9377 => '(f)',
  9378 => '(g)',
  9379 => '(h)',
  9380 => '(i)',
  9381 => '(j)',
  9382 => '(k)',
  9383 => '(l)',
  9384 => '(m)',
  9385 => '(n)',
  9386 => '(o)',
  9387 => '(p)',
  9388 => '(q)',
  9389 => '(r)',
  9390 => '(s)',
  9391 => '(t)',
  9392 => '(u)',
  9393 => '(v)',
  9394 => '(w)',
  9395 => '(x)',
  9396 => '(y)',
  9397 => '(z)',
  10868 => '::=',
  10869 => '==',
  10870 => '===',
  12288 => ' ',
  12443 => ' ゙',
  12444 => ' ゚',
  12800 => '(ᄀ)',
  12801 => '(ᄂ)',
  12802 => '(ᄃ)',
  12803 => '(ᄅ)',
  12804 => '(ᄆ)',
  12805 => '(ᄇ)',
  12806 => '(ᄉ)',
  12807 => '(ᄋ)',
  12808 => '(ᄌ)',
  12809 => '(ᄎ)',
  12810 => '(ᄏ)',
  12811 => '(ᄐ)',
  12812 => '(ᄑ)',
  12813 => '(ᄒ)',
  12814 => '(가)',
  12815 => '(나)',
  12816 => '(다)',
  12817 => '(라)',
  12818 => '(마)',
  12819 => '(바)',
  12820 => '(사)',
  12821 => '(아)',
  12822 => '(자)',
  12823 => '(차)',
  12824 => '(카)',
  12825 => '(타)',
  12826 => '(파)',
  12827 => '(하)',
  12828 => '(주)',
  12829 => '(오전)',
  12830 => '(오후)',
  12832 => '(一)',
  12833 => '(二)',
  12834 => '(三)',
  12835 => '(四)',
  12836 => '(五)',
  12837 => '(六)',
  12838 => '(七)',
  12839 => '(八)',
  12840 => '(九)',
  12841 => '(十)',
  12842 => '(月)',
  12843 => '(火)',
  12844 => '(水)',
  12845 => '(木)',
  12846 => '(金)',
  12847 => '(土)',
  12848 => '(日)',
  12849 => '(株)',
  12850 => '(有)',
  12851 => '(社)',
  12852 => '(名)',
  12853 => '(特)',
  12854 => '(財)',
  12855 => '(祝)',
  12856 => '(労)',
  12857 => '(代)',
  12858 => '(呼)',
  12859 => '(学)',
  12860 => '(監)',
  12861 => '(企)',
  12862 => '(資)',
  12863 => '(協)',
  12864 => '(祭)',
  12865 => '(休)',
  12866 => '(自)',
  12867 => '(至)',
  64297 => '+',
  64606 => ' ٌّ',
  64607 => ' ٍّ',
  64608 => ' َّ',
  64609 => ' ُّ',
  64610 => ' ِّ',
  64611 => ' ّٰ',
  65018 => 'صلى الله عليه وسلم',
  65019 => 'جل جلاله',
  65040 => ',',
  65043 => ':',
  65044 => ';',
  65045 => '!',
  65046 => '?',
  65075 => '_',
  65076 => '_',
  65077 => '(',
  65078 => ')',
  65079 => '{',
  65080 => '}',
  65095 => '[',
  65096 => ']',
  65097 => ' ̅',
  65098 => ' ̅',
  65099 => ' ̅',
  65100 => ' ̅',
  65101 => '_',
  65102 => '_',
  65103 => '_',
  65104 => ',',
  65108 => ';',
  65109 => ':',
  65110 => '?',
  65111 => '!',
  65113 => '(',
  65114 => ')',
  65115 => '{',
  65116 => '}',
  65119 => '#',
  65120 => '&',
  65121 => '*',
  65122 => '+',
  65124 => '<',
  65125 => '>',
  65126 => '=',
  65128 => '\\',
  65129 => '$',
  65130 => '%',
  65131 => '@',
  65136 => ' ً',
  65138 => ' ٌ',
  65140 => ' ٍ',
  65142 => ' َ',
  65144 => ' ُ',
  65146 => ' ِ',
  65148 => ' ّ',
  65150 => ' ْ',
  65281 => '!',
  65282 => '"',
  65283 => '#',
  65284 => '$',
  65285 => '%',
  65286 => '&',
  65287 => '\'',
  65288 => '(',
  65289 => ')',
  65290 => '*',
  65291 => '+',
  65292 => ',',
  65295 => '/',
  65306 => ':',
  65307 => ';',
  65308 => '<',
  65309 => '=',
  65310 => '>',
  65311 => '?',
  65312 => '@',
  65339 => '[',
  65340 => '\\',
  65341 => ']',
  65342 => '^',
  65343 => '_',
  65344 => '`',
  65371 => '{',
  65372 => '|',
  65373 => '}',
  65374 => '~',
  65507 => ' ̄',
  127233 => '0,',
  127234 => '1,',
  127235 => '2,',
  127236 => '3,',
  127237 => '4,',
  127238 => '5,',
  127239 => '6,',
  127240 => '7,',
  127241 => '8,',
  127242 => '9,',
  127248 => '(a)',
  127249 => '(b)',
  127250 => '(c)',
  127251 => '(d)',
  127252 => '(e)',
  127253 => '(f)',
  127254 => '(g)',
  127255 => '(h)',
  127256 => '(i)',
  127257 => '(j)',
  127258 => '(k)',
  127259 => '(l)',
  127260 => '(m)',
  127261 => '(n)',
  127262 => '(o)',
  127263 => '(p)',
  127264 => '(q)',
  127265 => '(r)',
  127266 => '(s)',
  127267 => '(t)',
  127268 => '(u)',
  127269 => '(v)',
  127270 => '(w)',
  127271 => '(x)',
  127272 => '(y)',
  127273 => '(z)',
);
<?php

return array (
  0 => true,
  1 => true,
  2 => true,
  3 => true,
  4 => true,
  5 => true,
  6 => true,
  7 => true,
  8 => true,
  9 => true,
  10 => true,
  11 => true,
  12 => true,
  13 => true,
  14 => true,
  15 => true,
  16 => true,
  17 => true,
  18 => true,
  19 => true,
  20 => true,
  21 => true,
  22 => true,
  23 => true,
  24 => true,
  25 => true,
  26 => true,
  27 => true,
  28 => true,
  29 => true,
  30 => true,
  31 => true,
  32 => true,
  33 => true,
  34 => true,
  35 => true,
  36 => true,
  37 => true,
  38 => true,
  39 => true,
  40 => true,
  41 => true,
  42 => true,
  43 => true,
  44 => true,
  47 => true,
  58 => true,
  59 => true,
  60 => true,
  61 => true,
  62 => true,
  63 => true,
  64 => true,
  91 => true,
  92 => true,
  93 => true,
  94 => true,
  95 => true,
  96 => true,
  123 => true,
  124 => true,
  125 => true,
  126 => true,
  127 => true,
  8800 => true,
  8814 => true,
  8815 => true,
);
<?php

return array (
  173 => true,
  847 => true,
  6155 => true,
  6156 => true,
  6157 => true,
  8203 => true,
  8288 => true,
  8292 => true,
  65024 => true,
  65025 => true,
  65026 => true,
  65027 => true,
  65028 => true,
  65029 => true,
  65030 => true,
  65031 => true,
  65032 => true,
  65033 => true,
  65034 => true,
  65035 => true,
  65036 => true,
  65037 => true,
  65038 => true,
  65039 => true,
  65279 => true,
  113824 => true,
  113825 => true,
  113826 => true,
  113827 => true,
  917760 => true,
  917761 => true,
  917762 => true,
  917763 => true,
  917764 => true,
  917765 => true,
  917766 => true,
  917767 => true,
  917768 => true,
  917769 => true,
  917770 => true,
  917771 => true,
  917772 => true,
  917773 => true,
  917774 => true,
  917775 => true,
  917776 => true,
  917777 => true,
  917778 => true,
  917779 => true,
  917780 => true,
  917781 => true,
  917782 => true,
  917783 => true,
  917784 => true,
  917785 => true,
  917786 => true,
  917787 => true,
  917788 => true,
  917789 => true,
  917790 => true,
  917791 => true,
  917792 => true,
  917793 => true,
  917794 => true,
  917795 => true,
  917796 => true,
  917797 => true,
  917798 => true,
  917799 => true,
  917800 => true,
  917801 => true,
  917802 => true,
  917803 => true,
  917804 => true,
  917805 => true,
  917806 => true,
  917807 => true,
  917808 => true,
  917809 => true,
  917810 => true,
  917811 => true,
  917812 => true,
  917813 => true,
  917814 => true,
  917815 => true,
  917816 => true,
  917817 => true,
  917818 => true,
  917819 => true,
  917820 => true,
  917821 => true,
  917822 => true,
  917823 => true,
  917824 => true,
  917825 => true,
  917826 => true,
  917827 => true,
  917828 => true,
  917829 => true,
  917830 => true,
  917831 => true,
  917832 => true,
  917833 => true,
  917834 => true,
  917835 => true,
  917836 => true,
  917837 => true,
  917838 => true,
  917839 => true,
  917840 => true,
  917841 => true,
  917842 => true,
  917843 => true,
  917844 => true,
  917845 => true,
  917846 => true,
  917847 => true,
  917848 => true,
  917849 => true,
  917850 => true,
  917851 => true,
  917852 => true,
  917853 => true,
  917854 => true,
  917855 => true,
  917856 => true,
  917857 => true,
  917858 => true,
  917859 => true,
  917860 => true,
  917861 => true,
  917862 => true,
  917863 => true,
  917864 => true,
  917865 => true,
  917866 => true,
  917867 => true,
  917868 => true,
  917869 => true,
  917870 => true,
  917871 => true,
  917872 => true,
  917873 => true,
  917874 => true,
  917875 => true,
  917876 => true,
  917877 => true,
  917878 => true,
  917879 => true,
  917880 => true,
  917881 => true,
  917882 => true,
  917883 => true,
  917884 => true,
  917885 => true,
  917886 => true,
  917887 => true,
  917888 => true,
  917889 => true,
  917890 => true,
  917891 => true,
  917892 => true,
  917893 => true,
  917894 => true,
  917895 => true,
  917896 => true,
  917897 => true,
  917898 => true,
  917899 => true,
  917900 => true,
  917901 => true,
  917902 => true,
  917903 => true,
  917904 => true,
  917905 => true,
  917906 => true,
  917907 => true,
  917908 => true,
  917909 => true,
  917910 => true,
  917911 => true,
  917912 => true,
  917913 => true,
  917914 => true,
  917915 => true,
  917916 => true,
  917917 => true,
  917918 => true,
  917919 => true,
  917920 => true,
  917921 => true,
  917922 => true,
  917923 => true,
  917924 => true,
  917925 => true,
  917926 => true,
  917927 => true,
  917928 => true,
  917929 => true,
  917930 => true,
  917931 => true,
  917932 => true,
  917933 => true,
  917934 => true,
  917935 => true,
  917936 => true,
  917937 => true,
  917938 => true,
  917939 => true,
  917940 => true,
  917941 => true,
  917942 => true,
  917943 => true,
  917944 => true,
  917945 => true,
  917946 => true,
  917947 => true,
  917948 => true,
  917949 => true,
  917950 => true,
  917951 => true,
  917952 => true,
  917953 => true,
  917954 => true,
  917955 => true,
  917956 => true,
  917957 => true,
  917958 => true,
  917959 => true,
  917960 => true,
  917961 => true,
  917962 => true,
  917963 => true,
  917964 => true,
  917965 => true,
  917966 => true,
  917967 => true,
  917968 => true,
  917969 => true,
  917970 => true,
  917971 => true,
  917972 => true,
  917973 => true,
  917974 => true,
  917975 => true,
  917976 => true,
  917977 => true,
  917978 => true,
  917979 => true,
  917980 => true,
  917981 => true,
  917982 => true,
  917983 => true,
  917984 => true,
  917985 => true,
  917986 => true,
  917987 => true,
  917988 => true,
  917989 => true,
  917990 => true,
  917991 => true,
  917992 => true,
  917993 => true,
  917994 => true,
  917995 => true,
  917996 => true,
  917997 => true,
  917998 => true,
  917999 => true,
);
<?php

return array (
  65 => 'a',
  66 => 'b',
  67 => 'c',
  68 => 'd',
  69 => 'e',
  70 => 'f',
  71 => 'g',
  72 => 'h',
  73 => 'i',
  74 => 'j',
  75 => 'k',
  76 => 'l',
  77 => 'm',
  78 => 'n',
  79 => 'o',
  80 => 'p',
  81 => 'q',
  82 => 'r',
  83 => 's',
  84 => 't',
  85 => 'u',
  86 => 'v',
  87 => 'w',
  88 => 'x',
  89 => 'y',
  90 => 'z',
  170 => 'a',
  178 => '2',
  179 => '3',
  181 => 'μ',
  185 => '1',
  186 => 'o',
  188 => '1⁄4',
  189 => '1⁄2',
  190 => '3⁄4',
  192 => 'à',
  193 => 'á',
  194 => 'â',
  195 => 'ã',
  196 => 'ä',
  197 => 'å',
  198 => 'æ',
  199 => 'ç',
  200 => 'è',
  201 => 'é',
  202 => 'ê',
  203 => 'ë',
  204 => 'ì',
  205 => 'í',
  206 => 'î',
  207 => 'ï',
  208 => 'ð',
  209 => 'ñ',
  210 => 'ò',
  211 => 'ó',
  212 => 'ô',
  213 => 'õ',
  214 => 'ö',
  216 => 'ø',
  217 => 'ù',
  218 => 'ú',
  219 => 'û',
  220 => 'ü',
  221 => 'ý',
  222 => 'þ',
  256 => 'ā',
  258 => 'ă',
  260 => 'ą',
  262 => 'ć',
  264 => 'ĉ',
  266 => 'ċ',
  268 => 'č',
  270 => 'ď',
  272 => 'đ',
  274 => 'ē',
  276 => 'ĕ',
  278 => 'ė',
  280 => 'ę',
  282 => 'ě',
  284 => 'ĝ',
  286 => 'ğ',
  288 => 'ġ',
  290 => 'ģ',
  292 => 'ĥ',
  294 => 'ħ',
  296 => 'ĩ',
  298 => 'ī',
  300 => 'ĭ',
  302 => 'į',
  304 => 'i̇',
  306 => 'ij',
  307 => 'ij',
  308 => 'ĵ',
  310 => 'ķ',
  313 => 'ĺ',
  315 => 'ļ',
  317 => 'ľ',
  319 => 'l·',
  320 => 'l·',
  321 => 'ł',
  323 => 'ń',
  325 => 'ņ',
  327 => 'ň',
  329 => 'ʼn',
  330 => 'ŋ',
  332 => 'ō',
  334 => 'ŏ',
  336 => 'ő',
  338 => 'œ',
  340 => 'ŕ',
  342 => 'ŗ',
  344 => 'ř',
  346 => 'ś',
  348 => 'ŝ',
  350 => 'ş',
  352 => 'š',
  354 => 'ţ',
  356 => 'ť',
  358 => 'ŧ',
  360 => 'ũ',
  362 => 'ū',
  364 => 'ŭ',
  366 => 'ů',
  368 => 'ű',
  370 => 'ų',
  372 => 'ŵ',
  374 => 'ŷ',
  376 => 'ÿ',
  377 => 'ź',
  379 => 'ż',
  381 => 'ž',
  383 => 's',
  385 => 'ɓ',
  386 => 'ƃ',
  388 => 'ƅ',
  390 => 'ɔ',
  391 => 'ƈ',
  393 => 'ɖ',
  394 => 'ɗ',
  395 => 'ƌ',
  398 => 'ǝ',
  399 => 'ə',
  400 => 'ɛ',
  401 => 'ƒ',
  403 => 'ɠ',
  404 => 'ɣ',
  406 => 'ɩ',
  407 => 'ɨ',
  408 => 'ƙ',
  412 => 'ɯ',
  413 => 'ɲ',
  415 => 'ɵ',
  416 => 'ơ',
  418 => 'ƣ',
  420 => 'ƥ',
  422 => 'ʀ',
  423 => 'ƨ',
  425 => 'ʃ',
  428 => 'ƭ',
  430 => 'ʈ',
  431 => 'ư',
  433 => 'ʊ',
  434 => 'ʋ',
  435 => 'ƴ',
  437 => 'ƶ',
  439 => 'ʒ',
  440 => 'ƹ',
  444 => 'ƽ',
  452 => 'dž',
  453 => 'dž',
  454 => 'dž',
  455 => 'lj',
  456 => 'lj',
  457 => 'lj',
  458 => 'nj',
  459 => 'nj',
  460 => 'nj',
  461 => 'ǎ',
  463 => 'ǐ',
  465 => 'ǒ',
  467 => 'ǔ',
  469 => 'ǖ',
  471 => 'ǘ',
  473 => 'ǚ',
  475 => 'ǜ',
  478 => 'ǟ',
  480 => 'ǡ',
  482 => 'ǣ',
  484 => 'ǥ',
  486 => 'ǧ',
  488 => 'ǩ',
  490 => 'ǫ',
  492 => 'ǭ',
  494 => 'ǯ',
  497 => 'dz',
  498 => 'dz',
  499 => 'dz',
  500 => 'ǵ',
  502 => 'ƕ',
  503 => 'ƿ',
  504 => 'ǹ',
  506 => 'ǻ',
  508 => 'ǽ',
  510 => 'ǿ',
  512 => 'ȁ',
  514 => 'ȃ',
  516 => 'ȅ',
  518 => 'ȇ',
  520 => 'ȉ',
  522 => 'ȋ',
  524 => 'ȍ',
  526 => 'ȏ',
  528 => 'ȑ',
  530 => 'ȓ',
  532 => 'ȕ',
  534 => 'ȗ',
  536 => 'ș',
  538 => 'ț',
  540 => 'ȝ',
  542 => 'ȟ',
  544 => 'ƞ',
  546 => 'ȣ',
  548 => 'ȥ',
  550 => 'ȧ',
  552 => 'ȩ',
  554 => 'ȫ',
  556 => 'ȭ',
  558 => 'ȯ',
  560 => 'ȱ',
  562 => 'ȳ',
  570 => 'ⱥ',
  571 => 'ȼ',
  573 => 'ƚ',
  574 => 'ⱦ',
  577 => 'ɂ',
  579 => 'ƀ',
  580 => 'ʉ',
  581 => 'ʌ',
  582 => 'ɇ',
  584 => 'ɉ',
  586 => 'ɋ',
  588 => 'ɍ',
  590 => 'ɏ',
  688 => 'h',
  689 => 'ɦ',
  690 => 'j',
  691 => 'r',
  692 => 'ɹ',
  693 => 'ɻ',
  694 => 'ʁ',
  695 => 'w',
  696 => 'y',
  736 => 'ɣ',
  737 => 'l',
  738 => 's',
  739 => 'x',
  740 => 'ʕ',
  832 => '̀',
  833 => '́',
  835 => '̓',
  836 => '̈́',
  837 => 'ι',
  880 => 'ͱ',
  882 => 'ͳ',
  884 => 'ʹ',
  886 => 'ͷ',
  895 => 'ϳ',
  902 => 'ά',
  903 => '·',
  904 => 'έ',
  905 => 'ή',
  906 => 'ί',
  908 => 'ό',
  910 => 'ύ',
  911 => 'ώ',
  913 => 'α',
  914 => 'β',
  915 => 'γ',
  916 => 'δ',
  917 => 'ε',
  918 => 'ζ',
  919 => 'η',
  920 => 'θ',
  921 => 'ι',
  922 => 'κ',
  923 => 'λ',
  924 => 'μ',
  925 => 'ν',
  926 => 'ξ',
  927 => 'ο',
  928 => 'π',
  929 => 'ρ',
  931 => 'σ',
  932 => 'τ',
  933 => 'υ',
  934 => 'φ',
  935 => 'χ',
  936 => 'ψ',
  937 => 'ω',
  938 => 'ϊ',
  939 => 'ϋ',
  975 => 'ϗ',
  976 => 'β',
  977 => 'θ',
  978 => 'υ',
  979 => 'ύ',
  980 => 'ϋ',
  981 => 'φ',
  982 => 'π',
  984 => 'ϙ',
  986 => 'ϛ',
  988 => 'ϝ',
  990 => 'ϟ',
  992 => 'ϡ',
  994 => 'ϣ',
  996 => 'ϥ',
  998 => 'ϧ',
  1000 => 'ϩ',
  1002 => 'ϫ',
  1004 => 'ϭ',
  1006 => 'ϯ',
  1008 => 'κ',
  1009 => 'ρ',
  1010 => 'σ',
  1012 => 'θ',
  1013 => 'ε',
  1015 => 'ϸ',
  1017 => 'σ',
  1018 => 'ϻ',
  1021 => 'ͻ',
  1022 => 'ͼ',
  1023 => 'ͽ',
  1024 => 'ѐ',
  1025 => 'ё',
  1026 => 'ђ',
  1027 => 'ѓ',
  1028 => 'є',
  1029 => 'ѕ',
  1030 => 'і',
  1031 => 'ї',
  1032 => 'ј',
  1033 => 'љ',
  1034 => 'њ',
  1035 => 'ћ',
  1036 => 'ќ',
  1037 => 'ѝ',
  1038 => 'ў',
  1039 => 'џ',
  1040 => 'а',
  1041 => 'б',
  1042 => 'в',
  1043 => 'г',
  1044 => 'д',
  1045 => 'е',
  1046 => 'ж',
  1047 => 'з',
  1048 => 'и',
  1049 => 'й',
  1050 => 'к',
  1051 => 'л',
  1052 => 'м',
  1053 => 'н',
  1054 => 'о',
  1055 => 'п',
  1056 => 'р',
  1057 => 'с',
  1058 => 'т',
  1059 => 'у',
  1060 => 'ф',
  1061 => 'х',
  1062 => 'ц',
  1063 => 'ч',
  1064 => 'ш',
  1065 => 'щ',
  1066 => 'ъ',
  1067 => 'ы',
  1068 => 'ь',
  1069 => 'э',
  1070 => 'ю',
  1071 => 'я',
  1120 => 'ѡ',
  1122 => 'ѣ',
  1124 => 'ѥ',
  1126 => 'ѧ',
  1128 => 'ѩ',
  1130 => 'ѫ',
  1132 => 'ѭ',
  1134 => 'ѯ',
  1136 => 'ѱ',
  1138 => 'ѳ',
  1140 => 'ѵ',
  1142 => 'ѷ',
  1144 => 'ѹ',
  1146 => 'ѻ',
  1148 => 'ѽ',
  1150 => 'ѿ',
  1152 => 'ҁ',
  1162 => 'ҋ',
  1164 => 'ҍ',
  1166 => 'ҏ',
  1168 => 'ґ',
  1170 => 'ғ',
  1172 => 'ҕ',
  1174 => 'җ',
  1176 => 'ҙ',
  1178 => 'қ',
  1180 => 'ҝ',
  1182 => 'ҟ',
  1184 => 'ҡ',
  1186 => 'ң',
  1188 => 'ҥ',
  1190 => 'ҧ',
  1192 => 'ҩ',
  1194 => 'ҫ',
  1196 => 'ҭ',
  1198 => 'ү',
  1200 => 'ұ',
  1202 => 'ҳ',
  1204 => 'ҵ',
  1206 => 'ҷ',
  1208 => 'ҹ',
  1210 => 'һ',
  1212 => 'ҽ',
  1214 => 'ҿ',
  1217 => 'ӂ',
  1219 => 'ӄ',
  1221 => 'ӆ',
  1223 => 'ӈ',
  1225 => 'ӊ',
  1227 => 'ӌ',
  1229 => 'ӎ',
  1232 => 'ӑ',
  1234 => 'ӓ',
  1236 => 'ӕ',
  1238 => 'ӗ',
  1240 => 'ә',
  1242 => 'ӛ',
  1244 => 'ӝ',
  1246 => 'ӟ',
  1248 => 'ӡ',
  1250 => 'ӣ',
  1252 => 'ӥ',
  1254 => 'ӧ',
  1256 => 'ө',
  1258 => 'ӫ',
  1260 => 'ӭ',
  1262 => 'ӯ',
  1264 => 'ӱ',
  1266 => 'ӳ',
  1268 => 'ӵ',
  1270 => 'ӷ',
  1272 => 'ӹ',
  1274 => 'ӻ',
  1276 => 'ӽ',
  1278 => 'ӿ',
  1280 => 'ԁ',
  1282 => 'ԃ',
  1284 => 'ԅ',
  1286 => 'ԇ',
  1288 => 'ԉ',
  1290 => 'ԋ',
  1292 => 'ԍ',
  1294 => 'ԏ',
  1296 => 'ԑ',
  1298 => 'ԓ',
  1300 => 'ԕ',
  1302 => 'ԗ',
  1304 => 'ԙ',
  1306 => 'ԛ',
  1308 => 'ԝ',
  1310 => 'ԟ',
  1312 => 'ԡ',
  1314 => 'ԣ',
  1316 => 'ԥ',
  1318 => 'ԧ',
  1320 => 'ԩ',
  1322 => 'ԫ',
  1324 => 'ԭ',
  1326 => 'ԯ',
  1329 => 'ա',
  1330 => 'բ',
  1331 => 'գ',
  1332 => 'դ',
  1333 => 'ե',
  1334 => 'զ',
  1335 => 'է',
  1336 => 'ը',
  1337 => 'թ',
  1338 => 'ժ',
  1339 => 'ի',
  1340 => 'լ',
  1341 => 'խ',
  1342 => 'ծ',
  1343 => 'կ',
  1344 => 'հ',
  1345 => 'ձ',
  1346 => 'ղ',
  1347 => 'ճ',
  1348 => 'մ',
  1349 => 'յ',
  1350 => 'ն',
  1351 => 'շ',
  1352 => 'ո',
  1353 => 'չ',
  1354 => 'պ',
  1355 => 'ջ',
  1356 => 'ռ',
  1357 => 'ս',
  1358 => 'վ',
  1359 => 'տ',
  1360 => 'ր',
  1361 => 'ց',
  1362 => 'ւ',
  1363 => 'փ',
  1364 => 'ք',
  1365 => 'օ',
  1366 => 'ֆ',
  1415 => 'եւ',
  1653 => 'اٴ',
  1654 => 'وٴ',
  1655 => 'ۇٴ',
  1656 => 'يٴ',
  2392 => 'क़',
  2393 => 'ख़',
  2394 => 'ग़',
  2395 => 'ज़',
  2396 => 'ड़',
  2397 => 'ढ़',
  2398 => 'फ़',
  2399 => 'य़',
  2524 => 'ড়',
  2525 => 'ঢ়',
  2527 => 'য়',
  2611 => 'ਲ਼',
  2614 => 'ਸ਼',
  2649 => 'ਖ਼',
  2650 => 'ਗ਼',
  2651 => 'ਜ਼',
  2654 => 'ਫ਼',
  2908 => 'ଡ଼',
  2909 => 'ଢ଼',
  3635 => 'ํา',
  3763 => 'ໍາ',
  3804 => 'ຫນ',
  3805 => 'ຫມ',
  3852 => '་',
  3907 => 'གྷ',
  3917 => 'ཌྷ',
  3922 => 'དྷ',
  3927 => 'བྷ',
  3932 => 'ཛྷ',
  3945 => 'ཀྵ',
  3955 => 'ཱི',
  3957 => 'ཱུ',
  3958 => 'ྲྀ',
  3959 => 'ྲཱྀ',
  3960 => 'ླྀ',
  3961 => 'ླཱྀ',
  3969 => 'ཱྀ',
  3987 => 'ྒྷ',
  3997 => 'ྜྷ',
  4002 => 'ྡྷ',
  4007 => 'ྦྷ',
  4012 => 'ྫྷ',
  4025 => 'ྐྵ',
  4295 => 'ⴧ',
  4301 => 'ⴭ',
  4348 => 'ნ',
  5112 => 'Ᏸ',
  5113 => 'Ᏹ',
  5114 => 'Ᏺ',
  5115 => 'Ᏻ',
  5116 => 'Ᏼ',
  5117 => 'Ᏽ',
  7296 => 'в',
  7297 => 'д',
  7298 => 'о',
  7299 => 'с',
  7300 => 'т',
  7301 => 'т',
  7302 => 'ъ',
  7303 => 'ѣ',
  7304 => 'ꙋ',
  7312 => 'ა',
  7313 => 'ბ',
  7314 => 'გ',
  7315 => 'დ',
  7316 => 'ე',
  7317 => 'ვ',
  7318 => 'ზ',
  7319 => 'თ',
  7320 => 'ი',
  7321 => 'კ',
  7322 => 'ლ',
  7323 => 'მ',
  7324 => 'ნ',
  7325 => 'ო',
  7326 => 'პ',
  7327 => 'ჟ',
  7328 => 'რ',
  7329 => 'ს',
  7330 => 'ტ',
  7331 => 'უ',
  7332 => 'ფ',
  7333 => 'ქ',
  7334 => 'ღ',
  7335 => 'ყ',
  7336 => 'შ',
  7337 => 'ჩ',
  7338 => 'ც',
  7339 => 'ძ',
  7340 => 'წ',
  7341 => 'ჭ',
  7342 => 'ხ',
  7343 => 'ჯ',
  7344 => 'ჰ',
  7345 => 'ჱ',
  7346 => 'ჲ',
  7347 => 'ჳ',
  7348 => 'ჴ',
  7349 => 'ჵ',
  7350 => 'ჶ',
  7351 => 'ჷ',
  7352 => 'ჸ',
  7353 => 'ჹ',
  7354 => 'ჺ',
  7357 => 'ჽ',
  7358 => 'ჾ',
  7359 => 'ჿ',
  7468 => 'a',
  7469 => 'æ',
  7470 => 'b',
  7472 => 'd',
  7473 => 'e',
  7474 => 'ǝ',
  7475 => 'g',
  7476 => 'h',
  7477 => 'i',
  7478 => 'j',
  7479 => 'k',
  7480 => 'l',
  7481 => 'm',
  7482 => 'n',
  7484 => 'o',
  7485 => 'ȣ',
  7486 => 'p',
  7487 => 'r',
  7488 => 't',
  7489 => 'u',
  7490 => 'w',
  7491 => 'a',
  7492 => 'ɐ',
  7493 => 'ɑ',
  7494 => 'ᴂ',
  7495 => 'b',
  7496 => 'd',
  7497 => 'e',
  7498 => 'ə',
  7499 => 'ɛ',
  7500 => 'ɜ',
  7501 => 'g',
  7503 => 'k',
  7504 => 'm',
  7505 => 'ŋ',
  7506 => 'o',
  7507 => 'ɔ',
  7508 => 'ᴖ',
  7509 => 'ᴗ',
  7510 => 'p',
  7511 => 't',
  7512 => 'u',
  7513 => 'ᴝ',
  7514 => 'ɯ',
  7515 => 'v',
  7516 => 'ᴥ',
  7517 => 'β',
  7518 => 'γ',
  7519 => 'δ',
  7520 => 'φ',
  7521 => 'χ',
  7522 => 'i',
  7523 => 'r',
  7524 => 'u',
  7525 => 'v',
  7526 => 'β',
  7527 => 'γ',
  7528 => 'ρ',
  7529 => 'φ',
  7530 => 'χ',
  7544 => 'н',
  7579 => 'ɒ',
  7580 => 'c',
  7581 => 'ɕ',
  7582 => 'ð',
  7583 => 'ɜ',
  7584 => 'f',
  7585 => 'ɟ',
  7586 => 'ɡ',
  7587 => 'ɥ',
  7588 => 'ɨ',
  7589 => 'ɩ',
  7590 => 'ɪ',
  7591 => 'ᵻ',
  7592 => 'ʝ',
  7593 => 'ɭ',
  7594 => 'ᶅ',
  7595 => 'ʟ',
  7596 => 'ɱ',
  7597 => 'ɰ',
  7598 => 'ɲ',
  7599 => 'ɳ',
  7600 => 'ɴ',
  7601 => 'ɵ',
  7602 => 'ɸ',
  7603 => 'ʂ',
  7604 => 'ʃ',
  7605 => 'ƫ',
  7606 => 'ʉ',
  7607 => 'ʊ',
  7608 => 'ᴜ',
  7609 => 'ʋ',
  7610 => 'ʌ',
  7611 => 'z',
  7612 => 'ʐ',
  7613 => 'ʑ',
  7614 => 'ʒ',
  7615 => 'θ',
  7680 => 'ḁ',
  7682 => 'ḃ',
  7684 => 'ḅ',
  7686 => 'ḇ',
  7688 => 'ḉ',
  7690 => 'ḋ',
  7692 => 'ḍ',
  7694 => 'ḏ',
  7696 => 'ḑ',
  7698 => 'ḓ',
  7700 => 'ḕ',
  7702 => 'ḗ',
  7704 => 'ḙ',
  7706 => 'ḛ',
  7708 => 'ḝ',
  7710 => 'ḟ',
  7712 => 'ḡ',
  7714 => 'ḣ',
  7716 => 'ḥ',
  7718 => 'ḧ',
  7720 => 'ḩ',
  7722 => 'ḫ',
  7724 => 'ḭ',
  7726 => 'ḯ',
  7728 => 'ḱ',
  7730 => 'ḳ',
  7732 => 'ḵ',
  7734 => 'ḷ',
  7736 => 'ḹ',
  7738 => 'ḻ',
  7740 => 'ḽ',
  7742 => 'ḿ',
  7744 => 'ṁ',
  7746 => 'ṃ',
  7748 => 'ṅ',
  7750 => 'ṇ',
  7752 => 'ṉ',
  7754 => 'ṋ',
  7756 => 'ṍ',
  7758 => 'ṏ',
  7760 => 'ṑ',
  7762 => 'ṓ',
  7764 => 'ṕ',
  7766 => 'ṗ',
  7768 => 'ṙ',
  7770 => 'ṛ',
  7772 => 'ṝ',
  7774 => 'ṟ',
  7776 => 'ṡ',
  7778 => 'ṣ',
  7780 => 'ṥ',
  7782 => 'ṧ',
  7784 => 'ṩ',
  7786 => 'ṫ',
  7788 => 'ṭ',
  7790 => 'ṯ',
  7792 => 'ṱ',
  7794 => 'ṳ',
  7796 => 'ṵ',
  7798 => 'ṷ',
  7800 => 'ṹ',
  7802 => 'ṻ',
  7804 => 'ṽ',
  7806 => 'ṿ',
  7808 => 'ẁ',
  7810 => 'ẃ',
  7812 => 'ẅ',
  7814 => 'ẇ',
  7816 => 'ẉ',
  7818 => 'ẋ',
  7820 => 'ẍ',
  7822 => 'ẏ',
  7824 => 'ẑ',
  7826 => 'ẓ',
  7828 => 'ẕ',
  7834 => 'aʾ',
  7835 => 'ṡ',
  7838 => 'ss',
  7840 => 'ạ',
  7842 => 'ả',
  7844 => 'ấ',
  7846 => 'ầ',
  7848 => 'ẩ',
  7850 => 'ẫ',
  7852 => 'ậ',
  7854 => 'ắ',
  7856 => 'ằ',
  7858 => 'ẳ',
  7860 => 'ẵ',
  7862 => 'ặ',
  7864 => 'ẹ',
  7866 => 'ẻ',
  7868 => 'ẽ',
  7870 => 'ế',
  7872 => 'ề',
  7874 => 'ể',
  7876 => 'ễ',
  7878 => 'ệ',
  7880 => 'ỉ',
  7882 => 'ị',
  7884 => 'ọ',
  7886 => 'ỏ',
  7888 => 'ố',
  7890 => 'ồ',
  7892 => 'ổ',
  7894 => 'ỗ',
  7896 => 'ộ',
  7898 => 'ớ',
  7900 => 'ờ',
  7902 => 'ở',
  7904 => 'ỡ',
  7906 => 'ợ',
  7908 => 'ụ',
  7910 => 'ủ',
  7912 => 'ứ',
  7914 => 'ừ',
  7916 => 'ử',
  7918 => 'ữ',
  7920 => 'ự',
  7922 => 'ỳ',
  7924 => 'ỵ',
  7926 => 'ỷ',
  7928 => 'ỹ',
  7930 => 'ỻ',
  7932 => 'ỽ',
  7934 => 'ỿ',
  7944 => 'ἀ',
  7945 => 'ἁ',
  7946 => 'ἂ',
  7947 => 'ἃ',
  7948 => 'ἄ',
  7949 => 'ἅ',
  7950 => 'ἆ',
  7951 => 'ἇ',
  7960 => 'ἐ',
  7961 => 'ἑ',
  7962 => 'ἒ',
  7963 => 'ἓ',
  7964 => 'ἔ',
  7965 => 'ἕ',
  7976 => 'ἠ',
  7977 => 'ἡ',
  7978 => 'ἢ',
  7979 => 'ἣ',
  7980 => 'ἤ',
  7981 => 'ἥ',
  7982 => 'ἦ',
  7983 => 'ἧ',
  7992 => 'ἰ',
  7993 => 'ἱ',
  7994 => 'ἲ',
  7995 => 'ἳ',
  7996 => 'ἴ',
  7997 => 'ἵ',
  7998 => 'ἶ',
  7999 => 'ἷ',
  8008 => 'ὀ',
  8009 => 'ὁ',
  8010 => 'ὂ',
  8011 => 'ὃ',
  8012 => 'ὄ',
  8013 => 'ὅ',
  8025 => 'ὑ',
  8027 => 'ὓ',
  8029 => 'ὕ',
  8031 => 'ὗ',
  8040 => 'ὠ',
  8041 => 'ὡ',
  8042 => 'ὢ',
  8043 => 'ὣ',
  8044 => 'ὤ',
  8045 => 'ὥ',
  8046 => 'ὦ',
  8047 => 'ὧ',
  8049 => 'ά',
  8051 => 'έ',
  8053 => 'ή',
  8055 => 'ί',
  8057 => 'ό',
  8059 => 'ύ',
  8061 => 'ώ',
  8064 => 'ἀι',
  8065 => 'ἁι',
  8066 => 'ἂι',
  8067 => 'ἃι',
  8068 => 'ἄι',
  8069 => 'ἅι',
  8070 => 'ἆι',
  8071 => 'ἇι',
  8072 => 'ἀι',
  8073 => 'ἁι',
  8074 => 'ἂι',
  8075 => 'ἃι',
  8076 => 'ἄι',
  8077 => 'ἅι',
  8078 => 'ἆι',
  8079 => 'ἇι',
  8080 => 'ἠι',
  8081 => 'ἡι',
  8082 => 'ἢι',
  8083 => 'ἣι',
  8084 => 'ἤι',
  8085 => 'ἥι',
  8086 => 'ἦι',
  8087 => 'ἧι',
  8088 => 'ἠι',
  8089 => 'ἡι',
  8090 => 'ἢι',
  8091 => 'ἣι',
  8092 => 'ἤι',
  8093 => 'ἥι',
  8094 => 'ἦι',
  8095 => 'ἧι',
  8096 => 'ὠι',
  8097 => 'ὡι',
  8098 => 'ὢι',
  8099 => 'ὣι',
  8100 => 'ὤι',
  8101 => 'ὥι',
  8102 => 'ὦι',
  8103 => 'ὧι',
  8104 => 'ὠι',
  8105 => 'ὡι',
  8106 => 'ὢι',
  8107 => 'ὣι',
  8108 => 'ὤι',
  8109 => 'ὥι',
  8110 => 'ὦι',
  8111 => 'ὧι',
  8114 => 'ὰι',
  8115 => 'αι',
  8116 => 'άι',
  8119 => 'ᾶι',
  8120 => 'ᾰ',
  8121 => 'ᾱ',
  8122 => 'ὰ',
  8123 => 'ά',
  8124 => 'αι',
  8126 => 'ι',
  8130 => 'ὴι',
  8131 => 'ηι',
  8132 => 'ήι',
  8135 => 'ῆι',
  8136 => 'ὲ',
  8137 => 'έ',
  8138 => 'ὴ',
  8139 => 'ή',
  8140 => 'ηι',
  8147 => 'ΐ',
  8152 => 'ῐ',
  8153 => 'ῑ',
  8154 => 'ὶ',
  8155 => 'ί',
  8163 => 'ΰ',
  8168 => 'ῠ',
  8169 => 'ῡ',
  8170 => 'ὺ',
  8171 => 'ύ',
  8172 => 'ῥ',
  8178 => 'ὼι',
  8179 => 'ωι',
  8180 => 'ώι',
  8183 => 'ῶι',
  8184 => 'ὸ',
  8185 => 'ό',
  8186 => 'ὼ',
  8187 => 'ώ',
  8188 => 'ωι',
  8209 => '‐',
  8243 => '′′',
  8244 => '′′′',
  8246 => '‵‵',
  8247 => '‵‵‵',
  8279 => '′′′′',
  8304 => '0',
  8305 => 'i',
  8308 => '4',
  8309 => '5',
  8310 => '6',
  8311 => '7',
  8312 => '8',
  8313 => '9',
  8315 => '−',
  8319 => 'n',
  8320 => '0',
  8321 => '1',
  8322 => '2',
  8323 => '3',
  8324 => '4',
  8325 => '5',
  8326 => '6',
  8327 => '7',
  8328 => '8',
  8329 => '9',
  8331 => '−',
  8336 => 'a',
  8337 => 'e',
  8338 => 'o',
  8339 => 'x',
  8340 => 'ə',
  8341 => 'h',
  8342 => 'k',
  8343 => 'l',
  8344 => 'm',
  8345 => 'n',
  8346 => 'p',
  8347 => 's',
  8348 => 't',
  8360 => 'rs',
  8450 => 'c',
  8451 => '°c',
  8455 => 'ɛ',
  8457 => '°f',
  8458 => 'g',
  8459 => 'h',
  8460 => 'h',
  8461 => 'h',
  8462 => 'h',
  8463 => 'ħ',
  8464 => 'i',
  8465 => 'i',
  8466 => 'l',
  8467 => 'l',
  8469 => 'n',
  8470 => 'no',
  8473 => 'p',
  8474 => 'q',
  8475 => 'r',
  8476 => 'r',
  8477 => 'r',
  8480 => 'sm',
  8481 => 'tel',
  8482 => 'tm',
  8484 => 'z',
  8486 => 'ω',
  8488 => 'z',
  8490 => 'k',
  8491 => 'å',
  8492 => 'b',
  8493 => 'c',
  8495 => 'e',
  8496 => 'e',
  8497 => 'f',
  8499 => 'm',
  8500 => 'o',
  8501 => 'א',
  8502 => 'ב',
  8503 => 'ג',
  8504 => 'ד',
  8505 => 'i',
  8507 => 'fax',
  8508 => 'π',
  8509 => 'γ',
  8510 => 'γ',
  8511 => 'π',
  8512 => '∑',
  8517 => 'd',
  8518 => 'd',
  8519 => 'e',
  8520 => 'i',
  8521 => 'j',
  8528 => '1⁄7',
  8529 => '1⁄9',
  8530 => '1⁄10',
  8531 => '1⁄3',
  8532 => '2⁄3',
  8533 => '1⁄5',
  8534 => '2⁄5',
  8535 => '3⁄5',
  8536 => '4⁄5',
  8537 => '1⁄6',
  8538 => '5⁄6',
  8539 => '1⁄8',
  8540 => '3⁄8',
  8541 => '5⁄8',
  8542 => '7⁄8',
  8543 => '1⁄',
  8544 => 'i',
  8545 => 'ii',
  8546 => 'iii',
  8547 => 'iv',
  8548 => 'v',
  8549 => 'vi',
  8550 => 'vii',
  8551 => 'viii',
  8552 => 'ix',
  8553 => 'x',
  8554 => 'xi',
  8555 => 'xii',
  8556 => 'l',
  8557 => 'c',
  8558 => 'd',
  8559 => 'm',
  8560 => 'i',
  8561 => 'ii',
  8562 => 'iii',
  8563 => 'iv',
  8564 => 'v',
  8565 => 'vi',
  8566 => 'vii',
  8567 => 'viii',
  8568 => 'ix',
  8569 => 'x',
  8570 => 'xi',
  8571 => 'xii',
  8572 => 'l',
  8573 => 'c',
  8574 => 'd',
  8575 => 'm',
  8585 => '0⁄3',
  8748 => '∫∫',
  8749 => '∫∫∫',
  8751 => '∮∮',
  8752 => '∮∮∮',
  9001 => '〈',
  9002 => '〉',
  9312 => '1',
  9313 => '2',
  9314 => '3',
  9315 => '4',
  9316 => '5',
  9317 => '6',
  9318 => '7',
  9319 => '8',
  9320 => '9',
  9321 => '10',
  9322 => '11',
  9323 => '12',
  9324 => '13',
  9325 => '14',
  9326 => '15',
  9327 => '16',
  9328 => '17',
  9329 => '18',
  9330 => '19',
  9331 => '20',
  9398 => 'a',
  9399 => 'b',
  9400 => 'c',
  9401 => 'd',
  9402 => 'e',
  9403 => 'f',
  9404 => 'g',
  9405 => 'h',
  9406 => 'i',
  9407 => 'j',
  9408 => 'k',
  9409 => 'l',
  9410 => 'm',
  9411 => 'n',
  9412 => 'o',
  9413 => 'p',
  9414 => 'q',
  9415 => 'r',
  9416 => 's',
  9417 => 't',
  9418 => 'u',
  9419 => 'v',
  9420 => 'w',
  9421 => 'x',
  9422 => 'y',
  9423 => 'z',
  9424 => 'a',
  9425 => 'b',
  9426 => 'c',
  9427 => 'd',
  9428 => 'e',
  9429 => 'f',
  9430 => 'g',
  9431 => 'h',
  9432 => 'i',
  9433 => 'j',
  9434 => 'k',
  9435 => 'l',
  9436 => 'm',
  9437 => 'n',
  9438 => 'o',
  9439 => 'p',
  9440 => 'q',
  9441 => 'r',
  9442 => 's',
  9443 => 't',
  9444 => 'u',
  9445 => 'v',
  9446 => 'w',
  9447 => 'x',
  9448 => 'y',
  9449 => 'z',
  9450 => '0',
  10764 => '∫∫∫∫',
  10972 => '⫝̸',
  11264 => 'ⰰ',
  11265 => 'ⰱ',
  11266 => 'ⰲ',
  11267 => 'ⰳ',
  11268 => 'ⰴ',
  11269 => 'ⰵ',
  11270 => 'ⰶ',
  11271 => 'ⰷ',
  11272 => 'ⰸ',
  11273 => 'ⰹ',
  11274 => 'ⰺ',
  11275 => 'ⰻ',
  11276 => 'ⰼ',
  11277 => 'ⰽ',
  11278 => 'ⰾ',
  11279 => 'ⰿ',
  11280 => 'ⱀ',
  11281 => 'ⱁ',
  11282 => 'ⱂ',
  11283 => 'ⱃ',
  11284 => 'ⱄ',
  11285 => 'ⱅ',
  11286 => 'ⱆ',
  11287 => 'ⱇ',
  11288 => 'ⱈ',
  11289 => 'ⱉ',
  11290 => 'ⱊ',
  11291 => 'ⱋ',
  11292 => 'ⱌ',
  11293 => 'ⱍ',
  11294 => 'ⱎ',
  11295 => 'ⱏ',
  11296 => 'ⱐ',
  11297 => 'ⱑ',
  11298 => 'ⱒ',
  11299 => 'ⱓ',
  11300 => 'ⱔ',
  11301 => 'ⱕ',
  11302 => 'ⱖ',
  11303 => 'ⱗ',
  11304 => 'ⱘ',
  11305 => 'ⱙ',
  11306 => 'ⱚ',
  11307 => 'ⱛ',
  11308 => 'ⱜ',
  11309 => 'ⱝ',
  11310 => 'ⱞ',
  11360 => 'ⱡ',
  11362 => 'ɫ',
  11363 => 'ᵽ',
  11364 => 'ɽ',
  11367 => 'ⱨ',
  11369 => 'ⱪ',
  11371 => 'ⱬ',
  11373 => 'ɑ',
  11374 => 'ɱ',
  11375 => 'ɐ',
  11376 => 'ɒ',
  11378 => 'ⱳ',
  11381 => 'ⱶ',
  11388 => 'j',
  11389 => 'v',
  11390 => 'ȿ',
  11391 => 'ɀ',
  11392 => 'ⲁ',
  11394 => 'ⲃ',
  11396 => 'ⲅ',
  11398 => 'ⲇ',
  11400 => 'ⲉ',
  11402 => 'ⲋ',
  11404 => 'ⲍ',
  11406 => 'ⲏ',
  11408 => 'ⲑ',
  11410 => 'ⲓ',
  11412 => 'ⲕ',
  11414 => 'ⲗ',
  11416 => 'ⲙ',
  11418 => 'ⲛ',
  11420 => 'ⲝ',
  11422 => 'ⲟ',
  11424 => 'ⲡ',
  11426 => 'ⲣ',
  11428 => 'ⲥ',
  11430 => 'ⲧ',
  11432 => 'ⲩ',
  11434 => 'ⲫ',
  11436 => 'ⲭ',
  11438 => 'ⲯ',
  11440 => 'ⲱ',
  11442 => 'ⲳ',
  11444 => 'ⲵ',
  11446 => 'ⲷ',
  11448 => 'ⲹ',
  11450 => 'ⲻ',
  11452 => 'ⲽ',
  11454 => 'ⲿ',
  11456 => 'ⳁ',
  11458 => 'ⳃ',
  11460 => 'ⳅ',
  11462 => 'ⳇ',
  11464 => 'ⳉ',
  11466 => 'ⳋ',
  11468 => 'ⳍ',
  11470 => 'ⳏ',
  11472 => 'ⳑ',
  11474 => 'ⳓ',
  11476 => 'ⳕ',
  11478 => 'ⳗ',
  11480 => 'ⳙ',
  11482 => 'ⳛ',
  11484 => 'ⳝ',
  11486 => 'ⳟ',
  11488 => 'ⳡ',
  11490 => 'ⳣ',
  11499 => 'ⳬ',
  11501 => 'ⳮ',
  11506 => 'ⳳ',
  11631 => 'ⵡ',
  11935 => '母',
  12019 => '龟',
  12032 => '一',
  12033 => '丨',
  12034 => '丶',
  12035 => '丿',
  12036 => '乙',
  12037 => '亅',
  12038 => '二',
  12039 => '亠',
  12040 => '人',
  12041 => '儿',
  12042 => '入',
  12043 => '八',
  12044 => '冂',
  12045 => '冖',
  12046 => '冫',
  12047 => '几',
  12048 => '凵',
  12049 => '刀',
  12050 => '力',
  12051 => '勹',
  12052 => '匕',
  12053 => '匚',
  12054 => '匸',
  12055 => '十',
  12056 => '卜',
  12057 => '卩',
  12058 => '厂',
  12059 => '厶',
  12060 => '又',
  12061 => '口',
  12062 => '囗',
  12063 => '土',
  12064 => '士',
  12065 => '夂',
  12066 => '夊',
  12067 => '夕',
  12068 => '大',
  12069 => '女',
  12070 => '子',
  12071 => '宀',
  12072 => '寸',
  12073 => '小',
  12074 => '尢',
  12075 => '尸',
  12076 => '屮',
  12077 => '山',
  12078 => '巛',
  12079 => '工',
  12080 => '己',
  12081 => '巾',
  12082 => '干',
  12083 => '幺',
  12084 => '广',
  12085 => '廴',
  12086 => '廾',
  12087 => '弋',
  12088 => '弓',
  12089 => '彐',
  12090 => '彡',
  12091 => '彳',
  12092 => '心',
  12093 => '戈',
  12094 => '戶',
  12095 => '手',
  12096 => '支',
  12097 => '攴',
  12098 => '文',
  12099 => '斗',
  12100 => '斤',
  12101 => '方',
  12102 => '无',
  12103 => '日',
  12104 => '曰',
  12105 => '月',
  12106 => '木',
  12107 => '欠',
  12108 => '止',
  12109 => '歹',
  12110 => '殳',
  12111 => '毋',
  12112 => '比',
  12113 => '毛',
  12114 => '氏',
  12115 => '气',
  12116 => '水',
  12117 => '火',
  12118 => '爪',
  12119 => '父',
  12120 => '爻',
  12121 => '爿',
  12122 => '片',
  12123 => '牙',
  12124 => '牛',
  12125 => '犬',
  12126 => '玄',
  12127 => '玉',
  12128 => '瓜',
  12129 => '瓦',
  12130 => '甘',
  12131 => '生',
  12132 => '用',
  12133 => '田',
  12134 => '疋',
  12135 => '疒',
  12136 => '癶',
  12137 => '白',
  12138 => '皮',
  12139 => '皿',
  12140 => '目',
  12141 => '矛',
  12142 => '矢',
  12143 => '石',
  12144 => '示',
  12145 => '禸',
  12146 => '禾',
  12147 => '穴',
  12148 => '立',
  12149 => '竹',
  12150 => '米',
  12151 => '糸',
  12152 => '缶',
  12153 => '网',
  12154 => '羊',
  12155 => '羽',
  12156 => '老',
  12157 => '而',
  12158 => '耒',
  12159 => '耳',
  12160 => '聿',
  12161 => '肉',
  12162 => '臣',
  12163 => '自',
  12164 => '至',
  12165 => '臼',
  12166 => '舌',
  12167 => '舛',
  12168 => '舟',
  12169 => '艮',
  12170 => '色',
  12171 => '艸',
  12172 => '虍',
  12173 => '虫',
  12174 => '血',
  12175 => '行',
  12176 => '衣',
  12177 => '襾',
  12178 => '見',
  12179 => '角',
  12180 => '言',
  12181 => '谷',
  12182 => '豆',
  12183 => '豕',
  12184 => '豸',
  12185 => '貝',
  12186 => '赤',
  12187 => '走',
  12188 => '足',
  12189 => '身',
  12190 => '車',
  12191 => '辛',
  12192 => '辰',
  12193 => '辵',
  12194 => '邑',
  12195 => '酉',
  12196 => '釆',
  12197 => '里',
  12198 => '金',
  12199 => '長',
  12200 => '門',
  12201 => '阜',
  12202 => '隶',
  12203 => '隹',
  12204 => '雨',
  12205 => '靑',
  12206 => '非',
  12207 => '面',
  12208 => '革',
  12209 => '韋',
  12210 => '韭',
  12211 => '音',
  12212 => '頁',
  12213 => '風',
  12214 => '飛',
  12215 => '食',
  12216 => '首',
  12217 => '香',
  12218 => '馬',
  12219 => '骨',
  12220 => '高',
  12221 => '髟',
  12222 => '鬥',
  12223 => '鬯',
  12224 => '鬲',
  12225 => '鬼',
  12226 => '魚',
  12227 => '鳥',
  12228 => '鹵',
  12229 => '鹿',
  12230 => '麥',
  12231 => '麻',
  12232 => '黃',
  12233 => '黍',
  12234 => '黑',
  12235 => '黹',
  12236 => '黽',
  12237 => '鼎',
  12238 => '鼓',
  12239 => '鼠',
  12240 => '鼻',
  12241 => '齊',
  12242 => '齒',
  12243 => '龍',
  12244 => '龜',
  12245 => '龠',
  12290 => '.',
  12342 => '〒',
  12344 => '十',
  12345 => '卄',
  12346 => '卅',
  12447 => 'より',
  12543 => 'コト',
  12593 => 'ᄀ',
  12594 => 'ᄁ',
  12595 => 'ᆪ',
  12596 => 'ᄂ',
  12597 => 'ᆬ',
  12598 => 'ᆭ',
  12599 => 'ᄃ',
  12600 => 'ᄄ',
  12601 => 'ᄅ',
  12602 => 'ᆰ',
  12603 => 'ᆱ',
  12604 => 'ᆲ',
  12605 => 'ᆳ',
  12606 => 'ᆴ',
  12607 => 'ᆵ',
  12608 => 'ᄚ',
  12609 => 'ᄆ',
  12610 => 'ᄇ',
  12611 => 'ᄈ',
  12612 => 'ᄡ',
  12613 => 'ᄉ',
  12614 => 'ᄊ',
  12615 => 'ᄋ',
  12616 => 'ᄌ',
  12617 => 'ᄍ',
  12618 => 'ᄎ',
  12619 => 'ᄏ',
  12620 => 'ᄐ',
  12621 => 'ᄑ',
  12622 => 'ᄒ',
  12623 => 'ᅡ',
  12624 => 'ᅢ',
  12625 => 'ᅣ',
  12626 => 'ᅤ',
  12627 => 'ᅥ',
  12628 => 'ᅦ',
  12629 => 'ᅧ',
  12630 => 'ᅨ',
  12631 => 'ᅩ',
  12632 => 'ᅪ',
  12633 => 'ᅫ',
  12634 => 'ᅬ',
  12635 => 'ᅭ',
  12636 => 'ᅮ',
  12637 => 'ᅯ',
  12638 => 'ᅰ',
  12639 => 'ᅱ',
  12640 => 'ᅲ',
  12641 => 'ᅳ',
  12642 => 'ᅴ',
  12643 => 'ᅵ',
  12645 => 'ᄔ',
  12646 => 'ᄕ',
  12647 => 'ᇇ',
  12648 => 'ᇈ',
  12649 => 'ᇌ',
  12650 => 'ᇎ',
  12651 => 'ᇓ',
  12652 => 'ᇗ',
  12653 => 'ᇙ',
  12654 => 'ᄜ',
  12655 => 'ᇝ',
  12656 => 'ᇟ',
  12657 => 'ᄝ',
  12658 => 'ᄞ',
  12659 => 'ᄠ',
  12660 => 'ᄢ',
  12661 => 'ᄣ',
  12662 => 'ᄧ',
  12663 => 'ᄩ',
  12664 => 'ᄫ',
  12665 => 'ᄬ',
  12666 => 'ᄭ',
  12667 => 'ᄮ',
  12668 => 'ᄯ',
  12669 => 'ᄲ',
  12670 => 'ᄶ',
  12671 => 'ᅀ',
  12672 => 'ᅇ',
  12673 => 'ᅌ',
  12674 => 'ᇱ',
  12675 => 'ᇲ',
  12676 => 'ᅗ',
  12677 => 'ᅘ',
  12678 => 'ᅙ',
  12679 => 'ᆄ',
  12680 => 'ᆅ',
  12681 => 'ᆈ',
  12682 => 'ᆑ',
  12683 => 'ᆒ',
  12684 => 'ᆔ',
  12685 => 'ᆞ',
  12686 => 'ᆡ',
  12690 => '一',
  12691 => '二',
  12692 => '三',
  12693 => '四',
  12694 => '上',
  12695 => '中',
  12696 => '下',
  12697 => '甲',
  12698 => '乙',
  12699 => '丙',
  12700 => '丁',
  12701 => '天',
  12702 => '地',
  12703 => '人',
  12868 => '問',
  12869 => '幼',
  12870 => '文',
  12871 => '箏',
  12880 => 'pte',
  12881 => '21',
  12882 => '22',
  12883 => '23',
  12884 => '24',
  12885 => '25',
  12886 => '26',
  12887 => '27',
  12888 => '28',
  12889 => '29',
  12890 => '30',
  12891 => '31',
  12892 => '32',
  12893 => '33',
  12894 => '34',
  12895 => '35',
  12896 => 'ᄀ',
  12897 => 'ᄂ',
  12898 => 'ᄃ',
  12899 => 'ᄅ',
  12900 => 'ᄆ',
  12901 => 'ᄇ',
  12902 => 'ᄉ',
  12903 => 'ᄋ',
  12904 => 'ᄌ',
  12905 => 'ᄎ',
  12906 => 'ᄏ',
  12907 => 'ᄐ',
  12908 => 'ᄑ',
  12909 => 'ᄒ',
  12910 => '가',
  12911 => '나',
  12912 => '다',
  12913 => '라',
  12914 => '마',
  12915 => '바',
  12916 => '사',
  12917 => '아',
  12918 => '자',
  12919 => '차',
  12920 => '카',
  12921 => '타',
  12922 => '파',
  12923 => '하',
  12924 => '참고',
  12925 => '주의',
  12926 => '우',
  12928 => '一',
  12929 => '二',
  12930 => '三',
  12931 => '四',
  12932 => '五',
  12933 => '六',
  12934 => '七',
  12935 => '八',
  12936 => '九',
  12937 => '十',
  12938 => '月',
  12939 => '火',
  12940 => '水',
  12941 => '木',
  12942 => '金',
  12943 => '土',
  12944 => '日',
  12945 => '株',
  12946 => '有',
  12947 => '社',
  12948 => '名',
  12949 => '特',
  12950 => '財',
  12951 => '祝',
  12952 => '労',
  12953 => '秘',
  12954 => '男',
  12955 => '女',
  12956 => '適',
  12957 => '優',
  12958 => '印',
  12959 => '注',
  12960 => '項',
  12961 => '休',
  12962 => '写',
  12963 => '正',
  12964 => '上',
  12965 => '中',
  12966 => '下',
  12967 => '左',
  12968 => '右',
  12969 => '医',
  12970 => '宗',
  12971 => '学',
  12972 => '監',
  12973 => '企',
  12974 => '資',
  12975 => '協',
  12976 => '夜',
  12977 => '36',
  12978 => '37',
  12979 => '38',
  12980 => '39',
  12981 => '40',
  12982 => '41',
  12983 => '42',
  12984 => '43',
  12985 => '44',
  12986 => '45',
  12987 => '46',
  12988 => '47',
  12989 => '48',
  12990 => '49',
  12991 => '50',
  12992 => '1月',
  12993 => '2月',
  12994 => '3月',
  12995 => '4月',
  12996 => '5月',
  12997 => '6月',
  12998 => '7月',
  12999 => '8月',
  13000 => '9月',
  13001 => '10月',
  13002 => '11月',
  13003 => '12月',
  13004 => 'hg',
  13005 => 'erg',
  13006 => 'ev',
  13007 => 'ltd',
  13008 => 'ア',
  13009 => 'イ',
  13010 => 'ウ',
  13011 => 'エ',
  13012 => 'オ',
  13013 => 'カ',
  13014 => 'キ',
  13015 => 'ク',
  13016 => 'ケ',
  13017 => 'コ',
  13018 => 'サ',
  13019 => 'シ',
  13020 => 'ス',
  13021 => 'セ',
  13022 => 'ソ',
  13023 => 'タ',
  13024 => 'チ',
  13025 => 'ツ',
  13026 => 'テ',
  13027 => 'ト',
  13028 => 'ナ',
  13029 => 'ニ',
  13030 => 'ヌ',
  13031 => 'ネ',
  13032 => 'ノ',
  13033 => 'ハ',
  13034 => 'ヒ',
  13035 => 'フ',
  13036 => 'ヘ',
  13037 => 'ホ',
  13038 => 'マ',
  13039 => 'ミ',
  13040 => 'ム',
  13041 => 'メ',
  13042 => 'モ',
  13043 => 'ヤ',
  13044 => 'ユ',
  13045 => 'ヨ',
  13046 => 'ラ',
  13047 => 'リ',
  13048 => 'ル',
  13049 => 'レ',
  13050 => 'ロ',
  13051 => 'ワ',
  13052 => 'ヰ',
  13053 => 'ヱ',
  13054 => 'ヲ',
  13055 => '令和',
  13056 => 'アパート',
  13057 => 'アルファ',
  13058 => 'アンペア',
  13059 => 'アール',
  13060 => 'イニング',
  13061 => 'インチ',
  13062 => 'ウォン',
  13063 => 'エスクード',
  13064 => 'エーカー',
  13065 => 'オンス',
  13066 => 'オーム',
  13067 => 'カイリ',
  13068 => 'カラット',
  13069 => 'カロリー',
  13070 => 'ガロン',
  13071 => 'ガンマ',
  13072 => 'ギガ',
  13073 => 'ギニー',
  13074 => 'キュリー',
  13075 => 'ギルダー',
  13076 => 'キロ',
  13077 => 'キログラム',
  13078 => 'キロメートル',
  13079 => 'キロワット',
  13080 => 'グラム',
  13081 => 'グラムトン',
  13082 => 'クルゼイロ',
  13083 => 'クローネ',
  13084 => 'ケース',
  13085 => 'コルナ',
  13086 => 'コーポ',
  13087 => 'サイクル',
  13088 => 'サンチーム',
  13089 => 'シリング',
  13090 => 'センチ',
  13091 => 'セント',
  13092 => 'ダース',
  13093 => 'デシ',
  13094 => 'ドル',
  13095 => 'トン',
  13096 => 'ナノ',
  13097 => 'ノット',
  13098 => 'ハイツ',
  13099 => 'パーセント',
  13100 => 'パーツ',
  13101 => 'バーレル',
  13102 => 'ピアストル',
  13103 => 'ピクル',
  13104 => 'ピコ',
  13105 => 'ビル',
  13106 => 'ファラッド',
  13107 => 'フィート',
  13108 => 'ブッシェル',
  13109 => 'フラン',
  13110 => 'ヘクタール',
  13111 => 'ペソ',
  13112 => 'ペニヒ',
  13113 => 'ヘルツ',
  13114 => 'ペンス',
  13115 => 'ページ',
  13116 => 'ベータ',
  13117 => 'ポイント',
  13118 => 'ボルト',
  13119 => 'ホン',
  13120 => 'ポンド',
  13121 => 'ホール',
  13122 => 'ホーン',
  13123 => 'マイクロ',
  13124 => 'マイル',
  13125 => 'マッハ',
  13126 => 'マルク',
  13127 => 'マンション',
  13128 => 'ミクロン',
  13129 => 'ミリ',
  13130 => 'ミリバール',
  13131 => 'メガ',
  13132 => 'メガトン',
  13133 => 'メートル',
  13134 => 'ヤード',
  13135 => 'ヤール',
  13136 => 'ユアン',
  13137 => 'リットル',
  13138 => 'リラ',
  13139 => 'ルピー',
  13140 => 'ルーブル',
  13141 => 'レム',
  13142 => 'レントゲン',
  13143 => 'ワット',
  13144 => '0点',
  13145 => '1点',
  13146 => '2点',
  13147 => '3点',
  13148 => '4点',
  13149 => '5点',
  13150 => '6点',
  13151 => '7点',
  13152 => '8点',
  13153 => '9点',
  13154 => '10点',
  13155 => '11点',
  13156 => '12点',
  13157 => '13点',
  13158 => '14点',
  13159 => '15点',
  13160 => '16点',
  13161 => '17点',
  13162 => '18点',
  13163 => '19点',
  13164 => '20点',
  13165 => '21点',
  13166 => '22点',
  13167 => '23点',
  13168 => '24点',
  13169 => 'hpa',
  13170 => 'da',
  13171 => 'au',
  13172 => 'bar',
  13173 => 'ov',
  13174 => 'pc',
  13175 => 'dm',
  13176 => 'dm2',
  13177 => 'dm3',
  13178 => 'iu',
  13179 => '平成',
  13180 => '昭和',
  13181 => '大正',
  13182 => '明治',
  13183 => '株式会社',
  13184 => 'pa',
  13185 => 'na',
  13186 => 'μa',
  13187 => 'ma',
  13188 => 'ka',
  13189 => 'kb',
  13190 => 'mb',
  13191 => 'gb',
  13192 => 'cal',
  13193 => 'kcal',
  13194 => 'pf',
  13195 => 'nf',
  13196 => 'μf',
  13197 => 'μg',
  13198 => 'mg',
  13199 => 'kg',
  13200 => 'hz',
  13201 => 'khz',
  13202 => 'mhz',
  13203 => 'ghz',
  13204 => 'thz',
  13205 => 'μl',
  13206 => 'ml',
  13207 => 'dl',
  13208 => 'kl',
  13209 => 'fm',
  13210 => 'nm',
  13211 => 'μm',
  13212 => 'mm',
  13213 => 'cm',
  13214 => 'km',
  13215 => 'mm2',
  13216 => 'cm2',
  13217 => 'm2',
  13218 => 'km2',
  13219 => 'mm3',
  13220 => 'cm3',
  13221 => 'm3',
  13222 => 'km3',
  13223 => 'm∕s',
  13224 => 'm∕s2',
  13225 => 'pa',
  13226 => 'kpa',
  13227 => 'mpa',
  13228 => 'gpa',
  13229 => 'rad',
  13230 => 'rad∕s',
  13231 => 'rad∕s2',
  13232 => 'ps',
  13233 => 'ns',
  13234 => 'μs',
  13235 => 'ms',
  13236 => 'pv',
  13237 => 'nv',
  13238 => 'μv',
  13239 => 'mv',
  13240 => 'kv',
  13241 => 'mv',
  13242 => 'pw',
  13243 => 'nw',
  13244 => 'μw',
  13245 => 'mw',
  13246 => 'kw',
  13247 => 'mw',
  13248 => 'kω',
  13249 => 'mω',
  13251 => 'bq',
  13252 => 'cc',
  13253 => 'cd',
  13254 => 'c∕kg',
  13256 => 'db',
  13257 => 'gy',
  13258 => 'ha',
  13259 => 'hp',
  13260 => 'in',
  13261 => 'kk',
  13262 => 'km',
  13263 => 'kt',
  13264 => 'lm',
  13265 => 'ln',
  13266 => 'log',
  13267 => 'lx',
  13268 => 'mb',
  13269 => 'mil',
  13270 => 'mol',
  13271 => 'ph',
  13273 => 'ppm',
  13274 => 'pr',
  13275 => 'sr',
  13276 => 'sv',
  13277 => 'wb',
  13278 => 'v∕m',
  13279 => 'a∕m',
  13280 => '1日',
  13281 => '2日',
  13282 => '3日',
  13283 => '4日',
  13284 => '5日',
  13285 => '6日',
  13286 => '7日',
  13287 => '8日',
  13288 => '9日',
  13289 => '10日',
  13290 => '11日',
  13291 => '12日',
  13292 => '13日',
  13293 => '14日',
  13294 => '15日',
  13295 => '16日',
  13296 => '17日',
  13297 => '18日',
  13298 => '19日',
  13299 => '20日',
  13300 => '21日',
  13301 => '22日',
  13302 => '23日',
  13303 => '24日',
  13304 => '25日',
  13305 => '26日',
  13306 => '27日',
  13307 => '28日',
  13308 => '29日',
  13309 => '30日',
  13310 => '31日',
  13311 => 'gal',
  42560 => 'ꙁ',
  42562 => 'ꙃ',
  42564 => 'ꙅ',
  42566 => 'ꙇ',
  42568 => 'ꙉ',
  42570 => 'ꙋ',
  42572 => 'ꙍ',
  42574 => 'ꙏ',
  42576 => 'ꙑ',
  42578 => 'ꙓ',
  42580 => 'ꙕ',
  42582 => 'ꙗ',
  42584 => 'ꙙ',
  42586 => 'ꙛ',
  42588 => 'ꙝ',
  42590 => 'ꙟ',
  42592 => 'ꙡ',
  42594 => 'ꙣ',
  42596 => 'ꙥ',
  42598 => 'ꙧ',
  42600 => 'ꙩ',
  42602 => 'ꙫ',
  42604 => 'ꙭ',
  42624 => 'ꚁ',
  42626 => 'ꚃ',
  42628 => 'ꚅ',
  42630 => 'ꚇ',
  42632 => 'ꚉ',
  42634 => 'ꚋ',
  42636 => 'ꚍ',
  42638 => 'ꚏ',
  42640 => 'ꚑ',
  42642 => 'ꚓ',
  42644 => 'ꚕ',
  42646 => 'ꚗ',
  42648 => 'ꚙ',
  42650 => 'ꚛ',
  42652 => 'ъ',
  42653 => 'ь',
  42786 => 'ꜣ',
  42788 => 'ꜥ',
  42790 => 'ꜧ',
  42792 => 'ꜩ',
  42794 => 'ꜫ',
  42796 => 'ꜭ',
  42798 => 'ꜯ',
  42802 => 'ꜳ',
  42804 => 'ꜵ',
  42806 => 'ꜷ',
  42808 => 'ꜹ',
  42810 => 'ꜻ',
  42812 => 'ꜽ',
  42814 => 'ꜿ',
  42816 => 'ꝁ',
  42818 => 'ꝃ',
  42820 => 'ꝅ',
  42822 => 'ꝇ',
  42824 => 'ꝉ',
  42826 => 'ꝋ',
  42828 => 'ꝍ',
  42830 => 'ꝏ',
  42832 => 'ꝑ',
  42834 => 'ꝓ',
  42836 => 'ꝕ',
  42838 => 'ꝗ',
  42840 => 'ꝙ',
  42842 => 'ꝛ',
  42844 => 'ꝝ',
  42846 => 'ꝟ',
  42848 => 'ꝡ',
  42850 => 'ꝣ',
  42852 => 'ꝥ',
  42854 => 'ꝧ',
  42856 => 'ꝩ',
  42858 => 'ꝫ',
  42860 => 'ꝭ',
  42862 => 'ꝯ',
  42864 => 'ꝯ',
  42873 => 'ꝺ',
  42875 => 'ꝼ',
  42877 => 'ᵹ',
  42878 => 'ꝿ',
  42880 => 'ꞁ',
  42882 => 'ꞃ',
  42884 => 'ꞅ',
  42886 => 'ꞇ',
  42891 => 'ꞌ',
  42893 => 'ɥ',
  42896 => 'ꞑ',
  42898 => 'ꞓ',
  42902 => 'ꞗ',
  42904 => 'ꞙ',
  42906 => 'ꞛ',
  42908 => 'ꞝ',
  42910 => 'ꞟ',
  42912 => 'ꞡ',
  42914 => 'ꞣ',
  42916 => 'ꞥ',
  42918 => 'ꞧ',
  42920 => 'ꞩ',
  42922 => 'ɦ',
  42923 => 'ɜ',
  42924 => 'ɡ',
  42925 => 'ɬ',
  42926 => 'ɪ',
  42928 => 'ʞ',
  42929 => 'ʇ',
  42930 => 'ʝ',
  42931 => 'ꭓ',
  42932 => 'ꞵ',
  42934 => 'ꞷ',
  42936 => 'ꞹ',
  42938 => 'ꞻ',
  42940 => 'ꞽ',
  42942 => 'ꞿ',
  42946 => 'ꟃ',
  42948 => 'ꞔ',
  42949 => 'ʂ',
  42950 => 'ᶎ',
  42951 => 'ꟈ',
  42953 => 'ꟊ',
  42997 => 'ꟶ',
  43000 => 'ħ',
  43001 => 'œ',
  43868 => 'ꜧ',
  43869 => 'ꬷ',
  43870 => 'ɫ',
  43871 => 'ꭒ',
  43881 => 'ʍ',
  43888 => 'Ꭰ',
  43889 => 'Ꭱ',
  43890 => 'Ꭲ',
  43891 => 'Ꭳ',
  43892 => 'Ꭴ',
  43893 => 'Ꭵ',
  43894 => 'Ꭶ',
  43895 => 'Ꭷ',
  43896 => 'Ꭸ',
  43897 => 'Ꭹ',
  43898 => 'Ꭺ',
  43899 => 'Ꭻ',
  43900 => 'Ꭼ',
  43901 => 'Ꭽ',
  43902 => 'Ꭾ',
  43903 => 'Ꭿ',
  43904 => 'Ꮀ',
  43905 => 'Ꮁ',
  43906 => 'Ꮂ',
  43907 => 'Ꮃ',
  43908 => 'Ꮄ',
  43909 => 'Ꮅ',
  43910 => 'Ꮆ',
  43911 => 'Ꮇ',
  43912 => 'Ꮈ',
  43913 => 'Ꮉ',
  43914 => 'Ꮊ',
  43915 => 'Ꮋ',
  43916 => 'Ꮌ',
  43917 => 'Ꮍ',
  43918 => 'Ꮎ',
  43919 => 'Ꮏ',
  43920 => 'Ꮐ',
  43921 => 'Ꮑ',
  43922 => 'Ꮒ',
  43923 => 'Ꮓ',
  43924 => 'Ꮔ',
  43925 => 'Ꮕ',
  43926 => 'Ꮖ',
  43927 => 'Ꮗ',
  43928 => 'Ꮘ',
  43929 => 'Ꮙ',
  43930 => 'Ꮚ',
  43931 => 'Ꮛ',
  43932 => 'Ꮜ',
  43933 => 'Ꮝ',
  43934 => 'Ꮞ',
  43935 => 'Ꮟ',
  43936 => 'Ꮠ',
  43937 => 'Ꮡ',
  43938 => 'Ꮢ',
  43939 => 'Ꮣ',
  43940 => 'Ꮤ',
  43941 => 'Ꮥ',
  43942 => 'Ꮦ',
  43943 => 'Ꮧ',
  43944 => 'Ꮨ',
  43945 => 'Ꮩ',
  43946 => 'Ꮪ',
  43947 => 'Ꮫ',
  43948 => 'Ꮬ',
  43949 => 'Ꮭ',
  43950 => 'Ꮮ',
  43951 => 'Ꮯ',
  43952 => 'Ꮰ',
  43953 => 'Ꮱ',
  43954 => 'Ꮲ',
  43955 => 'Ꮳ',
  43956 => 'Ꮴ',
  43957 => 'Ꮵ',
  43958 => 'Ꮶ',
  43959 => 'Ꮷ',
  43960 => 'Ꮸ',
  43961 => 'Ꮹ',
  43962 => 'Ꮺ',
  43963 => 'Ꮻ',
  43964 => 'Ꮼ',
  43965 => 'Ꮽ',
  43966 => 'Ꮾ',
  43967 => 'Ꮿ',
  63744 => '豈',
  63745 => '更',
  63746 => '車',
  63747 => '賈',
  63748 => '滑',
  63749 => '串',
  63750 => '句',
  63751 => '龜',
  63752 => '龜',
  63753 => '契',
  63754 => '金',
  63755 => '喇',
  63756 => '奈',
  63757 => '懶',
  63758 => '癩',
  63759 => '羅',
  63760 => '蘿',
  63761 => '螺',
  63762 => '裸',
  63763 => '邏',
  63764 => '樂',
  63765 => '洛',
  63766 => '烙',
  63767 => '珞',
  63768 => '落',
  63769 => '酪',
  63770 => '駱',
  63771 => '亂',
  63772 => '卵',
  63773 => '欄',
  63774 => '爛',
  63775 => '蘭',
  63776 => '鸞',
  63777 => '嵐',
  63778 => '濫',
  63779 => '藍',
  63780 => '襤',
  63781 => '拉',
  63782 => '臘',
  63783 => '蠟',
  63784 => '廊',
  63785 => '朗',
  63786 => '浪',
  63787 => '狼',
  63788 => '郎',
  63789 => '來',
  63790 => '冷',
  63791 => '勞',
  63792 => '擄',
  63793 => '櫓',
  63794 => '爐',
  63795 => '盧',
  63796 => '老',
  63797 => '蘆',
  63798 => '虜',
  63799 => '路',
  63800 => '露',
  63801 => '魯',
  63802 => '鷺',
  63803 => '碌',
  63804 => '祿',
  63805 => '綠',
  63806 => '菉',
  63807 => '錄',
  63808 => '鹿',
  63809 => '論',
  63810 => '壟',
  63811 => '弄',
  63812 => '籠',
  63813 => '聾',
  63814 => '牢',
  63815 => '磊',
  63816 => '賂',
  63817 => '雷',
  63818 => '壘',
  63819 => '屢',
  63820 => '樓',
  63821 => '淚',
  63822 => '漏',
  63823 => '累',
  63824 => '縷',
  63825 => '陋',
  63826 => '勒',
  63827 => '肋',
  63828 => '凜',
  63829 => '凌',
  63830 => '稜',
  63831 => '綾',
  63832 => '菱',
  63833 => '陵',
  63834 => '讀',
  63835 => '拏',
  63836 => '樂',
  63837 => '諾',
  63838 => '丹',
  63839 => '寧',
  63840 => '怒',
  63841 => '率',
  63842 => '異',
  63843 => '北',
  63844 => '磻',
  63845 => '便',
  63846 => '復',
  63847 => '不',
  63848 => '泌',
  63849 => '數',
  63850 => '索',
  63851 => '參',
  63852 => '塞',
  63853 => '省',
  63854 => '葉',
  63855 => '說',
  63856 => '殺',
  63857 => '辰',
  63858 => '沈',
  63859 => '拾',
  63860 => '若',
  63861 => '掠',
  63862 => '略',
  63863 => '亮',
  63864 => '兩',
  63865 => '凉',
  63866 => '梁',
  63867 => '糧',
  63868 => '良',
  63869 => '諒',
  63870 => '量',
  63871 => '勵',
  63872 => '呂',
  63873 => '女',
  63874 => '廬',
  63875 => '旅',
  63876 => '濾',
  63877 => '礪',
  63878 => '閭',
  63879 => '驪',
  63880 => '麗',
  63881 => '黎',
  63882 => '力',
  63883 => '曆',
  63884 => '歷',
  63885 => '轢',
  63886 => '年',
  63887 => '憐',
  63888 => '戀',
  63889 => '撚',
  63890 => '漣',
  63891 => '煉',
  63892 => '璉',
  63893 => '秊',
  63894 => '練',
  63895 => '聯',
  63896 => '輦',
  63897 => '蓮',
  63898 => '連',
  63899 => '鍊',
  63900 => '列',
  63901 => '劣',
  63902 => '咽',
  63903 => '烈',
  63904 => '裂',
  63905 => '說',
  63906 => '廉',
  63907 => '念',
  63908 => '捻',
  63909 => '殮',
  63910 => '簾',
  63911 => '獵',
  63912 => '令',
  63913 => '囹',
  63914 => '寧',
  63915 => '嶺',
  63916 => '怜',
  63917 => '玲',
  63918 => '瑩',
  63919 => '羚',
  63920 => '聆',
  63921 => '鈴',
  63922 => '零',
  63923 => '靈',
  63924 => '領',
  63925 => '例',
  63926 => '禮',
  63927 => '醴',
  63928 => '隸',
  63929 => '惡',
  63930 => '了',
  63931 => '僚',
  63932 => '寮',
  63933 => '尿',
  63934 => '料',
  63935 => '樂',
  63936 => '燎',
  63937 => '療',
  63938 => '蓼',
  63939 => '遼',
  63940 => '龍',
  63941 => '暈',
  63942 => '阮',
  63943 => '劉',
  63944 => '杻',
  63945 => '柳',
  63946 => '流',
  63947 => '溜',
  63948 => '琉',
  63949 => '留',
  63950 => '硫',
  63951 => '紐',
  63952 => '類',
  63953 => '六',
  63954 => '戮',
  63955 => '陸',
  63956 => '倫',
  63957 => '崙',
  63958 => '淪',
  63959 => '輪',
  63960 => '律',
  63961 => '慄',
  63962 => '栗',
  63963 => '率',
  63964 => '隆',
  63965 => '利',
  63966 => '吏',
  63967 => '履',
  63968 => '易',
  63969 => '李',
  63970 => '梨',
  63971 => '泥',
  63972 => '理',
  63973 => '痢',
  63974 => '罹',
  63975 => '裏',
  63976 => '裡',
  63977 => '里',
  63978 => '離',
  63979 => '匿',
  63980 => '溺',
  63981 => '吝',
  63982 => '燐',
  63983 => '璘',
  63984 => '藺',
  63985 => '隣',
  63986 => '鱗',
  63987 => '麟',
  63988 => '林',
  63989 => '淋',
  63990 => '臨',
  63991 => '立',
  63992 => '笠',
  63993 => '粒',
  63994 => '狀',
  63995 => '炙',
  63996 => '識',
  63997 => '什',
  63998 => '茶',
  63999 => '刺',
  64000 => '切',
  64001 => '度',
  64002 => '拓',
  64003 => '糖',
  64004 => '宅',
  64005 => '洞',
  64006 => '暴',
  64007 => '輻',
  64008 => '行',
  64009 => '降',
  64010 => '見',
  64011 => '廓',
  64012 => '兀',
  64013 => '嗀',
  64016 => '塚',
  64018 => '晴',
  64021 => '凞',
  64022 => '猪',
  64023 => '益',
  64024 => '礼',
  64025 => '神',
  64026 => '祥',
  64027 => '福',
  64028 => '靖',
  64029 => '精',
  64030 => '羽',
  64032 => '蘒',
  64034 => '諸',
  64037 => '逸',
  64038 => '都',
  64042 => '飯',
  64043 => '飼',
  64044 => '館',
  64045 => '鶴',
  64046 => '郞',
  64047 => '隷',
  64048 => '侮',
  64049 => '僧',
  64050 => '免',
  64051 => '勉',
  64052 => '勤',
  64053 => '卑',
  64054 => '喝',
  64055 => '嘆',
  64056 => '器',
  64057 => '塀',
  64058 => '墨',
  64059 => '層',
  64060 => '屮',
  64061 => '悔',
  64062 => '慨',
  64063 => '憎',
  64064 => '懲',
  64065 => '敏',
  64066 => '既',
  64067 => '暑',
  64068 => '梅',
  64069 => '海',
  64070 => '渚',
  64071 => '漢',
  64072 => '煮',
  64073 => '爫',
  64074 => '琢',
  64075 => '碑',
  64076 => '社',
  64077 => '祉',
  64078 => '祈',
  64079 => '祐',
  64080 => '祖',
  64081 => '祝',
  64082 => '禍',
  64083 => '禎',
  64084 => '穀',
  64085 => '突',
  64086 => '節',
  64087 => '練',
  64088 => '縉',
  64089 => '繁',
  64090 => '署',
  64091 => '者',
  64092 => '臭',
  64093 => '艹',
  64094 => '艹',
  64095 => '著',
  64096 => '褐',
  64097 => '視',
  64098 => '謁',
  64099 => '謹',
  64100 => '賓',
  64101 => '贈',
  64102 => '辶',
  64103 => '逸',
  64104 => '難',
  64105 => '響',
  64106 => '頻',
  64107 => '恵',
  64108 => '𤋮',
  64109 => '舘',
  64112 => '並',
  64113 => '况',
  64114 => '全',
  64115 => '侀',
  64116 => '充',
  64117 => '冀',
  64118 => '勇',
  64119 => '勺',
  64120 => '喝',
  64121 => '啕',
  64122 => '喙',
  64123 => '嗢',
  64124 => '塚',
  64125 => '墳',
  64126 => '奄',
  64127 => '奔',
  64128 => '婢',
  64129 => '嬨',
  64130 => '廒',
  64131 => '廙',
  64132 => '彩',
  64133 => '徭',
  64134 => '惘',
  64135 => '慎',
  64136 => '愈',
  64137 => '憎',
  64138 => '慠',
  64139 => '懲',
  64140 => '戴',
  64141 => '揄',
  64142 => '搜',
  64143 => '摒',
  64144 => '敖',
  64145 => '晴',
  64146 => '朗',
  64147 => '望',
  64148 => '杖',
  64149 => '歹',
  64150 => '殺',
  64151 => '流',
  64152 => '滛',
  64153 => '滋',
  64154 => '漢',
  64155 => '瀞',
  64156 => '煮',
  64157 => '瞧',
  64158 => '爵',
  64159 => '犯',
  64160 => '猪',
  64161 => '瑱',
  64162 => '甆',
  64163 => '画',
  64164 => '瘝',
  64165 => '瘟',
  64166 => '益',
  64167 => '盛',
  64168 => '直',
  64169 => '睊',
  64170 => '着',
  64171 => '磌',
  64172 => '窱',
  64173 => '節',
  64174 => '类',
  64175 => '絛',
  64176 => '練',
  64177 => '缾',
  64178 => '者',
  64179 => '荒',
  64180 => '華',
  64181 => '蝹',
  64182 => '襁',
  64183 => '覆',
  64184 => '視',
  64185 => '調',
  64186 => '諸',
  64187 => '請',
  64188 => '謁',
  64189 => '諾',
  64190 => '諭',
  64191 => '謹',
  64192 => '變',
  64193 => '贈',
  64194 => '輸',
  64195 => '遲',
  64196 => '醙',
  64197 => '鉶',
  64198 => '陼',
  64199 => '難',
  64200 => '靖',
  64201 => '韛',
  64202 => '響',
  64203 => '頋',
  64204 => '頻',
  64205 => '鬒',
  64206 => '龜',
  64207 => '𢡊',
  64208 => '𢡄',
  64209 => '𣏕',
  64210 => '㮝',
  64211 => '䀘',
  64212 => '䀹',
  64213 => '𥉉',
  64214 => '𥳐',
  64215 => '𧻓',
  64216 => '齃',
  64217 => '龎',
  64256 => 'ff',
  64257 => 'fi',
  64258 => 'fl',
  64259 => 'ffi',
  64260 => 'ffl',
  64261 => 'st',
  64262 => 'st',
  64275 => 'մն',
  64276 => 'մե',
  64277 => 'մի',
  64278 => 'վն',
  64279 => 'մխ',
  64285 => 'יִ',
  64287 => 'ײַ',
  64288 => 'ע',
  64289 => 'א',
  64290 => 'ד',
  64291 => 'ה',
  64292 => 'כ',
  64293 => 'ל',
  64294 => 'ם',
  64295 => 'ר',
  64296 => 'ת',
  64298 => 'שׁ',
  64299 => 'שׂ',
  64300 => 'שּׁ',
  64301 => 'שּׂ',
  64302 => 'אַ',
  64303 => 'אָ',
  64304 => 'אּ',
  64305 => 'בּ',
  64306 => 'גּ',
  64307 => 'דּ',
  64308 => 'הּ',
  64309 => 'וּ',
  64310 => 'זּ',
  64312 => 'טּ',
  64313 => 'יּ',
  64314 => 'ךּ',
  64315 => 'כּ',
  64316 => 'לּ',
  64318 => 'מּ',
  64320 => 'נּ',
  64321 => 'סּ',
  64323 => 'ףּ',
  64324 => 'פּ',
  64326 => 'צּ',
  64327 => 'קּ',
  64328 => 'רּ',
  64329 => 'שּ',
  64330 => 'תּ',
  64331 => 'וֹ',
  64332 => 'בֿ',
  64333 => 'כֿ',
  64334 => 'פֿ',
  64335 => 'אל',
  64336 => 'ٱ',
  64337 => 'ٱ',
  64338 => 'ٻ',
  64339 => 'ٻ',
  64340 => 'ٻ',
  64341 => 'ٻ',
  64342 => 'پ',
  64343 => 'پ',
  64344 => 'پ',
  64345 => 'پ',
  64346 => 'ڀ',
  64347 => 'ڀ',
  64348 => 'ڀ',
  64349 => 'ڀ',
  64350 => 'ٺ',
  64351 => 'ٺ',
  64352 => 'ٺ',
  64353 => 'ٺ',
  64354 => 'ٿ',
  64355 => 'ٿ',
  64356 => 'ٿ',
  64357 => 'ٿ',
  64358 => 'ٹ',
  64359 => 'ٹ',
  64360 => 'ٹ',
  64361 => 'ٹ',
  64362 => 'ڤ',
  64363 => 'ڤ',
  64364 => 'ڤ',
  64365 => 'ڤ',
  64366 => 'ڦ',
  64367 => 'ڦ',
  64368 => 'ڦ',
  64369 => 'ڦ',
  64370 => 'ڄ',
  64371 => 'ڄ',
  64372 => 'ڄ',
  64373 => 'ڄ',
  64374 => 'ڃ',
  64375 => 'ڃ',
  64376 => 'ڃ',
  64377 => 'ڃ',
  64378 => 'چ',
  64379 => 'چ',
  64380 => 'چ',
  64381 => 'چ',
  64382 => 'ڇ',
  64383 => 'ڇ',
  64384 => 'ڇ',
  64385 => 'ڇ',
  64386 => 'ڍ',
  64387 => 'ڍ',
  64388 => 'ڌ',
  64389 => 'ڌ',
  64390 => 'ڎ',
  64391 => 'ڎ',
  64392 => 'ڈ',
  64393 => 'ڈ',
  64394 => 'ژ',
  64395 => 'ژ',
  64396 => 'ڑ',
  64397 => 'ڑ',
  64398 => 'ک',
  64399 => 'ک',
  64400 => 'ک',
  64401 => 'ک',
  64402 => 'گ',
  64403 => 'گ',
  64404 => 'گ',
  64405 => 'گ',
  64406 => 'ڳ',
  64407 => 'ڳ',
  64408 => 'ڳ',
  64409 => 'ڳ',
  64410 => 'ڱ',
  64411 => 'ڱ',
  64412 => 'ڱ',
  64413 => 'ڱ',
  64414 => 'ں',
  64415 => 'ں',
  64416 => 'ڻ',
  64417 => 'ڻ',
  64418 => 'ڻ',
  64419 => 'ڻ',
  64420 => 'ۀ',
  64421 => 'ۀ',
  64422 => 'ہ',
  64423 => 'ہ',
  64424 => 'ہ',
  64425 => 'ہ',
  64426 => 'ھ',
  64427 => 'ھ',
  64428 => 'ھ',
  64429 => 'ھ',
  64430 => 'ے',
  64431 => 'ے',
  64432 => 'ۓ',
  64433 => 'ۓ',
  64467 => 'ڭ',
  64468 => 'ڭ',
  64469 => 'ڭ',
  64470 => 'ڭ',
  64471 => 'ۇ',
  64472 => 'ۇ',
  64473 => 'ۆ',
  64474 => 'ۆ',
  64475 => 'ۈ',
  64476 => 'ۈ',
  64477 => 'ۇٴ',
  64478 => 'ۋ',
  64479 => 'ۋ',
  64480 => 'ۅ',
  64481 => 'ۅ',
  64482 => 'ۉ',
  64483 => 'ۉ',
  64484 => 'ې',
  64485 => 'ې',
  64486 => 'ې',
  64487 => 'ې',
  64488 => 'ى',
  64489 => 'ى',
  64490 => 'ئا',
  64491 => 'ئا',
  64492 => 'ئە',
  64493 => 'ئە',
  64494 => 'ئو',
  64495 => 'ئو',
  64496 => 'ئۇ',
  64497 => 'ئۇ',
  64498 => 'ئۆ',
  64499 => 'ئۆ',
  64500 => 'ئۈ',
  64501 => 'ئۈ',
  64502 => 'ئې',
  64503 => 'ئې',
  64504 => 'ئې',
  64505 => 'ئى',
  64506 => 'ئى',
  64507 => 'ئى',
  64508 => 'ی',
  64509 => 'ی',
  64510 => 'ی',
  64511 => 'ی',
  64512 => 'ئج',
  64513 => 'ئح',
  64514 => 'ئم',
  64515 => 'ئى',
  64516 => 'ئي',
  64517 => 'بج',
  64518 => 'بح',
  64519 => 'بخ',
  64520 => 'بم',
  64521 => 'بى',
  64522 => 'بي',
  64523 => 'تج',
  64524 => 'تح',
  64525 => 'تخ',
  64526 => 'تم',
  64527 => 'تى',
  64528 => 'تي',
  64529 => 'ثج',
  64530 => 'ثم',
  64531 => 'ثى',
  64532 => 'ثي',
  64533 => 'جح',
  64534 => 'جم',
  64535 => 'حج',
  64536 => 'حم',
  64537 => 'خج',
  64538 => 'خح',
  64539 => 'خم',
  64540 => 'سج',
  64541 => 'سح',
  64542 => 'سخ',
  64543 => 'سم',
  64544 => 'صح',
  64545 => 'صم',
  64546 => 'ضج',
  64547 => 'ضح',
  64548 => 'ضخ',
  64549 => 'ضم',
  64550 => 'طح',
  64551 => 'طم',
  64552 => 'ظم',
  64553 => 'عج',
  64554 => 'عم',
  64555 => 'غج',
  64556 => 'غم',
  64557 => 'فج',
  64558 => 'فح',
  64559 => 'فخ',
  64560 => 'فم',
  64561 => 'فى',
  64562 => 'في',
  64563 => 'قح',
  64564 => 'قم',
  64565 => 'قى',
  64566 => 'قي',
  64567 => 'كا',
  64568 => 'كج',
  64569 => 'كح',
  64570 => 'كخ',
  64571 => 'كل',
  64572 => 'كم',
  64573 => 'كى',
  64574 => 'كي',
  64575 => 'لج',
  64576 => 'لح',
  64577 => 'لخ',
  64578 => 'لم',
  64579 => 'لى',
  64580 => 'لي',
  64581 => 'مج',
  64582 => 'مح',
  64583 => 'مخ',
  64584 => 'مم',
  64585 => 'مى',
  64586 => 'مي',
  64587 => 'نج',
  64588 => 'نح',
  64589 => 'نخ',
  64590 => 'نم',
  64591 => 'نى',
  64592 => 'ني',
  64593 => 'هج',
  64594 => 'هم',
  64595 => 'هى',
  64596 => 'هي',
  64597 => 'يج',
  64598 => 'يح',
  64599 => 'يخ',
  64600 => 'يم',
  64601 => 'يى',
  64602 => 'يي',
  64603 => 'ذٰ',
  64604 => 'رٰ',
  64605 => 'ىٰ',
  64612 => 'ئر',
  64613 => 'ئز',
  64614 => 'ئم',
  64615 => 'ئن',
  64616 => 'ئى',
  64617 => 'ئي',
  64618 => 'بر',
  64619 => 'بز',
  64620 => 'بم',
  64621 => 'بن',
  64622 => 'بى',
  64623 => 'بي',
  64624 => 'تر',
  64625 => 'تز',
  64626 => 'تم',
  64627 => 'تن',
  64628 => 'تى',
  64629 => 'تي',
  64630 => 'ثر',
  64631 => 'ثز',
  64632 => 'ثم',
  64633 => 'ثن',
  64634 => 'ثى',
  64635 => 'ثي',
  64636 => 'فى',
  64637 => 'في',
  64638 => 'قى',
  64639 => 'قي',
  64640 => 'كا',
  64641 => 'كل',
  64642 => 'كم',
  64643 => 'كى',
  64644 => 'كي',
  64645 => 'لم',
  64646 => 'لى',
  64647 => 'لي',
  64648 => 'ما',
  64649 => 'مم',
  64650 => 'نر',
  64651 => 'نز',
  64652 => 'نم',
  64653 => 'نن',
  64654 => 'نى',
  64655 => 'ني',
  64656 => 'ىٰ',
  64657 => 'ير',
  64658 => 'يز',
  64659 => 'يم',
  64660 => 'ين',
  64661 => 'يى',
  64662 => 'يي',
  64663 => 'ئج',
  64664 => 'ئح',
  64665 => 'ئخ',
  64666 => 'ئم',
  64667 => 'ئه',
  64668 => 'بج',
  64669 => 'بح',
  64670 => 'بخ',
  64671 => 'بم',
  64672 => 'به',
  64673 => 'تج',
  64674 => 'تح',
  64675 => 'تخ',
  64676 => 'تم',
  64677 => 'ته',
  64678 => 'ثم',
  64679 => 'جح',
  64680 => 'جم',
  64681 => 'حج',
  64682 => 'حم',
  64683 => 'خج',
  64684 => 'خم',
  64685 => 'سج',
  64686 => 'سح',
  64687 => 'سخ',
  64688 => 'سم',
  64689 => 'صح',
  64690 => 'صخ',
  64691 => 'صم',
  64692 => 'ضج',
  64693 => 'ضح',
  64694 => 'ضخ',
  64695 => 'ضم',
  64696 => 'طح',
  64697 => 'ظم',
  64698 => 'عج',
  64699 => 'عم',
  64700 => 'غج',
  64701 => 'غم',
  64702 => 'فج',
  64703 => 'فح',
  64704 => 'فخ',
  64705 => 'فم',
  64706 => 'قح',
  64707 => 'قم',
  64708 => 'كج',
  64709 => 'كح',
  64710 => 'كخ',
  64711 => 'كل',
  64712 => 'كم',
  64713 => 'لج',
  64714 => 'لح',
  64715 => 'لخ',
  64716 => 'لم',
  64717 => 'له',
  64718 => 'مج',
  64719 => 'مح',
  64720 => 'مخ',
  64721 => 'مم',
  64722 => 'نج',
  64723 => 'نح',
  64724 => 'نخ',
  64725 => 'نم',
  64726 => 'نه',
  64727 => 'هج',
  64728 => 'هم',
  64729 => 'هٰ',
  64730 => 'يج',
  64731 => 'يح',
  64732 => 'يخ',
  64733 => 'يم',
  64734 => 'يه',
  64735 => 'ئم',
  64736 => 'ئه',
  64737 => 'بم',
  64738 => 'به',
  64739 => 'تم',
  64740 => 'ته',
  64741 => 'ثم',
  64742 => 'ثه',
  64743 => 'سم',
  64744 => 'سه',
  64745 => 'شم',
  64746 => 'شه',
  64747 => 'كل',
  64748 => 'كم',
  64749 => 'لم',
  64750 => 'نم',
  64751 => 'نه',
  64752 => 'يم',
  64753 => 'يه',
  64754 => 'ـَّ',
  64755 => 'ـُّ',
  64756 => 'ـِّ',
  64757 => 'طى',
  64758 => 'طي',
  64759 => 'عى',
  64760 => 'عي',
  64761 => 'غى',
  64762 => 'غي',
  64763 => 'سى',
  64764 => 'سي',
  64765 => 'شى',
  64766 => 'شي',
  64767 => 'حى',
  64768 => 'حي',
  64769 => 'جى',
  64770 => 'جي',
  64771 => 'خى',
  64772 => 'خي',
  64773 => 'صى',
  64774 => 'صي',
  64775 => 'ضى',
  64776 => 'ضي',
  64777 => 'شج',
  64778 => 'شح',
  64779 => 'شخ',
  64780 => 'شم',
  64781 => 'شر',
  64782 => 'سر',
  64783 => 'صر',
  64784 => 'ضر',
  64785 => 'طى',
  64786 => 'طي',
  64787 => 'عى',
  64788 => 'عي',
  64789 => 'غى',
  64790 => 'غي',
  64791 => 'سى',
  64792 => 'سي',
  64793 => 'شى',
  64794 => 'شي',
  64795 => 'حى',
  64796 => 'حي',
  64797 => 'جى',
  64798 => 'جي',
  64799 => 'خى',
  64800 => 'خي',
  64801 => 'صى',
  64802 => 'صي',
  64803 => 'ضى',
  64804 => 'ضي',
  64805 => 'شج',
  64806 => 'شح',
  64807 => 'شخ',
  64808 => 'شم',
  64809 => 'شر',
  64810 => 'سر',
  64811 => 'صر',
  64812 => 'ضر',
  64813 => 'شج',
  64814 => 'شح',
  64815 => 'شخ',
  64816 => 'شم',
  64817 => 'سه',
  64818 => 'شه',
  64819 => 'طم',
  64820 => 'سج',
  64821 => 'سح',
  64822 => 'سخ',
  64823 => 'شج',
  64824 => 'شح',
  64825 => 'شخ',
  64826 => 'طم',
  64827 => 'ظم',
  64828 => 'اً',
  64829 => 'اً',
  64848 => 'تجم',
  64849 => 'تحج',
  64850 => 'تحج',
  64851 => 'تحم',
  64852 => 'تخم',
  64853 => 'تمج',
  64854 => 'تمح',
  64855 => 'تمخ',
  64856 => 'جمح',
  64857 => 'جمح',
  64858 => 'حمي',
  64859 => 'حمى',
  64860 => 'سحج',
  64861 => 'سجح',
  64862 => 'سجى',
  64863 => 'سمح',
  64864 => 'سمح',
  64865 => 'سمج',
  64866 => 'سمم',
  64867 => 'سمم',
  64868 => 'صحح',
  64869 => 'صحح',
  64870 => 'صمم',
  64871 => 'شحم',
  64872 => 'شحم',
  64873 => 'شجي',
  64874 => 'شمخ',
  64875 => 'شمخ',
  64876 => 'شمم',
  64877 => 'شمم',
  64878 => 'ضحى',
  64879 => 'ضخم',
  64880 => 'ضخم',
  64881 => 'طمح',
  64882 => 'طمح',
  64883 => 'طمم',
  64884 => 'طمي',
  64885 => 'عجم',
  64886 => 'عمم',
  64887 => 'عمم',
  64888 => 'عمى',
  64889 => 'غمم',
  64890 => 'غمي',
  64891 => 'غمى',
  64892 => 'فخم',
  64893 => 'فخم',
  64894 => 'قمح',
  64895 => 'قمم',
  64896 => 'لحم',
  64897 => 'لحي',
  64898 => 'لحى',
  64899 => 'لجج',
  64900 => 'لجج',
  64901 => 'لخم',
  64902 => 'لخم',
  64903 => 'لمح',
  64904 => 'لمح',
  64905 => 'محج',
  64906 => 'محم',
  64907 => 'محي',
  64908 => 'مجح',
  64909 => 'مجم',
  64910 => 'مخج',
  64911 => 'مخم',
  64914 => 'مجخ',
  64915 => 'همج',
  64916 => 'همم',
  64917 => 'نحم',
  64918 => 'نحى',
  64919 => 'نجم',
  64920 => 'نجم',
  64921 => 'نجى',
  64922 => 'نمي',
  64923 => 'نمى',
  64924 => 'يمم',
  64925 => 'يمم',
  64926 => 'بخي',
  64927 => 'تجي',
  64928 => 'تجى',
  64929 => 'تخي',
  64930 => 'تخى',
  64931 => 'تمي',
  64932 => 'تمى',
  64933 => 'جمي',
  64934 => 'جحى',
  64935 => 'جمى',
  64936 => 'سخى',
  64937 => 'صحي',
  64938 => 'شحي',
  64939 => 'ضحي',
  64940 => 'لجي',
  64941 => 'لمي',
  64942 => 'يحي',
  64943 => 'يجي',
  64944 => 'يمي',
  64945 => 'ممي',
  64946 => 'قمي',
  64947 => 'نحي',
  64948 => 'قمح',
  64949 => 'لحم',
  64950 => 'عمي',
  64951 => 'كمي',
  64952 => 'نجح',
  64953 => 'مخي',
  64954 => 'لجم',
  64955 => 'كمم',
  64956 => 'لجم',
  64957 => 'نجح',
  64958 => 'جحي',
  64959 => 'حجي',
  64960 => 'مجي',
  64961 => 'فمي',
  64962 => 'بحي',
  64963 => 'كمم',
  64964 => 'عجم',
  64965 => 'صمم',
  64966 => 'سخي',
  64967 => 'نجي',
  65008 => 'صلے',
  65009 => 'قلے',
  65010 => 'الله',
  65011 => 'اكبر',
  65012 => 'محمد',
  65013 => 'صلعم',
  65014 => 'رسول',
  65015 => 'عليه',
  65016 => 'وسلم',
  65017 => 'صلى',
  65020 => 'ریال',
  65041 => '、',
  65047 => '〖',
  65048 => '〗',
  65073 => '—',
  65074 => '–',
  65081 => '〔',
  65082 => '〕',
  65083 => '【',
  65084 => '】',
  65085 => '《',
  65086 => '》',
  65087 => '〈',
  65088 => '〉',
  65089 => '「',
  65090 => '」',
  65091 => '『',
  65092 => '』',
  65105 => '、',
  65112 => '—',
  65117 => '〔',
  65118 => '〕',
  65123 => '-',
  65137 => 'ـً',
  65143 => 'ـَ',
  65145 => 'ـُ',
  65147 => 'ـِ',
  65149 => 'ـّ',
  65151 => 'ـْ',
  65152 => 'ء',
  65153 => 'آ',
  65154 => 'آ',
  65155 => 'أ',
  65156 => 'أ',
  65157 => 'ؤ',
  65158 => 'ؤ',
  65159 => 'إ',
  65160 => 'إ',
  65161 => 'ئ',
  65162 => 'ئ',
  65163 => 'ئ',
  65164 => 'ئ',
  65165 => 'ا',
  65166 => 'ا',
  65167 => 'ب',
  65168 => 'ب',
  65169 => 'ب',
  65170 => 'ب',
  65171 => 'ة',
  65172 => 'ة',
  65173 => 'ت',
  65174 => 'ت',
  65175 => 'ت',
  65176 => 'ت',
  65177 => 'ث',
  65178 => 'ث',
  65179 => 'ث',
  65180 => 'ث',
  65181 => 'ج',
  65182 => 'ج',
  65183 => 'ج',
  65184 => 'ج',
  65185 => 'ح',
  65186 => 'ح',
  65187 => 'ح',
  65188 => 'ح',
  65189 => 'خ',
  65190 => 'خ',
  65191 => 'خ',
  65192 => 'خ',
  65193 => 'د',
  65194 => 'د',
  65195 => 'ذ',
  65196 => 'ذ',
  65197 => 'ر',
  65198 => 'ر',
  65199 => 'ز',
  65200 => 'ز',
  65201 => 'س',
  65202 => 'س',
  65203 => 'س',
  65204 => 'س',
  65205 => 'ش',
  65206 => 'ش',
  65207 => 'ش',
  65208 => 'ش',
  65209 => 'ص',
  65210 => 'ص',
  65211 => 'ص',
  65212 => 'ص',
  65213 => 'ض',
  65214 => 'ض',
  65215 => 'ض',
  65216 => 'ض',
  65217 => 'ط',
  65218 => 'ط',
  65219 => 'ط',
  65220 => 'ط',
  65221 => 'ظ',
  65222 => 'ظ',
  65223 => 'ظ',
  65224 => 'ظ',
  65225 => 'ع',
  65226 => 'ع',
  65227 => 'ع',
  65228 => 'ع',
  65229 => 'غ',
  65230 => 'غ',
  65231 => 'غ',
  65232 => 'غ',
  65233 => 'ف',
  65234 => 'ف',
  65235 => 'ف',
  65236 => 'ف',
  65237 => 'ق',
  65238 => 'ق',
  65239 => 'ق',
  65240 => 'ق',
  65241 => 'ك',
  65242 => 'ك',
  65243 => 'ك',
  65244 => 'ك',
  65245 => 'ل',
  65246 => 'ل',
  65247 => 'ل',
  65248 => 'ل',
  65249 => 'م',
  65250 => 'م',
  65251 => 'م',
  65252 => 'م',
  65253 => 'ن',
  65254 => 'ن',
  65255 => 'ن',
  65256 => 'ن',
  65257 => 'ه',
  65258 => 'ه',
  65259 => 'ه',
  65260 => 'ه',
  65261 => 'و',
  65262 => 'و',
  65263 => 'ى',
  65264 => 'ى',
  65265 => 'ي',
  65266 => 'ي',
  65267 => 'ي',
  65268 => 'ي',
  65269 => 'لآ',
  65270 => 'لآ',
  65271 => 'لأ',
  65272 => 'لأ',
  65273 => 'لإ',
  65274 => 'لإ',
  65275 => 'لا',
  65276 => 'لا',
  65293 => '-',
  65294 => '.',
  65296 => '0',
  65297 => '1',
  65298 => '2',
  65299 => '3',
  65300 => '4',
  65301 => '5',
  65302 => '6',
  65303 => '7',
  65304 => '8',
  65305 => '9',
  65313 => 'a',
  65314 => 'b',
  65315 => 'c',
  65316 => 'd',
  65317 => 'e',
  65318 => 'f',
  65319 => 'g',
  65320 => 'h',
  65321 => 'i',
  65322 => 'j',
  65323 => 'k',
  65324 => 'l',
  65325 => 'm',
  65326 => 'n',
  65327 => 'o',
  65328 => 'p',
  65329 => 'q',
  65330 => 'r',
  65331 => 's',
  65332 => 't',
  65333 => 'u',
  65334 => 'v',
  65335 => 'w',
  65336 => 'x',
  65337 => 'y',
  65338 => 'z',
  65345 => 'a',
  65346 => 'b',
  65347 => 'c',
  65348 => 'd',
  65349 => 'e',
  65350 => 'f',
  65351 => 'g',
  65352 => 'h',
  65353 => 'i',
  65354 => 'j',
  65355 => 'k',
  65356 => 'l',
  65357 => 'm',
  65358 => 'n',
  65359 => 'o',
  65360 => 'p',
  65361 => 'q',
  65362 => 'r',
  65363 => 's',
  65364 => 't',
  65365 => 'u',
  65366 => 'v',
  65367 => 'w',
  65368 => 'x',
  65369 => 'y',
  65370 => 'z',
  65375 => '⦅',
  65376 => '⦆',
  65377 => '.',
  65378 => '「',
  65379 => '」',
  65380 => '、',
  65381 => '・',
  65382 => 'ヲ',
  65383 => 'ァ',
  65384 => 'ィ',
  65385 => 'ゥ',
  65386 => 'ェ',
  65387 => 'ォ',
  65388 => 'ャ',
  65389 => 'ュ',
  65390 => 'ョ',
  65391 => 'ッ',
  65392 => 'ー',
  65393 => 'ア',
  65394 => 'イ',
  65395 => 'ウ',
  65396 => 'エ',
  65397 => 'オ',
  65398 => 'カ',
  65399 => 'キ',
  65400 => 'ク',
  65401 => 'ケ',
  65402 => 'コ',
  65403 => 'サ',
  65404 => 'シ',
  65405 => 'ス',
  65406 => 'セ',
  65407 => 'ソ',
  65408 => 'タ',
  65409 => 'チ',
  65410 => 'ツ',
  65411 => 'テ',
  65412 => 'ト',
  65413 => 'ナ',
  65414 => 'ニ',
  65415 => 'ヌ',
  65416 => 'ネ',
  65417 => 'ノ',
  65418 => 'ハ',
  65419 => 'ヒ',
  65420 => 'フ',
  65421 => 'ヘ',
  65422 => 'ホ',
  65423 => 'マ',
  65424 => 'ミ',
  65425 => 'ム',
  65426 => 'メ',
  65427 => 'モ',
  65428 => 'ヤ',
  65429 => 'ユ',
  65430 => 'ヨ',
  65431 => 'ラ',
  65432 => 'リ',
  65433 => 'ル',
  65434 => 'レ',
  65435 => 'ロ',
  65436 => 'ワ',
  65437 => 'ン',
  65438 => '゙',
  65439 => '゚',
  65441 => 'ᄀ',
  65442 => 'ᄁ',
  65443 => 'ᆪ',
  65444 => 'ᄂ',
  65445 => 'ᆬ',
  65446 => 'ᆭ',
  65447 => 'ᄃ',
  65448 => 'ᄄ',
  65449 => 'ᄅ',
  65450 => 'ᆰ',
  65451 => 'ᆱ',
  65452 => 'ᆲ',
  65453 => 'ᆳ',
  65454 => 'ᆴ',
  65455 => 'ᆵ',
  65456 => 'ᄚ',
  65457 => 'ᄆ',
  65458 => 'ᄇ',
  65459 => 'ᄈ',
  65460 => 'ᄡ',
  65461 => 'ᄉ',
  65462 => 'ᄊ',
  65463 => 'ᄋ',
  65464 => 'ᄌ',
  65465 => 'ᄍ',
  65466 => 'ᄎ',
  65467 => 'ᄏ',
  65468 => 'ᄐ',
  65469 => 'ᄑ',
  65470 => 'ᄒ',
  65474 => 'ᅡ',
  65475 => 'ᅢ',
  65476 => 'ᅣ',
  65477 => 'ᅤ',
  65478 => 'ᅥ',
  65479 => 'ᅦ',
  65482 => 'ᅧ',
  65483 => 'ᅨ',
  65484 => 'ᅩ',
  65485 => 'ᅪ',
  65486 => 'ᅫ',
  65487 => 'ᅬ',
  65490 => 'ᅭ',
  65491 => 'ᅮ',
  65492 => 'ᅯ',
  65493 => 'ᅰ',
  65494 => 'ᅱ',
  65495 => 'ᅲ',
  65498 => 'ᅳ',
  65499 => 'ᅴ',
  65500 => 'ᅵ',
  65504 => '¢',
  65505 => '£',
  65506 => '¬',
  65508 => '¦',
  65509 => '¥',
  65510 => '₩',
  65512 => '│',
  65513 => '←',
  65514 => '↑',
  65515 => '→',
  65516 => '↓',
  65517 => '■',
  65518 => '○',
  66560 => '𐐨',
  66561 => '𐐩',
  66562 => '𐐪',
  66563 => '𐐫',
  66564 => '𐐬',
  66565 => '𐐭',
  66566 => '𐐮',
  66567 => '𐐯',
  66568 => '𐐰',
  66569 => '𐐱',
  66570 => '𐐲',
  66571 => '𐐳',
  66572 => '𐐴',
  66573 => '𐐵',
  66574 => '𐐶',
  66575 => '𐐷',
  66576 => '𐐸',
  66577 => '𐐹',
  66578 => '𐐺',
  66579 => '𐐻',
  66580 => '𐐼',
  66581 => '𐐽',
  66582 => '𐐾',
  66583 => '𐐿',
  66584 => '𐑀',
  66585 => '𐑁',
  66586 => '𐑂',
  66587 => '𐑃',
  66588 => '𐑄',
  66589 => '𐑅',
  66590 => '𐑆',
  66591 => '𐑇',
  66592 => '𐑈',
  66593 => '𐑉',
  66594 => '𐑊',
  66595 => '𐑋',
  66596 => '𐑌',
  66597 => '𐑍',
  66598 => '𐑎',
  66599 => '𐑏',
  66736 => '𐓘',
  66737 => '𐓙',
  66738 => '𐓚',
  66739 => '𐓛',
  66740 => '𐓜',
  66741 => '𐓝',
  66742 => '𐓞',
  66743 => '𐓟',
  66744 => '𐓠',
  66745 => '𐓡',
  66746 => '𐓢',
  66747 => '𐓣',
  66748 => '𐓤',
  66749 => '𐓥',
  66750 => '𐓦',
  66751 => '𐓧',
  66752 => '𐓨',
  66753 => '𐓩',
  66754 => '𐓪',
  66755 => '𐓫',
  66756 => '𐓬',
  66757 => '𐓭',
  66758 => '𐓮',
  66759 => '𐓯',
  66760 => '𐓰',
  66761 => '𐓱',
  66762 => '𐓲',
  66763 => '𐓳',
  66764 => '𐓴',
  66765 => '𐓵',
  66766 => '𐓶',
  66767 => '𐓷',
  66768 => '𐓸',
  66769 => '𐓹',
  66770 => '𐓺',
  66771 => '𐓻',
  68736 => '𐳀',
  68737 => '𐳁',
  68738 => '𐳂',
  68739 => '𐳃',
  68740 => '𐳄',
  68741 => '𐳅',
  68742 => '𐳆',
  68743 => '𐳇',
  68744 => '𐳈',
  68745 => '𐳉',
  68746 => '𐳊',
  68747 => '𐳋',
  68748 => '𐳌',
  68749 => '𐳍',
  68750 => '𐳎',
  68751 => '𐳏',
  68752 => '𐳐',
  68753 => '𐳑',
  68754 => '𐳒',
  68755 => '𐳓',
  68756 => '𐳔',
  68757 => '𐳕',
  68758 => '𐳖',
  68759 => '𐳗',
  68760 => '𐳘',
  68761 => '𐳙',
  68762 => '𐳚',
  68763 => '𐳛',
  68764 => '𐳜',
  68765 => '𐳝',
  68766 => '𐳞',
  68767 => '𐳟',
  68768 => '𐳠',
  68769 => '𐳡',
  68770 => '𐳢',
  68771 => '𐳣',
  68772 => '𐳤',
  68773 => '𐳥',
  68774 => '𐳦',
  68775 => '𐳧',
  68776 => '𐳨',
  68777 => '𐳩',
  68778 => '𐳪',
  68779 => '𐳫',
  68780 => '𐳬',
  68781 => '𐳭',
  68782 => '𐳮',
  68783 => '𐳯',
  68784 => '𐳰',
  68785 => '𐳱',
  68786 => '𐳲',
  71840 => '𑣀',
  71841 => '𑣁',
  71842 => '𑣂',
  71843 => '𑣃',
  71844 => '𑣄',
  71845 => '𑣅',
  71846 => '𑣆',
  71847 => '𑣇',
  71848 => '𑣈',
  71849 => '𑣉',
  71850 => '𑣊',
  71851 => '𑣋',
  71852 => '𑣌',
  71853 => '𑣍',
  71854 => '𑣎',
  71855 => '𑣏',
  71856 => '𑣐',
  71857 => '𑣑',
  71858 => '𑣒',
  71859 => '𑣓',
  71860 => '𑣔',
  71861 => '𑣕',
  71862 => '𑣖',
  71863 => '𑣗',
  71864 => '𑣘',
  71865 => '𑣙',
  71866 => '𑣚',
  71867 => '𑣛',
  71868 => '𑣜',
  71869 => '𑣝',
  71870 => '𑣞',
  71871 => '𑣟',
  93760 => '𖹠',
  93761 => '𖹡',
  93762 => '𖹢',
  93763 => '𖹣',
  93764 => '𖹤',
  93765 => '𖹥',
  93766 => '𖹦',
  93767 => '𖹧',
  93768 => '𖹨',
  93769 => '𖹩',
  93770 => '𖹪',
  93771 => '𖹫',
  93772 => '𖹬',
  93773 => '𖹭',
  93774 => '𖹮',
  93775 => '𖹯',
  93776 => '𖹰',
  93777 => '𖹱',
  93778 => '𖹲',
  93779 => '𖹳',
  93780 => '𖹴',
  93781 => '𖹵',
  93782 => '𖹶',
  93783 => '𖹷',
  93784 => '𖹸',
  93785 => '𖹹',
  93786 => '𖹺',
  93787 => '𖹻',
  93788 => '𖹼',
  93789 => '𖹽',
  93790 => '𖹾',
  93791 => '𖹿',
  119134 => '𝅗𝅥',
  119135 => '𝅘𝅥',
  119136 => '𝅘𝅥𝅮',
  119137 => '𝅘𝅥𝅯',
  119138 => '𝅘𝅥𝅰',
  119139 => '𝅘𝅥𝅱',
  119140 => '𝅘𝅥𝅲',
  119227 => '𝆹𝅥',
  119228 => '𝆺𝅥',
  119229 => '𝆹𝅥𝅮',
  119230 => '𝆺𝅥𝅮',
  119231 => '𝆹𝅥𝅯',
  119232 => '𝆺𝅥𝅯',
  119808 => 'a',
  119809 => 'b',
  119810 => 'c',
  119811 => 'd',
  119812 => 'e',
  119813 => 'f',
  119814 => 'g',
  119815 => 'h',
  119816 => 'i',
  119817 => 'j',
  119818 => 'k',
  119819 => 'l',
  119820 => 'm',
  119821 => 'n',
  119822 => 'o',
  119823 => 'p',
  119824 => 'q',
  119825 => 'r',
  119826 => 's',
  119827 => 't',
  119828 => 'u',
  119829 => 'v',
  119830 => 'w',
  119831 => 'x',
  119832 => 'y',
  119833 => 'z',
  119834 => 'a',
  119835 => 'b',
  119836 => 'c',
  119837 => 'd',
  119838 => 'e',
  119839 => 'f',
  119840 => 'g',
  119841 => 'h',
  119842 => 'i',
  119843 => 'j',
  119844 => 'k',
  119845 => 'l',
  119846 => 'm',
  119847 => 'n',
  119848 => 'o',
  119849 => 'p',
  119850 => 'q',
  119851 => 'r',
  119852 => 's',
  119853 => 't',
  119854 => 'u',
  119855 => 'v',
  119856 => 'w',
  119857 => 'x',
  119858 => 'y',
  119859 => 'z',
  119860 => 'a',
  119861 => 'b',
  119862 => 'c',
  119863 => 'd',
  119864 => 'e',
  119865 => 'f',
  119866 => 'g',
  119867 => 'h',
  119868 => 'i',
  119869 => 'j',
  119870 => 'k',
  119871 => 'l',
  119872 => 'm',
  119873 => 'n',
  119874 => 'o',
  119875 => 'p',
  119876 => 'q',
  119877 => 'r',
  119878 => 's',
  119879 => 't',
  119880 => 'u',
  119881 => 'v',
  119882 => 'w',
  119883 => 'x',
  119884 => 'y',
  119885 => 'z',
  119886 => 'a',
  119887 => 'b',
  119888 => 'c',
  119889 => 'd',
  119890 => 'e',
  119891 => 'f',
  119892 => 'g',
  119894 => 'i',
  119895 => 'j',
  119896 => 'k',
  119897 => 'l',
  119898 => 'm',
  119899 => 'n',
  119900 => 'o',
  119901 => 'p',
  119902 => 'q',
  119903 => 'r',
  119904 => 's',
  119905 => 't',
  119906 => 'u',
  119907 => 'v',
  119908 => 'w',
  119909 => 'x',
  119910 => 'y',
  119911 => 'z',
  119912 => 'a',
  119913 => 'b',
  119914 => 'c',
  119915 => 'd',
  119916 => 'e',
  119917 => 'f',
  119918 => 'g',
  119919 => 'h',
  119920 => 'i',
  119921 => 'j',
  119922 => 'k',
  119923 => 'l',
  119924 => 'm',
  119925 => 'n',
  119926 => 'o',
  119927 => 'p',
  119928 => 'q',
  119929 => 'r',
  119930 => 's',
  119931 => 't',
  119932 => 'u',
  119933 => 'v',
  119934 => 'w',
  119935 => 'x',
  119936 => 'y',
  119937 => 'z',
  119938 => 'a',
  119939 => 'b',
  119940 => 'c',
  119941 => 'd',
  119942 => 'e',
  119943 => 'f',
  119944 => 'g',
  119945 => 'h',
  119946 => 'i',
  119947 => 'j',
  119948 => 'k',
  119949 => 'l',
  119950 => 'm',
  119951 => 'n',
  119952 => 'o',
  119953 => 'p',
  119954 => 'q',
  119955 => 'r',
  119956 => 's',
  119957 => 't',
  119958 => 'u',
  119959 => 'v',
  119960 => 'w',
  119961 => 'x',
  119962 => 'y',
  119963 => 'z',
  119964 => 'a',
  119966 => 'c',
  119967 => 'd',
  119970 => 'g',
  119973 => 'j',
  119974 => 'k',
  119977 => 'n',
  119978 => 'o',
  119979 => 'p',
  119980 => 'q',
  119982 => 's',
  119983 => 't',
  119984 => 'u',
  119985 => 'v',
  119986 => 'w',
  119987 => 'x',
  119988 => 'y',
  119989 => 'z',
  119990 => 'a',
  119991 => 'b',
  119992 => 'c',
  119993 => 'd',
  119995 => 'f',
  119997 => 'h',
  119998 => 'i',
  119999 => 'j',
  120000 => 'k',
  120001 => 'l',
  120002 => 'm',
  120003 => 'n',
  120005 => 'p',
  120006 => 'q',
  120007 => 'r',
  120008 => 's',
  120009 => 't',
  120010 => 'u',
  120011 => 'v',
  120012 => 'w',
  120013 => 'x',
  120014 => 'y',
  120015 => 'z',
  120016 => 'a',
  120017 => 'b',
  120018 => 'c',
  120019 => 'd',
  120020 => 'e',
  120021 => 'f',
  120022 => 'g',
  120023 => 'h',
  120024 => 'i',
  120025 => 'j',
  120026 => 'k',
  120027 => 'l',
  120028 => 'm',
  120029 => 'n',
  120030 => 'o',
  120031 => 'p',
  120032 => 'q',
  120033 => 'r',
  120034 => 's',
  120035 => 't',
  120036 => 'u',
  120037 => 'v',
  120038 => 'w',
  120039 => 'x',
  120040 => 'y',
  120041 => 'z',
  120042 => 'a',
  120043 => 'b',
  120044 => 'c',
  120045 => 'd',
  120046 => 'e',
  120047 => 'f',
  120048 => 'g',
  120049 => 'h',
  120050 => 'i',
  120051 => 'j',
  120052 => 'k',
  120053 => 'l',
  120054 => 'm',
  120055 => 'n',
  120056 => 'o',
  120057 => 'p',
  120058 => 'q',
  120059 => 'r',
  120060 => 's',
  120061 => 't',
  120062 => 'u',
  120063 => 'v',
  120064 => 'w',
  120065 => 'x',
  120066 => 'y',
  120067 => 'z',
  120068 => 'a',
  120069 => 'b',
  120071 => 'd',
  120072 => 'e',
  120073 => 'f',
  120074 => 'g',
  120077 => 'j',
  120078 => 'k',
  120079 => 'l',
  120080 => 'm',
  120081 => 'n',
  120082 => 'o',
  120083 => 'p',
  120084 => 'q',
  120086 => 's',
  120087 => 't',
  120088 => 'u',
  120089 => 'v',
  120090 => 'w',
  120091 => 'x',
  120092 => 'y',
  120094 => 'a',
  120095 => 'b',
  120096 => 'c',
  120097 => 'd',
  120098 => 'e',
  120099 => 'f',
  120100 => 'g',
  120101 => 'h',
  120102 => 'i',
  120103 => 'j',
  120104 => 'k',
  120105 => 'l',
  120106 => 'm',
  120107 => 'n',
  120108 => 'o',
  120109 => 'p',
  120110 => 'q',
  120111 => 'r',
  120112 => 's',
  120113 => 't',
  120114 => 'u',
  120115 => 'v',
  120116 => 'w',
  120117 => 'x',
  120118 => 'y',
  120119 => 'z',
  120120 => 'a',
  120121 => 'b',
  120123 => 'd',
  120124 => 'e',
  120125 => 'f',
  120126 => 'g',
  120128 => 'i',
  120129 => 'j',
  120130 => 'k',
  120131 => 'l',
  120132 => 'm',
  120134 => 'o',
  120138 => 's',
  120139 => 't',
  120140 => 'u',
  120141 => 'v',
  120142 => 'w',
  120143 => 'x',
  120144 => 'y',
  120146 => 'a',
  120147 => 'b',
  120148 => 'c',
  120149 => 'd',
  120150 => 'e',
  120151 => 'f',
  120152 => 'g',
  120153 => 'h',
  120154 => 'i',
  120155 => 'j',
  120156 => 'k',
  120157 => 'l',
  120158 => 'm',
  120159 => 'n',
  120160 => 'o',
  120161 => 'p',
  120162 => 'q',
  120163 => 'r',
  120164 => 's',
  120165 => 't',
  120166 => 'u',
  120167 => 'v',
  120168 => 'w',
  120169 => 'x',
  120170 => 'y',
  120171 => 'z',
  120172 => 'a',
  120173 => 'b',
  120174 => 'c',
  120175 => 'd',
  120176 => 'e',
  120177 => 'f',
  120178 => 'g',
  120179 => 'h',
  120180 => 'i',
  120181 => 'j',
  120182 => 'k',
  120183 => 'l',
  120184 => 'm',
  120185 => 'n',
  120186 => 'o',
  120187 => 'p',
  120188 => 'q',
  120189 => 'r',
  120190 => 's',
  120191 => 't',
  120192 => 'u',
  120193 => 'v',
  120194 => 'w',
  120195 => 'x',
  120196 => 'y',
  120197 => 'z',
  120198 => 'a',
  120199 => 'b',
  120200 => 'c',
  120201 => 'd',
  120202 => 'e',
  120203 => 'f',
  120204 => 'g',
  120205 => 'h',
  120206 => 'i',
  120207 => 'j',
  120208 => 'k',
  120209 => 'l',
  120210 => 'm',
  120211 => 'n',
  120212 => 'o',
  120213 => 'p',
  120214 => 'q',
  120215 => 'r',
  120216 => 's',
  120217 => 't',
  120218 => 'u',
  120219 => 'v',
  120220 => 'w',
  120221 => 'x',
  120222 => 'y',
  120223 => 'z',
  120224 => 'a',
  120225 => 'b',
  120226 => 'c',
  120227 => 'd',
  120228 => 'e',
  120229 => 'f',
  120230 => 'g',
  120231 => 'h',
  120232 => 'i',
  120233 => 'j',
  120234 => 'k',
  120235 => 'l',
  120236 => 'm',
  120237 => 'n',
  120238 => 'o',
  120239 => 'p',
  120240 => 'q',
  120241 => 'r',
  120242 => 's',
  120243 => 't',
  120244 => 'u',
  120245 => 'v',
  120246 => 'w',
  120247 => 'x',
  120248 => 'y',
  120249 => 'z',
  120250 => 'a',
  120251 => 'b',
  120252 => 'c',
  120253 => 'd',
  120254 => 'e',
  120255 => 'f',
  120256 => 'g',
  120257 => 'h',
  120258 => 'i',
  120259 => 'j',
  120260 => 'k',
  120261 => 'l',
  120262 => 'm',
  120263 => 'n',
  120264 => 'o',
  120265 => 'p',
  120266 => 'q',
  120267 => 'r',
  120268 => 's',
  120269 => 't',
  120270 => 'u',
  120271 => 'v',
  120272 => 'w',
  120273 => 'x',
  120274 => 'y',
  120275 => 'z',
  120276 => 'a',
  120277 => 'b',
  120278 => 'c',
  120279 => 'd',
  120280 => 'e',
  120281 => 'f',
  120282 => 'g',
  120283 => 'h',
  120284 => 'i',
  120285 => 'j',
  120286 => 'k',
  120287 => 'l',
  120288 => 'm',
  120289 => 'n',
  120290 => 'o',
  120291 => 'p',
  120292 => 'q',
  120293 => 'r',
  120294 => 's',
  120295 => 't',
  120296 => 'u',
  120297 => 'v',
  120298 => 'w',
  120299 => 'x',
  120300 => 'y',
  120301 => 'z',
  120302 => 'a',
  120303 => 'b',
  120304 => 'c',
  120305 => 'd',
  120306 => 'e',
  120307 => 'f',
  120308 => 'g',
  120309 => 'h',
  120310 => 'i',
  120311 => 'j',
  120312 => 'k',
  120313 => 'l',
  120314 => 'm',
  120315 => 'n',
  120316 => 'o',
  120317 => 'p',
  120318 => 'q',
  120319 => 'r',
  120320 => 's',
  120321 => 't',
  120322 => 'u',
  120323 => 'v',
  120324 => 'w',
  120325 => 'x',
  120326 => 'y',
  120327 => 'z',
  120328 => 'a',
  120329 => 'b',
  120330 => 'c',
  120331 => 'd',
  120332 => 'e',
  120333 => 'f',
  120334 => 'g',
  120335 => 'h',
  120336 => 'i',
  120337 => 'j',
  120338 => 'k',
  120339 => 'l',
  120340 => 'm',
  120341 => 'n',
  120342 => 'o',
  120343 => 'p',
  120344 => 'q',
  120345 => 'r',
  120346 => 's',
  120347 => 't',
  120348 => 'u',
  120349 => 'v',
  120350 => 'w',
  120351 => 'x',
  120352 => 'y',
  120353 => 'z',
  120354 => 'a',
  120355 => 'b',
  120356 => 'c',
  120357 => 'd',
  120358 => 'e',
  120359 => 'f',
  120360 => 'g',
  120361 => 'h',
  120362 => 'i',
  120363 => 'j',
  120364 => 'k',
  120365 => 'l',
  120366 => 'm',
  120367 => 'n',
  120368 => 'o',
  120369 => 'p',
  120370 => 'q',
  120371 => 'r',
  120372 => 's',
  120373 => 't',
  120374 => 'u',
  120375 => 'v',
  120376 => 'w',
  120377 => 'x',
  120378 => 'y',
  120379 => 'z',
  120380 => 'a',
  120381 => 'b',
  120382 => 'c',
  120383 => 'd',
  120384 => 'e',
  120385 => 'f',
  120386 => 'g',
  120387 => 'h',
  120388 => 'i',
  120389 => 'j',
  120390 => 'k',
  120391 => 'l',
  120392 => 'm',
  120393 => 'n',
  120394 => 'o',
  120395 => 'p',
  120396 => 'q',
  120397 => 'r',
  120398 => 's',
  120399 => 't',
  120400 => 'u',
  120401 => 'v',
  120402 => 'w',
  120403 => 'x',
  120404 => 'y',
  120405 => 'z',
  120406 => 'a',
  120407 => 'b',
  120408 => 'c',
  120409 => 'd',
  120410 => 'e',
  120411 => 'f',
  120412 => 'g',
  120413 => 'h',
  120414 => 'i',
  120415 => 'j',
  120416 => 'k',
  120417 => 'l',
  120418 => 'm',
  120419 => 'n',
  120420 => 'o',
  120421 => 'p',
  120422 => 'q',
  120423 => 'r',
  120424 => 's',
  120425 => 't',
  120426 => 'u',
  120427 => 'v',
  120428 => 'w',
  120429 => 'x',
  120430 => 'y',
  120431 => 'z',
  120432 => 'a',
  120433 => 'b',
  120434 => 'c',
  120435 => 'd',
  120436 => 'e',
  120437 => 'f',
  120438 => 'g',
  120439 => 'h',
  120440 => 'i',
  120441 => 'j',
  120442 => 'k',
  120443 => 'l',
  120444 => 'm',
  120445 => 'n',
  120446 => 'o',
  120447 => 'p',
  120448 => 'q',
  120449 => 'r',
  120450 => 's',
  120451 => 't',
  120452 => 'u',
  120453 => 'v',
  120454 => 'w',
  120455 => 'x',
  120456 => 'y',
  120457 => 'z',
  120458 => 'a',
  120459 => 'b',
  120460 => 'c',
  120461 => 'd',
  120462 => 'e',
  120463 => 'f',
  120464 => 'g',
  120465 => 'h',
  120466 => 'i',
  120467 => 'j',
  120468 => 'k',
  120469 => 'l',
  120470 => 'm',
  120471 => 'n',
  120472 => 'o',
  120473 => 'p',
  120474 => 'q',
  120475 => 'r',
  120476 => 's',
  120477 => 't',
  120478 => 'u',
  120479 => 'v',
  120480 => 'w',
  120481 => 'x',
  120482 => 'y',
  120483 => 'z',
  120484 => 'ı',
  120485 => 'ȷ',
  120488 => 'α',
  120489 => 'β',
  120490 => 'γ',
  120491 => 'δ',
  120492 => 'ε',
  120493 => 'ζ',
  120494 => 'η',
  120495 => 'θ',
  120496 => 'ι',
  120497 => 'κ',
  120498 => 'λ',
  120499 => 'μ',
  120500 => 'ν',
  120501 => 'ξ',
  120502 => 'ο',
  120503 => 'π',
  120504 => 'ρ',
  120505 => 'θ',
  120506 => 'σ',
  120507 => 'τ',
  120508 => 'υ',
  120509 => 'φ',
  120510 => 'χ',
  120511 => 'ψ',
  120512 => 'ω',
  120513 => '∇',
  120514 => 'α',
  120515 => 'β',
  120516 => 'γ',
  120517 => 'δ',
  120518 => 'ε',
  120519 => 'ζ',
  120520 => 'η',
  120521 => 'θ',
  120522 => 'ι',
  120523 => 'κ',
  120524 => 'λ',
  120525 => 'μ',
  120526 => 'ν',
  120527 => 'ξ',
  120528 => 'ο',
  120529 => 'π',
  120530 => 'ρ',
  120531 => 'σ',
  120532 => 'σ',
  120533 => 'τ',
  120534 => 'υ',
  120535 => 'φ',
  120536 => 'χ',
  120537 => 'ψ',
  120538 => 'ω',
  120539 => '∂',
  120540 => 'ε',
  120541 => 'θ',
  120542 => 'κ',
  120543 => 'φ',
  120544 => 'ρ',
  120545 => 'π',
  120546 => 'α',
  120547 => 'β',
  120548 => 'γ',
  120549 => 'δ',
  120550 => 'ε',
  120551 => 'ζ',
  120552 => 'η',
  120553 => 'θ',
  120554 => 'ι',
  120555 => 'κ',
  120556 => 'λ',
  120557 => 'μ',
  120558 => 'ν',
  120559 => 'ξ',
  120560 => 'ο',
  120561 => 'π',
  120562 => 'ρ',
  120563 => 'θ',
  120564 => 'σ',
  120565 => 'τ',
  120566 => 'υ',
  120567 => 'φ',
  120568 => 'χ',
  120569 => 'ψ',
  120570 => 'ω',
  120571 => '∇',
  120572 => 'α',
  120573 => 'β',
  120574 => 'γ',
  120575 => 'δ',
  120576 => 'ε',
  120577 => 'ζ',
  120578 => 'η',
  120579 => 'θ',
  120580 => 'ι',
  120581 => 'κ',
  120582 => 'λ',
  120583 => 'μ',
  120584 => 'ν',
  120585 => 'ξ',
  120586 => 'ο',
  120587 => 'π',
  120588 => 'ρ',
  120589 => 'σ',
  120590 => 'σ',
  120591 => 'τ',
  120592 => 'υ',
  120593 => 'φ',
  120594 => 'χ',
  120595 => 'ψ',
  120596 => 'ω',
  120597 => '∂',
  120598 => 'ε',
  120599 => 'θ',
  120600 => 'κ',
  120601 => 'φ',
  120602 => 'ρ',
  120603 => 'π',
  120604 => 'α',
  120605 => 'β',
  120606 => 'γ',
  120607 => 'δ',
  120608 => 'ε',
  120609 => 'ζ',
  120610 => 'η',
  120611 => 'θ',
  120612 => 'ι',
  120613 => 'κ',
  120614 => 'λ',
  120615 => 'μ',
  120616 => 'ν',
  120617 => 'ξ',
  120618 => 'ο',
  120619 => 'π',
  120620 => 'ρ',
  120621 => 'θ',
  120622 => 'σ',
  120623 => 'τ',
  120624 => 'υ',
  120625 => 'φ',
  120626 => 'χ',
  120627 => 'ψ',
  120628 => 'ω',
  120629 => '∇',
  120630 => 'α',
  120631 => 'β',
  120632 => 'γ',
  120633 => 'δ',
  120634 => 'ε',
  120635 => 'ζ',
  120636 => 'η',
  120637 => 'θ',
  120638 => 'ι',
  120639 => 'κ',
  120640 => 'λ',
  120641 => 'μ',
  120642 => 'ν',
  120643 => 'ξ',
  120644 => 'ο',
  120645 => 'π',
  120646 => 'ρ',
  120647 => 'σ',
  120648 => 'σ',
  120649 => 'τ',
  120650 => 'υ',
  120651 => 'φ',
  120652 => 'χ',
  120653 => 'ψ',
  120654 => 'ω',
  120655 => '∂',
  120656 => 'ε',
  120657 => 'θ',
  120658 => 'κ',
  120659 => 'φ',
  120660 => 'ρ',
  120661 => 'π',
  120662 => 'α',
  120663 => 'β',
  120664 => 'γ',
  120665 => 'δ',
  120666 => 'ε',
  120667 => 'ζ',
  120668 => 'η',
  120669 => 'θ',
  120670 => 'ι',
  120671 => 'κ',
  120672 => 'λ',
  120673 => 'μ',
  120674 => 'ν',
  120675 => 'ξ',
  120676 => 'ο',
  120677 => 'π',
  120678 => 'ρ',
  120679 => 'θ',
  120680 => 'σ',
  120681 => 'τ',
  120682 => 'υ',
  120683 => 'φ',
  120684 => 'χ',
  120685 => 'ψ',
  120686 => 'ω',
  120687 => '∇',
  120688 => 'α',
  120689 => 'β',
  120690 => 'γ',
  120691 => 'δ',
  120692 => 'ε',
  120693 => 'ζ',
  120694 => 'η',
  120695 => 'θ',
  120696 => 'ι',
  120697 => 'κ',
  120698 => 'λ',
  120699 => 'μ',
  120700 => 'ν',
  120701 => 'ξ',
  120702 => 'ο',
  120703 => 'π',
  120704 => 'ρ',
  120705 => 'σ',
  120706 => 'σ',
  120707 => 'τ',
  120708 => 'υ',
  120709 => 'φ',
  120710 => 'χ',
  120711 => 'ψ',
  120712 => 'ω',
  120713 => '∂',
  120714 => 'ε',
  120715 => 'θ',
  120716 => 'κ',
  120717 => 'φ',
  120718 => 'ρ',
  120719 => 'π',
  120720 => 'α',
  120721 => 'β',
  120722 => 'γ',
  120723 => 'δ',
  120724 => 'ε',
  120725 => 'ζ',
  120726 => 'η',
  120727 => 'θ',
  120728 => 'ι',
  120729 => 'κ',
  120730 => 'λ',
  120731 => 'μ',
  120732 => 'ν',
  120733 => 'ξ',
  120734 => 'ο',
  120735 => 'π',
  120736 => 'ρ',
  120737 => 'θ',
  120738 => 'σ',
  120739 => 'τ',
  120740 => 'υ',
  120741 => 'φ',
  120742 => 'χ',
  120743 => 'ψ',
  120744 => 'ω',
  120745 => '∇',
  120746 => 'α',
  120747 => 'β',
  120748 => 'γ',
  120749 => 'δ',
  120750 => 'ε',
  120751 => 'ζ',
  120752 => 'η',
  120753 => 'θ',
  120754 => 'ι',
  120755 => 'κ',
  120756 => 'λ',
  120757 => 'μ',
  120758 => 'ν',
  120759 => 'ξ',
  120760 => 'ο',
  120761 => 'π',
  120762 => 'ρ',
  120763 => 'σ',
  120764 => 'σ',
  120765 => 'τ',
  120766 => 'υ',
  120767 => 'φ',
  120768 => 'χ',
  120769 => 'ψ',
  120770 => 'ω',
  120771 => '∂',
  120772 => 'ε',
  120773 => 'θ',
  120774 => 'κ',
  120775 => 'φ',
  120776 => 'ρ',
  120777 => 'π',
  120778 => 'ϝ',
  120779 => 'ϝ',
  120782 => '0',
  120783 => '1',
  120784 => '2',
  120785 => '3',
  120786 => '4',
  120787 => '5',
  120788 => '6',
  120789 => '7',
  120790 => '8',
  120791 => '9',
  120792 => '0',
  120793 => '1',
  120794 => '2',
  120795 => '3',
  120796 => '4',
  120797 => '5',
  120798 => '6',
  120799 => '7',
  120800 => '8',
  120801 => '9',
  120802 => '0',
  120803 => '1',
  120804 => '2',
  120805 => '3',
  120806 => '4',
  120807 => '5',
  120808 => '6',
  120809 => '7',
  120810 => '8',
  120811 => '9',
  120812 => '0',
  120813 => '1',
  120814 => '2',
  120815 => '3',
  120816 => '4',
  120817 => '5',
  120818 => '6',
  120819 => '7',
  120820 => '8',
  120821 => '9',
  120822 => '0',
  120823 => '1',
  120824 => '2',
  120825 => '3',
  120826 => '4',
  120827 => '5',
  120828 => '6',
  120829 => '7',
  120830 => '8',
  120831 => '9',
  125184 => '𞤢',
  125185 => '𞤣',
  125186 => '𞤤',
  125187 => '𞤥',
  125188 => '𞤦',
  125189 => '𞤧',
  125190 => '𞤨',
  125191 => '𞤩',
  125192 => '𞤪',
  125193 => '𞤫',
  125194 => '𞤬',
  125195 => '𞤭',
  125196 => '𞤮',
  125197 => '𞤯',
  125198 => '𞤰',
  125199 => '𞤱',
  125200 => '𞤲',
  125201 => '𞤳',
  125202 => '𞤴',
  125203 => '𞤵',
  125204 => '𞤶',
  125205 => '𞤷',
  125206 => '𞤸',
  125207 => '𞤹',
  125208 => '𞤺',
  125209 => '𞤻',
  125210 => '𞤼',
  125211 => '𞤽',
  125212 => '𞤾',
  125213 => '𞤿',
  125214 => '𞥀',
  125215 => '𞥁',
  125216 => '𞥂',
  125217 => '𞥃',
  126464 => 'ا',
  126465 => 'ب',
  126466 => 'ج',
  126467 => 'د',
  126469 => 'و',
  126470 => 'ز',
  126471 => 'ح',
  126472 => 'ط',
  126473 => 'ي',
  126474 => 'ك',
  126475 => 'ل',
  126476 => 'م',
  126477 => 'ن',
  126478 => 'س',
  126479 => 'ع',
  126480 => 'ف',
  126481 => 'ص',
  126482 => 'ق',
  126483 => 'ر',
  126484 => 'ش',
  126485 => 'ت',
  126486 => 'ث',
  126487 => 'خ',
  126488 => 'ذ',
  126489 => 'ض',
  126490 => 'ظ',
  126491 => 'غ',
  126492 => 'ٮ',
  126493 => 'ں',
  126494 => 'ڡ',
  126495 => 'ٯ',
  126497 => 'ب',
  126498 => 'ج',
  126500 => 'ه',
  126503 => 'ح',
  126505 => 'ي',
  126506 => 'ك',
  126507 => 'ل',
  126508 => 'م',
  126509 => 'ن',
  126510 => 'س',
  126511 => 'ع',
  126512 => 'ف',
  126513 => 'ص',
  126514 => 'ق',
  126516 => 'ش',
  126517 => 'ت',
  126518 => 'ث',
  126519 => 'خ',
  126521 => 'ض',
  126523 => 'غ',
  126530 => 'ج',
  126535 => 'ح',
  126537 => 'ي',
  126539 => 'ل',
  126541 => 'ن',
  126542 => 'س',
  126543 => 'ع',
  126545 => 'ص',
  126546 => 'ق',
  126548 => 'ش',
  126551 => 'خ',
  126553 => 'ض',
  126555 => 'غ',
  126557 => 'ں',
  126559 => 'ٯ',
  126561 => 'ب',
  126562 => 'ج',
  126564 => 'ه',
  126567 => 'ح',
  126568 => 'ط',
  126569 => 'ي',
  126570 => 'ك',
  126572 => 'م',
  126573 => 'ن',
  126574 => 'س',
  126575 => 'ع',
  126576 => 'ف',
  126577 => 'ص',
  126578 => 'ق',
  126580 => 'ش',
  126581 => 'ت',
  126582 => 'ث',
  126583 => 'خ',
  126585 => 'ض',
  126586 => 'ظ',
  126587 => 'غ',
  126588 => 'ٮ',
  126590 => 'ڡ',
  126592 => 'ا',
  126593 => 'ب',
  126594 => 'ج',
  126595 => 'د',
  126596 => 'ه',
  126597 => 'و',
  126598 => 'ز',
  126599 => 'ح',
  126600 => 'ط',
  126601 => 'ي',
  126603 => 'ل',
  126604 => 'م',
  126605 => 'ن',
  126606 => 'س',
  126607 => 'ع',
  126608 => 'ف',
  126609 => 'ص',
  126610 => 'ق',
  126611 => 'ر',
  126612 => 'ش',
  126613 => 'ت',
  126614 => 'ث',
  126615 => 'خ',
  126616 => 'ذ',
  126617 => 'ض',
  126618 => 'ظ',
  126619 => 'غ',
  126625 => 'ب',
  126626 => 'ج',
  126627 => 'د',
  126629 => 'و',
  126630 => 'ز',
  126631 => 'ح',
  126632 => 'ط',
  126633 => 'ي',
  126635 => 'ل',
  126636 => 'م',
  126637 => 'ن',
  126638 => 'س',
  126639 => 'ع',
  126640 => 'ف',
  126641 => 'ص',
  126642 => 'ق',
  126643 => 'ر',
  126644 => 'ش',
  126645 => 'ت',
  126646 => 'ث',
  126647 => 'خ',
  126648 => 'ذ',
  126649 => 'ض',
  126650 => 'ظ',
  126651 => 'غ',
  127274 => '〔s〕',
  127275 => 'c',
  127276 => 'r',
  127277 => 'cd',
  127278 => 'wz',
  127280 => 'a',
  127281 => 'b',
  127282 => 'c',
  127283 => 'd',
  127284 => 'e',
  127285 => 'f',
  127286 => 'g',
  127287 => 'h',
  127288 => 'i',
  127289 => 'j',
  127290 => 'k',
  127291 => 'l',
  127292 => 'm',
  127293 => 'n',
  127294 => 'o',
  127295 => 'p',
  127296 => 'q',
  127297 => 'r',
  127298 => 's',
  127299 => 't',
  127300 => 'u',
  127301 => 'v',
  127302 => 'w',
  127303 => 'x',
  127304 => 'y',
  127305 => 'z',
  127306 => 'hv',
  127307 => 'mv',
  127308 => 'sd',
  127309 => 'ss',
  127310 => 'ppv',
  127311 => 'wc',
  127338 => 'mc',
  127339 => 'md',
  127340 => 'mr',
  127376 => 'dj',
  127488 => 'ほか',
  127489 => 'ココ',
  127490 => 'サ',
  127504 => '手',
  127505 => '字',
  127506 => '双',
  127507 => 'デ',
  127508 => '二',
  127509 => '多',
  127510 => '解',
  127511 => '天',
  127512 => '交',
  127513 => '映',
  127514 => '無',
  127515 => '料',
  127516 => '前',
  127517 => '後',
  127518 => '再',
  127519 => '新',
  127520 => '初',
  127521 => '終',
  127522 => '生',
  127523 => '販',
  127524 => '声',
  127525 => '吹',
  127526 => '演',
  127527 => '投',
  127528 => '捕',
  127529 => '一',
  127530 => '三',
  127531 => '遊',
  127532 => '左',
  127533 => '中',
  127534 => '右',
  127535 => '指',
  127536 => '走',
  127537 => '打',
  127538 => '禁',
  127539 => '空',
  127540 => '合',
  127541 => '満',
  127542 => '有',
  127543 => '月',
  127544 => '申',
  127545 => '割',
  127546 => '営',
  127547 => '配',
  127552 => '〔本〕',
  127553 => '〔三〕',
  127554 => '〔二〕',
  127555 => '〔安〕',
  127556 => '〔点〕',
  127557 => '〔打〕',
  127558 => '〔盗〕',
  127559 => '〔勝〕',
  127560 => '〔敗〕',
  127568 => '得',
  127569 => '可',
  130032 => '0',
  130033 => '1',
  130034 => '2',
  130035 => '3',
  130036 => '4',
  130037 => '5',
  130038 => '6',
  130039 => '7',
  130040 => '8',
  130041 => '9',
  194560 => '丽',
  194561 => '丸',
  194562 => '乁',
  194563 => '𠄢',
  194564 => '你',
  194565 => '侮',
  194566 => '侻',
  194567 => '倂',
  194568 => '偺',
  194569 => '備',
  194570 => '僧',
  194571 => '像',
  194572 => '㒞',
  194573 => '𠘺',
  194574 => '免',
  194575 => '兔',
  194576 => '兤',
  194577 => '具',
  194578 => '𠔜',
  194579 => '㒹',
  194580 => '內',
  194581 => '再',
  194582 => '𠕋',
  194583 => '冗',
  194584 => '冤',
  194585 => '仌',
  194586 => '冬',
  194587 => '况',
  194588 => '𩇟',
  194589 => '凵',
  194590 => '刃',
  194591 => '㓟',
  194592 => '刻',
  194593 => '剆',
  194594 => '割',
  194595 => '剷',
  194596 => '㔕',
  194597 => '勇',
  194598 => '勉',
  194599 => '勤',
  194600 => '勺',
  194601 => '包',
  194602 => '匆',
  194603 => '北',
  194604 => '卉',
  194605 => '卑',
  194606 => '博',
  194607 => '即',
  194608 => '卽',
  194609 => '卿',
  194610 => '卿',
  194611 => '卿',
  194612 => '𠨬',
  194613 => '灰',
  194614 => '及',
  194615 => '叟',
  194616 => '𠭣',
  194617 => '叫',
  194618 => '叱',
  194619 => '吆',
  194620 => '咞',
  194621 => '吸',
  194622 => '呈',
  194623 => '周',
  194624 => '咢',
  194625 => '哶',
  194626 => '唐',
  194627 => '啓',
  194628 => '啣',
  194629 => '善',
  194630 => '善',
  194631 => '喙',
  194632 => '喫',
  194633 => '喳',
  194634 => '嗂',
  194635 => '圖',
  194636 => '嘆',
  194637 => '圗',
  194638 => '噑',
  194639 => '噴',
  194640 => '切',
  194641 => '壮',
  194642 => '城',
  194643 => '埴',
  194644 => '堍',
  194645 => '型',
  194646 => '堲',
  194647 => '報',
  194648 => '墬',
  194649 => '𡓤',
  194650 => '売',
  194651 => '壷',
  194652 => '夆',
  194653 => '多',
  194654 => '夢',
  194655 => '奢',
  194656 => '𡚨',
  194657 => '𡛪',
  194658 => '姬',
  194659 => '娛',
  194660 => '娧',
  194661 => '姘',
  194662 => '婦',
  194663 => '㛮',
  194665 => '嬈',
  194666 => '嬾',
  194667 => '嬾',
  194668 => '𡧈',
  194669 => '寃',
  194670 => '寘',
  194671 => '寧',
  194672 => '寳',
  194673 => '𡬘',
  194674 => '寿',
  194675 => '将',
  194677 => '尢',
  194678 => '㞁',
  194679 => '屠',
  194680 => '屮',
  194681 => '峀',
  194682 => '岍',
  194683 => '𡷤',
  194684 => '嵃',
  194685 => '𡷦',
  194686 => '嵮',
  194687 => '嵫',
  194688 => '嵼',
  194689 => '巡',
  194690 => '巢',
  194691 => '㠯',
  194692 => '巽',
  194693 => '帨',
  194694 => '帽',
  194695 => '幩',
  194696 => '㡢',
  194697 => '𢆃',
  194698 => '㡼',
  194699 => '庰',
  194700 => '庳',
  194701 => '庶',
  194702 => '廊',
  194703 => '𪎒',
  194704 => '廾',
  194705 => '𢌱',
  194706 => '𢌱',
  194707 => '舁',
  194708 => '弢',
  194709 => '弢',
  194710 => '㣇',
  194711 => '𣊸',
  194712 => '𦇚',
  194713 => '形',
  194714 => '彫',
  194715 => '㣣',
  194716 => '徚',
  194717 => '忍',
  194718 => '志',
  194719 => '忹',
  194720 => '悁',
  194721 => '㤺',
  194722 => '㤜',
  194723 => '悔',
  194724 => '𢛔',
  194725 => '惇',
  194726 => '慈',
  194727 => '慌',
  194728 => '慎',
  194729 => '慌',
  194730 => '慺',
  194731 => '憎',
  194732 => '憲',
  194733 => '憤',
  194734 => '憯',
  194735 => '懞',
  194736 => '懲',
  194737 => '懶',
  194738 => '成',
  194739 => '戛',
  194740 => '扝',
  194741 => '抱',
  194742 => '拔',
  194743 => '捐',
  194744 => '𢬌',
  194745 => '挽',
  194746 => '拼',
  194747 => '捨',
  194748 => '掃',
  194749 => '揤',
  194750 => '𢯱',
  194751 => '搢',
  194752 => '揅',
  194753 => '掩',
  194754 => '㨮',
  194755 => '摩',
  194756 => '摾',
  194757 => '撝',
  194758 => '摷',
  194759 => '㩬',
  194760 => '敏',
  194761 => '敬',
  194762 => '𣀊',
  194763 => '旣',
  194764 => '書',
  194765 => '晉',
  194766 => '㬙',
  194767 => '暑',
  194768 => '㬈',
  194769 => '㫤',
  194770 => '冒',
  194771 => '冕',
  194772 => '最',
  194773 => '暜',
  194774 => '肭',
  194775 => '䏙',
  194776 => '朗',
  194777 => '望',
  194778 => '朡',
  194779 => '杞',
  194780 => '杓',
  194781 => '𣏃',
  194782 => '㭉',
  194783 => '柺',
  194784 => '枅',
  194785 => '桒',
  194786 => '梅',
  194787 => '𣑭',
  194788 => '梎',
  194789 => '栟',
  194790 => '椔',
  194791 => '㮝',
  194792 => '楂',
  194793 => '榣',
  194794 => '槪',
  194795 => '檨',
  194796 => '𣚣',
  194797 => '櫛',
  194798 => '㰘',
  194799 => '次',
  194800 => '𣢧',
  194801 => '歔',
  194802 => '㱎',
  194803 => '歲',
  194804 => '殟',
  194805 => '殺',
  194806 => '殻',
  194807 => '𣪍',
  194808 => '𡴋',
  194809 => '𣫺',
  194810 => '汎',
  194811 => '𣲼',
  194812 => '沿',
  194813 => '泍',
  194814 => '汧',
  194815 => '洖',
  194816 => '派',
  194817 => '海',
  194818 => '流',
  194819 => '浩',
  194820 => '浸',
  194821 => '涅',
  194822 => '𣴞',
  194823 => '洴',
  194824 => '港',
  194825 => '湮',
  194826 => '㴳',
  194827 => '滋',
  194828 => '滇',
  194829 => '𣻑',
  194830 => '淹',
  194831 => '潮',
  194832 => '𣽞',
  194833 => '𣾎',
  194834 => '濆',
  194835 => '瀹',
  194836 => '瀞',
  194837 => '瀛',
  194838 => '㶖',
  194839 => '灊',
  194840 => '災',
  194841 => '灷',
  194842 => '炭',
  194843 => '𠔥',
  194844 => '煅',
  194845 => '𤉣',
  194846 => '熜',
  194848 => '爨',
  194849 => '爵',
  194850 => '牐',
  194851 => '𤘈',
  194852 => '犀',
  194853 => '犕',
  194854 => '𤜵',
  194855 => '𤠔',
  194856 => '獺',
  194857 => '王',
  194858 => '㺬',
  194859 => '玥',
  194860 => '㺸',
  194861 => '㺸',
  194862 => '瑇',
  194863 => '瑜',
  194864 => '瑱',
  194865 => '璅',
  194866 => '瓊',
  194867 => '㼛',
  194868 => '甤',
  194869 => '𤰶',
  194870 => '甾',
  194871 => '𤲒',
  194872 => '異',
  194873 => '𢆟',
  194874 => '瘐',
  194875 => '𤾡',
  194876 => '𤾸',
  194877 => '𥁄',
  194878 => '㿼',
  194879 => '䀈',
  194880 => '直',
  194881 => '𥃳',
  194882 => '𥃲',
  194883 => '𥄙',
  194884 => '𥄳',
  194885 => '眞',
  194886 => '真',
  194887 => '真',
  194888 => '睊',
  194889 => '䀹',
  194890 => '瞋',
  194891 => '䁆',
  194892 => '䂖',
  194893 => '𥐝',
  194894 => '硎',
  194895 => '碌',
  194896 => '磌',
  194897 => '䃣',
  194898 => '𥘦',
  194899 => '祖',
  194900 => '𥚚',
  194901 => '𥛅',
  194902 => '福',
  194903 => '秫',
  194904 => '䄯',
  194905 => '穀',
  194906 => '穊',
  194907 => '穏',
  194908 => '𥥼',
  194909 => '𥪧',
  194910 => '𥪧',
  194912 => '䈂',
  194913 => '𥮫',
  194914 => '篆',
  194915 => '築',
  194916 => '䈧',
  194917 => '𥲀',
  194918 => '糒',
  194919 => '䊠',
  194920 => '糨',
  194921 => '糣',
  194922 => '紀',
  194923 => '𥾆',
  194924 => '絣',
  194925 => '䌁',
  194926 => '緇',
  194927 => '縂',
  194928 => '繅',
  194929 => '䌴',
  194930 => '𦈨',
  194931 => '𦉇',
  194932 => '䍙',
  194933 => '𦋙',
  194934 => '罺',
  194935 => '𦌾',
  194936 => '羕',
  194937 => '翺',
  194938 => '者',
  194939 => '𦓚',
  194940 => '𦔣',
  194941 => '聠',
  194942 => '𦖨',
  194943 => '聰',
  194944 => '𣍟',
  194945 => '䏕',
  194946 => '育',
  194947 => '脃',
  194948 => '䐋',
  194949 => '脾',
  194950 => '媵',
  194951 => '𦞧',
  194952 => '𦞵',
  194953 => '𣎓',
  194954 => '𣎜',
  194955 => '舁',
  194956 => '舄',
  194957 => '辞',
  194958 => '䑫',
  194959 => '芑',
  194960 => '芋',
  194961 => '芝',
  194962 => '劳',
  194963 => '花',
  194964 => '芳',
  194965 => '芽',
  194966 => '苦',
  194967 => '𦬼',
  194968 => '若',
  194969 => '茝',
  194970 => '荣',
  194971 => '莭',
  194972 => '茣',
  194973 => '莽',
  194974 => '菧',
  194975 => '著',
  194976 => '荓',
  194977 => '菊',
  194978 => '菌',
  194979 => '菜',
  194980 => '𦰶',
  194981 => '𦵫',
  194982 => '𦳕',
  194983 => '䔫',
  194984 => '蓱',
  194985 => '蓳',
  194986 => '蔖',
  194987 => '𧏊',
  194988 => '蕤',
  194989 => '𦼬',
  194990 => '䕝',
  194991 => '䕡',
  194992 => '𦾱',
  194993 => '𧃒',
  194994 => '䕫',
  194995 => '虐',
  194996 => '虜',
  194997 => '虧',
  194998 => '虩',
  194999 => '蚩',
  195000 => '蚈',
  195001 => '蜎',
  195002 => '蛢',
  195003 => '蝹',
  195004 => '蜨',
  195005 => '蝫',
  195006 => '螆',
  195008 => '蟡',
  195009 => '蠁',
  195010 => '䗹',
  195011 => '衠',
  195012 => '衣',
  195013 => '𧙧',
  195014 => '裗',
  195015 => '裞',
  195016 => '䘵',
  195017 => '裺',
  195018 => '㒻',
  195019 => '𧢮',
  195020 => '𧥦',
  195021 => '䚾',
  195022 => '䛇',
  195023 => '誠',
  195024 => '諭',
  195025 => '變',
  195026 => '豕',
  195027 => '𧲨',
  195028 => '貫',
  195029 => '賁',
  195030 => '贛',
  195031 => '起',
  195032 => '𧼯',
  195033 => '𠠄',
  195034 => '跋',
  195035 => '趼',
  195036 => '跰',
  195037 => '𠣞',
  195038 => '軔',
  195039 => '輸',
  195040 => '𨗒',
  195041 => '𨗭',
  195042 => '邔',
  195043 => '郱',
  195044 => '鄑',
  195045 => '𨜮',
  195046 => '鄛',
  195047 => '鈸',
  195048 => '鋗',
  195049 => '鋘',
  195050 => '鉼',
  195051 => '鏹',
  195052 => '鐕',
  195053 => '𨯺',
  195054 => '開',
  195055 => '䦕',
  195056 => '閷',
  195057 => '𨵷',
  195058 => '䧦',
  195059 => '雃',
  195060 => '嶲',
  195061 => '霣',
  195062 => '𩅅',
  195063 => '𩈚',
  195064 => '䩮',
  195065 => '䩶',
  195066 => '韠',
  195067 => '𩐊',
  195068 => '䪲',
  195069 => '𩒖',
  195070 => '頋',
  195071 => '頋',
  195072 => '頩',
  195073 => '𩖶',
  195074 => '飢',
  195075 => '䬳',
  195076 => '餩',
  195077 => '馧',
  195078 => '駂',
  195079 => '駾',
  195080 => '䯎',
  195081 => '𩬰',
  195082 => '鬒',
  195083 => '鱀',
  195084 => '鳽',
  195085 => '䳎',
  195086 => '䳭',
  195087 => '鵧',
  195088 => '𪃎',
  195089 => '䳸',
  195090 => '𪄅',
  195091 => '𪈎',
  195092 => '𪊑',
  195093 => '麻',
  195094 => '䵖',
  195095 => '黹',
  195096 => '黾',
  195097 => '鼅',
  195098 => '鼏',
  195099 => '鼖',
  195100 => '鼻',
  195101 => '𪘀',
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;

/**
 * @internal
 */
final class Regex
{
    const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u';

    const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';

    const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
    const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
    const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
    const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';
    const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u';
    const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u';
    const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
    const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';

    const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u';
}
<?php

return array (
  2381 => 9,
  2509 => 9,
  2637 => 9,
  2765 => 9,
  2893 => 9,
  3021 => 9,
  3149 => 9,
  3277 => 9,
  3387 => 9,
  3388 => 9,
  3405 => 9,
  3530 => 9,
  3642 => 9,
  3770 => 9,
  3972 => 9,
  4153 => 9,
  4154 => 9,
  5908 => 9,
  5940 => 9,
  6098 => 9,
  6752 => 9,
  6980 => 9,
  7082 => 9,
  7083 => 9,
  7154 => 9,
  7155 => 9,
  11647 => 9,
  43014 => 9,
  43052 => 9,
  43204 => 9,
  43347 => 9,
  43456 => 9,
  43766 => 9,
  44013 => 9,
  68159 => 9,
  69702 => 9,
  69759 => 9,
  69817 => 9,
  69939 => 9,
  69940 => 9,
  70080 => 9,
  70197 => 9,
  70378 => 9,
  70477 => 9,
  70722 => 9,
  70850 => 9,
  71103 => 9,
  71231 => 9,
  71350 => 9,
  71467 => 9,
  71737 => 9,
  71997 => 9,
  71998 => 9,
  72160 => 9,
  72244 => 9,
  72263 => 9,
  72345 => 9,
  72767 => 9,
  73028 => 9,
  73029 => 9,
  73111 => 9,
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

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); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

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); }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\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 <p@tchwork.com>
 *
 * @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;
    }
}
<?php

class Normalizer extends Symfony\Polyfill\Intl\Normalizer\Normalizer
{
    /**
     * @deprecated since ICU 56 and removed in PHP 8
     */
    public const NONE = 2;
    public const FORM_D = 4;
    public const FORM_KD = 8;
    public const FORM_C = 16;
    public const FORM_KC = 32;
    public const NFD = 4;
    public const NFKD = 8;
    public const NFC = 16;
    public const NFKC = 32;
}
<?php

return array (
  'À' => 'À',
  'Á' => 'Á',
  'Â' => 'Â',
  'Ã' => 'Ã',
  'Ä' => 'Ä',
  'Å' => 'Å',
  'Ç' => 'Ç',
  'È' => 'È',
  'É' => 'É',
  'Ê' => 'Ê',
  'Ë' => 'Ë',
  'Ì' => 'Ì',
  'Í' => 'Í',
  'Î' => 'Î',
  'Ï' => 'Ï',
  'Ñ' => 'Ñ',
  'Ò' => 'Ò',
  'Ó' => 'Ó',
  'Ô' => 'Ô',
  'Õ' => 'Õ',
  'Ö' => 'Ö',
  'Ù' => 'Ù',
  'Ú' => 'Ú',
  'Û' => 'Û',
  'Ü' => 'Ü',
  'Ý' => 'Ý',
  'à' => 'à',
  'á' => 'á',
  'â' => 'â',
  'ã' => 'ã',
  'ä' => 'ä',
  'å' => 'å',
  'ç' => 'ç',
  'è' => 'è',
  'é' => 'é',
  'ê' => 'ê',
  'ë' => 'ë',
  'ì' => 'ì',
  'í' => 'í',
  'î' => 'î',
  'ï' => 'ï',
  'ñ' => 'ñ',
  'ò' => 'ò',
  'ó' => 'ó',
  'ô' => 'ô',
  'õ' => 'õ',
  'ö' => 'ö',
  'ù' => 'ù',
  'ú' => 'ú',
  'û' => 'û',
  'ü' => 'ü',
  'ý' => 'ý',
  'ÿ' => 'ÿ',
  'Ā' => 'Ā',
  'ā' => 'ā',
  'Ă' => 'Ă',
  'ă' => 'ă',
  'Ą' => 'Ą',
  'ą' => 'ą',
  'Ć' => 'Ć',
  'ć' => 'ć',
  'Ĉ' => 'Ĉ',
  'ĉ' => 'ĉ',
  'Ċ' => 'Ċ',
  'ċ' => 'ċ',
  'Č' => 'Č',
  'č' => 'č',
  'Ď' => 'Ď',
  'ď' => 'ď',
  'Ē' => 'Ē',
  'ē' => 'ē',
  'Ĕ' => 'Ĕ',
  'ĕ' => 'ĕ',
  'Ė' => 'Ė',
  'ė' => 'ė',
  'Ę' => 'Ę',
  'ę' => 'ę',
  'Ě' => 'Ě',
  'ě' => 'ě',
  'Ĝ' => 'Ĝ',
  'ĝ' => 'ĝ',
  'Ğ' => 'Ğ',
  'ğ' => 'ğ',
  'Ġ' => 'Ġ',
  'ġ' => 'ġ',
  'Ģ' => 'Ģ',
  'ģ' => 'ģ',
  'Ĥ' => 'Ĥ',
  'ĥ' => 'ĥ',
  'Ĩ' => 'Ĩ',
  'ĩ' => 'ĩ',
  'Ī' => 'Ī',
  'ī' => 'ī',
  'Ĭ' => 'Ĭ',
  'ĭ' => 'ĭ',
  'Į' => 'Į',
  'į' => 'į',
  'İ' => 'İ',
  'Ĵ' => 'Ĵ',
  'ĵ' => 'ĵ',
  'Ķ' => 'Ķ',
  'ķ' => 'ķ',
  'Ĺ' => 'Ĺ',
  'ĺ' => 'ĺ',
  'Ļ' => 'Ļ',
  'ļ' => 'ļ',
  'Ľ' => 'Ľ',
  'ľ' => 'ľ',
  'Ń' => 'Ń',
  'ń' => 'ń',
  'Ņ' => 'Ņ',
  'ņ' => 'ņ',
  'Ň' => 'Ň',
  'ň' => 'ň',
  'Ō' => 'Ō',
  'ō' => 'ō',
  'Ŏ' => 'Ŏ',
  'ŏ' => 'ŏ',
  'Ő' => 'Ő',
  'ő' => 'ő',
  'Ŕ' => 'Ŕ',
  'ŕ' => 'ŕ',
  'Ŗ' => 'Ŗ',
  'ŗ' => 'ŗ',
  'Ř' => 'Ř',
  'ř' => 'ř',
  'Ś' => 'Ś',
  'ś' => 'ś',
  'Ŝ' => 'Ŝ',
  'ŝ' => 'ŝ',
  'Ş' => 'Ş',
  'ş' => 'ş',
  'Š' => 'Š',
  'š' => 'š',
  'Ţ' => 'Ţ',
  'ţ' => 'ţ',
  'Ť' => 'Ť',
  'ť' => 'ť',
  'Ũ' => 'Ũ',
  'ũ' => 'ũ',
  'Ū' => 'Ū',
  'ū' => 'ū',
  'Ŭ' => 'Ŭ',
  'ŭ' => 'ŭ',
  'Ů' => 'Ů',
  'ů' => 'ů',
  'Ű' => 'Ű',
  'ű' => 'ű',
  'Ų' => 'Ų',
  'ų' => 'ų',
  'Ŵ' => 'Ŵ',
  'ŵ' => 'ŵ',
  'Ŷ' => 'Ŷ',
  'ŷ' => 'ŷ',
  'Ÿ' => 'Ÿ',
  'Ź' => 'Ź',
  'ź' => 'ź',
  'Ż' => 'Ż',
  'ż' => 'ż',
  'Ž' => 'Ž',
  'ž' => 'ž',
  'Ơ' => 'Ơ',
  'ơ' => 'ơ',
  'Ư' => 'Ư',
  'ư' => 'ư',
  'Ǎ' => 'Ǎ',
  'ǎ' => 'ǎ',
  'Ǐ' => 'Ǐ',
  'ǐ' => 'ǐ',
  'Ǒ' => 'Ǒ',
  'ǒ' => 'ǒ',
  'Ǔ' => 'Ǔ',
  'ǔ' => 'ǔ',
  'Ǖ' => 'Ǖ',
  'ǖ' => 'ǖ',
  'Ǘ' => 'Ǘ',
  'ǘ' => 'ǘ',
  'Ǚ' => 'Ǚ',
  'ǚ' => 'ǚ',
  'Ǜ' => 'Ǜ',
  'ǜ' => 'ǜ',
  'Ǟ' => 'Ǟ',
  'ǟ' => 'ǟ',
  'Ǡ' => 'Ǡ',
  'ǡ' => 'ǡ',
  'Ǣ' => 'Ǣ',
  'ǣ' => 'ǣ',
  'Ǧ' => 'Ǧ',
  'ǧ' => 'ǧ',
  'Ǩ' => 'Ǩ',
  'ǩ' => 'ǩ',
  'Ǫ' => 'Ǫ',
  'ǫ' => 'ǫ',
  'Ǭ' => 'Ǭ',
  'ǭ' => 'ǭ',
  'Ǯ' => 'Ǯ',
  'ǯ' => 'ǯ',
  'ǰ' => 'ǰ',
  'Ǵ' => 'Ǵ',
  'ǵ' => 'ǵ',
  'Ǹ' => 'Ǹ',
  'ǹ' => 'ǹ',
  'Ǻ' => 'Ǻ',
  'ǻ' => 'ǻ',
  'Ǽ' => 'Ǽ',
  'ǽ' => 'ǽ',
  'Ǿ' => 'Ǿ',
  'ǿ' => 'ǿ',
  'Ȁ' => 'Ȁ',
  'ȁ' => 'ȁ',
  'Ȃ' => 'Ȃ',
  'ȃ' => 'ȃ',
  'Ȅ' => 'Ȅ',
  'ȅ' => 'ȅ',
  'Ȇ' => 'Ȇ',
  'ȇ' => 'ȇ',
  'Ȉ' => 'Ȉ',
  'ȉ' => 'ȉ',
  'Ȋ' => 'Ȋ',
  'ȋ' => 'ȋ',
  'Ȍ' => 'Ȍ',
  'ȍ' => 'ȍ',
  'Ȏ' => 'Ȏ',
  'ȏ' => 'ȏ',
  'Ȑ' => 'Ȑ',
  'ȑ' => 'ȑ',
  'Ȓ' => 'Ȓ',
  'ȓ' => 'ȓ',
  'Ȕ' => 'Ȕ',
  'ȕ' => 'ȕ',
  'Ȗ' => 'Ȗ',
  'ȗ' => 'ȗ',
  'Ș' => 'Ș',
  'ș' => 'ș',
  'Ț' => 'Ț',
  'ț' => 'ț',
  'Ȟ' => 'Ȟ',
  'ȟ' => 'ȟ',
  'Ȧ' => 'Ȧ',
  'ȧ' => 'ȧ',
  'Ȩ' => 'Ȩ',
  'ȩ' => 'ȩ',
  'Ȫ' => 'Ȫ',
  'ȫ' => 'ȫ',
  'Ȭ' => 'Ȭ',
  'ȭ' => 'ȭ',
  'Ȯ' => 'Ȯ',
  'ȯ' => 'ȯ',
  'Ȱ' => 'Ȱ',
  'ȱ' => 'ȱ',
  'Ȳ' => 'Ȳ',
  'ȳ' => 'ȳ',
  '΅' => '΅',
  'Ά' => 'Ά',
  'Έ' => 'Έ',
  'Ή' => 'Ή',
  'Ί' => 'Ί',
  'Ό' => 'Ό',
  'Ύ' => 'Ύ',
  'Ώ' => 'Ώ',
  'ΐ' => 'ΐ',
  'Ϊ' => 'Ϊ',
  'Ϋ' => 'Ϋ',
  'ά' => 'ά',
  'έ' => 'έ',
  'ή' => 'ή',
  'ί' => 'ί',
  'ΰ' => 'ΰ',
  'ϊ' => 'ϊ',
  'ϋ' => 'ϋ',
  'ό' => 'ό',
  'ύ' => 'ύ',
  'ώ' => 'ώ',
  'ϓ' => 'ϓ',
  'ϔ' => 'ϔ',
  'Ѐ' => 'Ѐ',
  'Ё' => 'Ё',
  'Ѓ' => 'Ѓ',
  'Ї' => 'Ї',
  'Ќ' => 'Ќ',
  'Ѝ' => 'Ѝ',
  'Ў' => 'Ў',
  'Й' => 'Й',
  'й' => 'й',
  'ѐ' => 'ѐ',
  'ё' => 'ё',
  'ѓ' => 'ѓ',
  'ї' => 'ї',
  'ќ' => 'ќ',
  'ѝ' => 'ѝ',
  'ў' => 'ў',
  'Ѷ' => 'Ѷ',
  'ѷ' => 'ѷ',
  'Ӂ' => 'Ӂ',
  'ӂ' => 'ӂ',
  'Ӑ' => 'Ӑ',
  'ӑ' => 'ӑ',
  'Ӓ' => 'Ӓ',
  'ӓ' => 'ӓ',
  'Ӗ' => 'Ӗ',
  'ӗ' => 'ӗ',
  'Ӛ' => 'Ӛ',
  'ӛ' => 'ӛ',
  'Ӝ' => 'Ӝ',
  'ӝ' => 'ӝ',
  'Ӟ' => 'Ӟ',
  'ӟ' => 'ӟ',
  'Ӣ' => 'Ӣ',
  'ӣ' => 'ӣ',
  'Ӥ' => 'Ӥ',
  'ӥ' => 'ӥ',
  'Ӧ' => 'Ӧ',
  'ӧ' => 'ӧ',
  'Ӫ' => 'Ӫ',
  'ӫ' => 'ӫ',
  'Ӭ' => 'Ӭ',
  'ӭ' => 'ӭ',
  'Ӯ' => 'Ӯ',
  'ӯ' => 'ӯ',
  'Ӱ' => 'Ӱ',
  'ӱ' => 'ӱ',
  'Ӳ' => 'Ӳ',
  'ӳ' => 'ӳ',
  'Ӵ' => 'Ӵ',
  'ӵ' => 'ӵ',
  'Ӹ' => 'Ӹ',
  'ӹ' => 'ӹ',
  'آ' => 'آ',
  'أ' => 'أ',
  'ؤ' => 'ؤ',
  'إ' => 'إ',
  'ئ' => 'ئ',
  'ۀ' => 'ۀ',
  'ۂ' => 'ۂ',
  'ۓ' => 'ۓ',
  'ऩ' => 'ऩ',
  'ऱ' => 'ऱ',
  'ऴ' => 'ऴ',
  'ো' => 'ো',
  'ৌ' => 'ৌ',
  'ୈ' => 'ୈ',
  'ୋ' => 'ୋ',
  'ୌ' => 'ୌ',
  'ஔ' => 'ஔ',
  'ொ' => 'ொ',
  'ோ' => 'ோ',
  'ௌ' => 'ௌ',
  'ై' => 'ై',
  'ೀ' => 'ೀ',
  'ೇ' => 'ೇ',
  'ೈ' => 'ೈ',
  'ೊ' => 'ೊ',
  'ೋ' => 'ೋ',
  'ൊ' => 'ൊ',
  'ോ' => 'ോ',
  'ൌ' => 'ൌ',
  'ේ' => 'ේ',
  'ො' => 'ො',
  'ෝ' => 'ෝ',
  'ෞ' => 'ෞ',
  'ဦ' => 'ဦ',
  'ᬆ' => 'ᬆ',
  'ᬈ' => 'ᬈ',
  'ᬊ' => 'ᬊ',
  'ᬌ' => 'ᬌ',
  'ᬎ' => 'ᬎ',
  'ᬒ' => 'ᬒ',
  'ᬻ' => 'ᬻ',
  'ᬽ' => 'ᬽ',
  'ᭀ' => 'ᭀ',
  'ᭁ' => 'ᭁ',
  'ᭃ' => 'ᭃ',
  'Ḁ' => 'Ḁ',
  'ḁ' => 'ḁ',
  'Ḃ' => 'Ḃ',
  'ḃ' => 'ḃ',
  'Ḅ' => 'Ḅ',
  'ḅ' => 'ḅ',
  'Ḇ' => 'Ḇ',
  'ḇ' => 'ḇ',
  'Ḉ' => 'Ḉ',
  'ḉ' => 'ḉ',
  'Ḋ' => 'Ḋ',
  'ḋ' => 'ḋ',
  'Ḍ' => 'Ḍ',
  'ḍ' => 'ḍ',
  'Ḏ' => 'Ḏ',
  'ḏ' => 'ḏ',
  'Ḑ' => 'Ḑ',
  'ḑ' => 'ḑ',
  'Ḓ' => 'Ḓ',
  'ḓ' => 'ḓ',
  'Ḕ' => 'Ḕ',
  'ḕ' => 'ḕ',
  'Ḗ' => 'Ḗ',
  'ḗ' => 'ḗ',
  'Ḙ' => 'Ḙ',
  'ḙ' => 'ḙ',
  'Ḛ' => 'Ḛ',
  'ḛ' => 'ḛ',
  'Ḝ' => 'Ḝ',
  'ḝ' => 'ḝ',
  'Ḟ' => 'Ḟ',
  'ḟ' => 'ḟ',
  'Ḡ' => 'Ḡ',
  'ḡ' => 'ḡ',
  'Ḣ' => 'Ḣ',
  'ḣ' => 'ḣ',
  'Ḥ' => 'Ḥ',
  'ḥ' => 'ḥ',
  'Ḧ' => 'Ḧ',
  'ḧ' => 'ḧ',
  'Ḩ' => 'Ḩ',
  'ḩ' => 'ḩ',
  'Ḫ' => 'Ḫ',
  'ḫ' => 'ḫ',
  'Ḭ' => 'Ḭ',
  'ḭ' => 'ḭ',
  'Ḯ' => 'Ḯ',
  'ḯ' => 'ḯ',
  'Ḱ' => 'Ḱ',
  'ḱ' => 'ḱ',
  'Ḳ' => 'Ḳ',
  'ḳ' => 'ḳ',
  'Ḵ' => 'Ḵ',
  'ḵ' => 'ḵ',
  'Ḷ' => 'Ḷ',
  'ḷ' => 'ḷ',
  'Ḹ' => 'Ḹ',
  'ḹ' => 'ḹ',
  'Ḻ' => 'Ḻ',
  'ḻ' => 'ḻ',
  'Ḽ' => 'Ḽ',
  'ḽ' => 'ḽ',
  'Ḿ' => 'Ḿ',
  'ḿ' => 'ḿ',
  'Ṁ' => 'Ṁ',
  'ṁ' => 'ṁ',
  'Ṃ' => 'Ṃ',
  'ṃ' => 'ṃ',
  'Ṅ' => 'Ṅ',
  'ṅ' => 'ṅ',
  'Ṇ' => 'Ṇ',
  'ṇ' => 'ṇ',
  'Ṉ' => 'Ṉ',
  'ṉ' => 'ṉ',
  'Ṋ' => 'Ṋ',
  'ṋ' => 'ṋ',
  'Ṍ' => 'Ṍ',
  'ṍ' => 'ṍ',
  'Ṏ' => 'Ṏ',
  'ṏ' => 'ṏ',
  'Ṑ' => 'Ṑ',
  'ṑ' => 'ṑ',
  'Ṓ' => 'Ṓ',
  'ṓ' => 'ṓ',
  'Ṕ' => 'Ṕ',
  'ṕ' => 'ṕ',
  'Ṗ' => 'Ṗ',
  'ṗ' => 'ṗ',
  'Ṙ' => 'Ṙ',
  'ṙ' => 'ṙ',
  'Ṛ' => 'Ṛ',
  'ṛ' => 'ṛ',
  'Ṝ' => 'Ṝ',
  'ṝ' => 'ṝ',
  'Ṟ' => 'Ṟ',
  'ṟ' => 'ṟ',
  'Ṡ' => 'Ṡ',
  'ṡ' => 'ṡ',
  'Ṣ' => 'Ṣ',
  'ṣ' => 'ṣ',
  'Ṥ' => 'Ṥ',
  'ṥ' => 'ṥ',
  'Ṧ' => 'Ṧ',
  'ṧ' => 'ṧ',
  'Ṩ' => 'Ṩ',
  'ṩ' => 'ṩ',
  'Ṫ' => 'Ṫ',
  'ṫ' => 'ṫ',
  'Ṭ' => 'Ṭ',
  'ṭ' => 'ṭ',
  'Ṯ' => 'Ṯ',
  'ṯ' => 'ṯ',
  'Ṱ' => 'Ṱ',
  'ṱ' => 'ṱ',
  'Ṳ' => 'Ṳ',
  'ṳ' => 'ṳ',
  'Ṵ' => 'Ṵ',
  'ṵ' => 'ṵ',
  'Ṷ' => 'Ṷ',
  'ṷ' => 'ṷ',
  'Ṹ' => 'Ṹ',
  'ṹ' => 'ṹ',
  'Ṻ' => 'Ṻ',
  'ṻ' => 'ṻ',
  'Ṽ' => 'Ṽ',
  'ṽ' => 'ṽ',
  'Ṿ' => 'Ṿ',
  'ṿ' => 'ṿ',
  'Ẁ' => 'Ẁ',
  'ẁ' => 'ẁ',
  'Ẃ' => 'Ẃ',
  'ẃ' => 'ẃ',
  'Ẅ' => 'Ẅ',
  'ẅ' => 'ẅ',
  'Ẇ' => 'Ẇ',
  'ẇ' => 'ẇ',
  'Ẉ' => 'Ẉ',
  'ẉ' => 'ẉ',
  'Ẋ' => 'Ẋ',
  'ẋ' => 'ẋ',
  'Ẍ' => 'Ẍ',
  'ẍ' => 'ẍ',
  'Ẏ' => 'Ẏ',
  'ẏ' => 'ẏ',
  'Ẑ' => 'Ẑ',
  'ẑ' => 'ẑ',
  'Ẓ' => 'Ẓ',
  'ẓ' => 'ẓ',
  'Ẕ' => 'Ẕ',
  'ẕ' => 'ẕ',
  'ẖ' => 'ẖ',
  'ẗ' => 'ẗ',
  'ẘ' => 'ẘ',
  'ẙ' => 'ẙ',
  'ẛ' => 'ẛ',
  'Ạ' => 'Ạ',
  'ạ' => 'ạ',
  'Ả' => 'Ả',
  'ả' => 'ả',
  'Ấ' => 'Ấ',
  'ấ' => 'ấ',
  'Ầ' => 'Ầ',
  'ầ' => 'ầ',
  'Ẩ' => 'Ẩ',
  'ẩ' => 'ẩ',
  'Ẫ' => 'Ẫ',
  'ẫ' => 'ẫ',
  'Ậ' => 'Ậ',
  'ậ' => 'ậ',
  'Ắ' => 'Ắ',
  'ắ' => 'ắ',
  'Ằ' => 'Ằ',
  'ằ' => 'ằ',
  'Ẳ' => 'Ẳ',
  'ẳ' => 'ẳ',
  'Ẵ' => 'Ẵ',
  'ẵ' => 'ẵ',
  'Ặ' => 'Ặ',
  'ặ' => 'ặ',
  'Ẹ' => 'Ẹ',
  'ẹ' => 'ẹ',
  'Ẻ' => 'Ẻ',
  'ẻ' => 'ẻ',
  'Ẽ' => 'Ẽ',
  'ẽ' => 'ẽ',
  'Ế' => 'Ế',
  'ế' => 'ế',
  'Ề' => 'Ề',
  'ề' => 'ề',
  'Ể' => 'Ể',
  'ể' => 'ể',
  'Ễ' => 'Ễ',
  'ễ' => 'ễ',
  'Ệ' => 'Ệ',
  'ệ' => 'ệ',
  'Ỉ' => 'Ỉ',
  'ỉ' => 'ỉ',
  'Ị' => 'Ị',
  'ị' => 'ị',
  'Ọ' => 'Ọ',
  'ọ' => 'ọ',
  'Ỏ' => 'Ỏ',
  'ỏ' => 'ỏ',
  'Ố' => 'Ố',
  'ố' => 'ố',
  'Ồ' => 'Ồ',
  'ồ' => 'ồ',
  'Ổ' => 'Ổ',
  'ổ' => 'ổ',
  'Ỗ' => 'Ỗ',
  'ỗ' => 'ỗ',
  'Ộ' => 'Ộ',
  'ộ' => 'ộ',
  'Ớ' => 'Ớ',
  'ớ' => 'ớ',
  'Ờ' => 'Ờ',
  'ờ' => 'ờ',
  'Ở' => 'Ở',
  'ở' => 'ở',
  'Ỡ' => 'Ỡ',
  'ỡ' => 'ỡ',
  'Ợ' => 'Ợ',
  'ợ' => 'ợ',
  'Ụ' => 'Ụ',
  'ụ' => 'ụ',
  'Ủ' => 'Ủ',
  'ủ' => 'ủ',
  'Ứ' => 'Ứ',
  'ứ' => 'ứ',
  'Ừ' => 'Ừ',
  'ừ' => 'ừ',
  'Ử' => 'Ử',
  'ử' => 'ử',
  'Ữ' => 'Ữ',
  'ữ' => 'ữ',
  'Ự' => 'Ự',
  'ự' => 'ự',
  'Ỳ' => 'Ỳ',
  'ỳ' => 'ỳ',
  'Ỵ' => 'Ỵ',
  'ỵ' => 'ỵ',
  'Ỷ' => 'Ỷ',
  'ỷ' => 'ỷ',
  'Ỹ' => 'Ỹ',
  'ỹ' => 'ỹ',
  'ἀ' => 'ἀ',
  'ἁ' => 'ἁ',
  'ἂ' => 'ἂ',
  'ἃ' => 'ἃ',
  'ἄ' => 'ἄ',
  'ἅ' => 'ἅ',
  'ἆ' => 'ἆ',
  'ἇ' => 'ἇ',
  'Ἀ' => 'Ἀ',
  'Ἁ' => 'Ἁ',
  'Ἂ' => 'Ἂ',
  'Ἃ' => 'Ἃ',
  'Ἄ' => 'Ἄ',
  'Ἅ' => 'Ἅ',
  'Ἆ' => 'Ἆ',
  'Ἇ' => 'Ἇ',
  'ἐ' => 'ἐ',
  'ἑ' => 'ἑ',
  'ἒ' => 'ἒ',
  'ἓ' => 'ἓ',
  'ἔ' => 'ἔ',
  'ἕ' => 'ἕ',
  'Ἐ' => 'Ἐ',
  'Ἑ' => 'Ἑ',
  'Ἒ' => 'Ἒ',
  'Ἓ' => 'Ἓ',
  'Ἔ' => 'Ἔ',
  'Ἕ' => 'Ἕ',
  'ἠ' => 'ἠ',
  'ἡ' => 'ἡ',
  'ἢ' => 'ἢ',
  'ἣ' => 'ἣ',
  'ἤ' => 'ἤ',
  'ἥ' => 'ἥ',
  'ἦ' => 'ἦ',
  'ἧ' => 'ἧ',
  'Ἠ' => 'Ἠ',
  'Ἡ' => 'Ἡ',
  'Ἢ' => 'Ἢ',
  'Ἣ' => 'Ἣ',
  'Ἤ' => 'Ἤ',
  'Ἥ' => 'Ἥ',
  'Ἦ' => 'Ἦ',
  'Ἧ' => 'Ἧ',
  'ἰ' => 'ἰ',
  'ἱ' => 'ἱ',
  'ἲ' => 'ἲ',
  'ἳ' => 'ἳ',
  'ἴ' => 'ἴ',
  'ἵ' => 'ἵ',
  'ἶ' => 'ἶ',
  'ἷ' => 'ἷ',
  'Ἰ' => 'Ἰ',
  'Ἱ' => 'Ἱ',
  'Ἲ' => 'Ἲ',
  'Ἳ' => 'Ἳ',
  'Ἴ' => 'Ἴ',
  'Ἵ' => 'Ἵ',
  'Ἶ' => 'Ἶ',
  'Ἷ' => 'Ἷ',
  'ὀ' => 'ὀ',
  'ὁ' => 'ὁ',
  'ὂ' => 'ὂ',
  'ὃ' => 'ὃ',
  'ὄ' => 'ὄ',
  'ὅ' => 'ὅ',
  'Ὀ' => 'Ὀ',
  'Ὁ' => 'Ὁ',
  'Ὂ' => 'Ὂ',
  'Ὃ' => 'Ὃ',
  'Ὄ' => 'Ὄ',
  'Ὅ' => 'Ὅ',
  'ὐ' => 'ὐ',
  'ὑ' => 'ὑ',
  'ὒ' => 'ὒ',
  'ὓ' => 'ὓ',
  'ὔ' => 'ὔ',
  'ὕ' => 'ὕ',
  'ὖ' => 'ὖ',
  'ὗ' => 'ὗ',
  'Ὑ' => 'Ὑ',
  'Ὓ' => 'Ὓ',
  'Ὕ' => 'Ὕ',
  'Ὗ' => 'Ὗ',
  'ὠ' => 'ὠ',
  'ὡ' => 'ὡ',
  'ὢ' => 'ὢ',
  'ὣ' => 'ὣ',
  'ὤ' => 'ὤ',
  'ὥ' => 'ὥ',
  'ὦ' => 'ὦ',
  'ὧ' => 'ὧ',
  'Ὠ' => 'Ὠ',
  'Ὡ' => 'Ὡ',
  'Ὢ' => 'Ὢ',
  'Ὣ' => 'Ὣ',
  'Ὤ' => 'Ὤ',
  'Ὥ' => 'Ὥ',
  'Ὦ' => 'Ὦ',
  'Ὧ' => 'Ὧ',
  'ὰ' => 'ὰ',
  'ὲ' => 'ὲ',
  'ὴ' => 'ὴ',
  'ὶ' => 'ὶ',
  'ὸ' => 'ὸ',
  'ὺ' => 'ὺ',
  'ὼ' => 'ὼ',
  'ᾀ' => 'ᾀ',
  'ᾁ' => 'ᾁ',
  'ᾂ' => 'ᾂ',
  'ᾃ' => 'ᾃ',
  'ᾄ' => 'ᾄ',
  'ᾅ' => 'ᾅ',
  'ᾆ' => 'ᾆ',
  'ᾇ' => 'ᾇ',
  'ᾈ' => 'ᾈ',
  'ᾉ' => 'ᾉ',
  'ᾊ' => 'ᾊ',
  'ᾋ' => 'ᾋ',
  'ᾌ' => 'ᾌ',
  'ᾍ' => 'ᾍ',
  'ᾎ' => 'ᾎ',
  'ᾏ' => 'ᾏ',
  'ᾐ' => 'ᾐ',
  'ᾑ' => 'ᾑ',
  'ᾒ' => 'ᾒ',
  'ᾓ' => 'ᾓ',
  'ᾔ' => 'ᾔ',
  'ᾕ' => 'ᾕ',
  'ᾖ' => 'ᾖ',
  'ᾗ' => 'ᾗ',
  'ᾘ' => 'ᾘ',
  'ᾙ' => 'ᾙ',
  'ᾚ' => 'ᾚ',
  'ᾛ' => 'ᾛ',
  'ᾜ' => 'ᾜ',
  'ᾝ' => 'ᾝ',
  'ᾞ' => 'ᾞ',
  'ᾟ' => 'ᾟ',
  'ᾠ' => 'ᾠ',
  'ᾡ' => 'ᾡ',
  'ᾢ' => 'ᾢ',
  'ᾣ' => 'ᾣ',
  'ᾤ' => 'ᾤ',
  'ᾥ' => 'ᾥ',
  'ᾦ' => 'ᾦ',
  'ᾧ' => 'ᾧ',
  'ᾨ' => 'ᾨ',
  'ᾩ' => 'ᾩ',
  'ᾪ' => 'ᾪ',
  'ᾫ' => 'ᾫ',
  'ᾬ' => 'ᾬ',
  'ᾭ' => 'ᾭ',
  'ᾮ' => 'ᾮ',
  'ᾯ' => 'ᾯ',
  'ᾰ' => 'ᾰ',
  'ᾱ' => 'ᾱ',
  'ᾲ' => 'ᾲ',
  'ᾳ' => 'ᾳ',
  'ᾴ' => 'ᾴ',
  'ᾶ' => 'ᾶ',
  'ᾷ' => 'ᾷ',
  'Ᾰ' => 'Ᾰ',
  'Ᾱ' => 'Ᾱ',
  'Ὰ' => 'Ὰ',
  'ᾼ' => 'ᾼ',
  '῁' => '῁',
  'ῂ' => 'ῂ',
  'ῃ' => 'ῃ',
  'ῄ' => 'ῄ',
  'ῆ' => 'ῆ',
  'ῇ' => 'ῇ',
  'Ὲ' => 'Ὲ',
  'Ὴ' => 'Ὴ',
  'ῌ' => 'ῌ',
  '῍' => '῍',
  '῎' => '῎',
  '῏' => '῏',
  'ῐ' => 'ῐ',
  'ῑ' => 'ῑ',
  'ῒ' => 'ῒ',
  'ῖ' => 'ῖ',
  'ῗ' => 'ῗ',
  'Ῐ' => 'Ῐ',
  'Ῑ' => 'Ῑ',
  'Ὶ' => 'Ὶ',
  '῝' => '῝',
  '῞' => '῞',
  '῟' => '῟',
  'ῠ' => 'ῠ',
  'ῡ' => 'ῡ',
  'ῢ' => 'ῢ',
  'ῤ' => 'ῤ',
  'ῥ' => 'ῥ',
  'ῦ' => 'ῦ',
  'ῧ' => 'ῧ',
  'Ῠ' => 'Ῠ',
  'Ῡ' => 'Ῡ',
  'Ὺ' => 'Ὺ',
  'Ῥ' => 'Ῥ',
  '῭' => '῭',
  'ῲ' => 'ῲ',
  'ῳ' => 'ῳ',
  'ῴ' => 'ῴ',
  'ῶ' => 'ῶ',
  'ῷ' => 'ῷ',
  'Ὸ' => 'Ὸ',
  'Ὼ' => 'Ὼ',
  'ῼ' => 'ῼ',
  '↚' => '↚',
  '↛' => '↛',
  '↮' => '↮',
  '⇍' => '⇍',
  '⇎' => '⇎',
  '⇏' => '⇏',
  '∄' => '∄',
  '∉' => '∉',
  '∌' => '∌',
  '∤' => '∤',
  '∦' => '∦',
  '≁' => '≁',
  '≄' => '≄',
  '≇' => '≇',
  '≉' => '≉',
  '≠' => '≠',
  '≢' => '≢',
  '≭' => '≭',
  '≮' => '≮',
  '≯' => '≯',
  '≰' => '≰',
  '≱' => '≱',
  '≴' => '≴',
  '≵' => '≵',
  '≸' => '≸',
  '≹' => '≹',
  '⊀' => '⊀',
  '⊁' => '⊁',
  '⊄' => '⊄',
  '⊅' => '⊅',
  '⊈' => '⊈',
  '⊉' => '⊉',
  '⊬' => '⊬',
  '⊭' => '⊭',
  '⊮' => '⊮',
  '⊯' => '⊯',
  '⋠' => '⋠',
  '⋡' => '⋡',
  '⋢' => '⋢',
  '⋣' => '⋣',
  '⋪' => '⋪',
  '⋫' => '⋫',
  '⋬' => '⋬',
  '⋭' => '⋭',
  'が' => 'が',
  'ぎ' => 'ぎ',
  'ぐ' => 'ぐ',
  'げ' => 'げ',
  'ご' => 'ご',
  'ざ' => 'ざ',
  'じ' => 'じ',
  'ず' => 'ず',
  'ぜ' => 'ぜ',
  'ぞ' => 'ぞ',
  'だ' => 'だ',
  'ぢ' => 'ぢ',
  'づ' => 'づ',
  'で' => 'で',
  'ど' => 'ど',
  'ば' => 'ば',
  'ぱ' => 'ぱ',
  'び' => 'び',
  'ぴ' => 'ぴ',
  'ぶ' => 'ぶ',
  'ぷ' => 'ぷ',
  'べ' => 'べ',
  'ぺ' => 'ぺ',
  'ぼ' => 'ぼ',
  'ぽ' => 'ぽ',
  'ゔ' => 'ゔ',
  'ゞ' => 'ゞ',
  'ガ' => 'ガ',
  'ギ' => 'ギ',
  'グ' => 'グ',
  'ゲ' => 'ゲ',
  'ゴ' => 'ゴ',
  'ザ' => 'ザ',
  'ジ' => 'ジ',
  'ズ' => 'ズ',
  'ゼ' => 'ゼ',
  'ゾ' => 'ゾ',
  'ダ' => 'ダ',
  'ヂ' => 'ヂ',
  'ヅ' => 'ヅ',
  'デ' => 'デ',
  'ド' => 'ド',
  'バ' => 'バ',
  'パ' => 'パ',
  'ビ' => 'ビ',
  'ピ' => 'ピ',
  'ブ' => 'ブ',
  'プ' => 'プ',
  'ベ' => 'ベ',
  'ペ' => 'ペ',
  'ボ' => 'ボ',
  'ポ' => 'ポ',
  'ヴ' => 'ヴ',
  'ヷ' => 'ヷ',
  'ヸ' => 'ヸ',
  'ヹ' => 'ヹ',
  'ヺ' => 'ヺ',
  'ヾ' => 'ヾ',
  '𑂚' => '𑂚',
  '𑂜' => '𑂜',
  '𑂫' => '𑂫',
  '𑄮' => '𑄮',
  '𑄯' => '𑄯',
  '𑍋' => '𑍋',
  '𑍌' => '𑍌',
  '𑒻' => '𑒻',
  '𑒼' => '𑒼',
  '𑒾' => '𑒾',
  '𑖺' => '𑖺',
  '𑖻' => '𑖻',
  '𑤸' => '𑤸',
);
<?php

return array (
  'À' => 'À',
  'Á' => 'Á',
  'Â' => 'Â',
  'Ã' => 'Ã',
  'Ä' => 'Ä',
  'Å' => 'Å',
  'Ç' => 'Ç',
  'È' => 'È',
  'É' => 'É',
  'Ê' => 'Ê',
  'Ë' => 'Ë',
  'Ì' => 'Ì',
  'Í' => 'Í',
  'Î' => 'Î',
  'Ï' => 'Ï',
  'Ñ' => 'Ñ',
  'Ò' => 'Ò',
  'Ó' => 'Ó',
  'Ô' => 'Ô',
  'Õ' => 'Õ',
  'Ö' => 'Ö',
  'Ù' => 'Ù',
  'Ú' => 'Ú',
  'Û' => 'Û',
  'Ü' => 'Ü',
  'Ý' => 'Ý',
  'à' => 'à',
  'á' => 'á',
  'â' => 'â',
  'ã' => 'ã',
  'ä' => 'ä',
  'å' => 'å',
  'ç' => 'ç',
  'è' => 'è',
  'é' => 'é',
  'ê' => 'ê',
  'ë' => 'ë',
  'ì' => 'ì',
  'í' => 'í',
  'î' => 'î',
  'ï' => 'ï',
  'ñ' => 'ñ',
  'ò' => 'ò',
  'ó' => 'ó',
  'ô' => 'ô',
  'õ' => 'õ',
  'ö' => 'ö',
  'ù' => 'ù',
  'ú' => 'ú',
  'û' => 'û',
  'ü' => 'ü',
  'ý' => 'ý',
  'ÿ' => 'ÿ',
  'Ā' => 'Ā',
  'ā' => 'ā',
  'Ă' => 'Ă',
  'ă' => 'ă',
  'Ą' => 'Ą',
  'ą' => 'ą',
  'Ć' => 'Ć',
  'ć' => 'ć',
  'Ĉ' => 'Ĉ',
  'ĉ' => 'ĉ',
  'Ċ' => 'Ċ',
  'ċ' => 'ċ',
  'Č' => 'Č',
  'č' => 'č',
  'Ď' => 'Ď',
  'ď' => 'ď',
  'Ē' => 'Ē',
  'ē' => 'ē',
  'Ĕ' => 'Ĕ',
  'ĕ' => 'ĕ',
  'Ė' => 'Ė',
  'ė' => 'ė',
  'Ę' => 'Ę',
  'ę' => 'ę',
  'Ě' => 'Ě',
  'ě' => 'ě',
  'Ĝ' => 'Ĝ',
  'ĝ' => 'ĝ',
  'Ğ' => 'Ğ',
  'ğ' => 'ğ',
  'Ġ' => 'Ġ',
  'ġ' => 'ġ',
  'Ģ' => 'Ģ',
  'ģ' => 'ģ',
  'Ĥ' => 'Ĥ',
  'ĥ' => 'ĥ',
  'Ĩ' => 'Ĩ',
  'ĩ' => 'ĩ',
  'Ī' => 'Ī',
  'ī' => 'ī',
  'Ĭ' => 'Ĭ',
  'ĭ' => 'ĭ',
  'Į' => 'Į',
  'į' => 'į',
  'İ' => 'İ',
  'Ĵ' => 'Ĵ',
  'ĵ' => 'ĵ',
  'Ķ' => 'Ķ',
  'ķ' => 'ķ',
  'Ĺ' => 'Ĺ',
  'ĺ' => 'ĺ',
  'Ļ' => 'Ļ',
  'ļ' => 'ļ',
  'Ľ' => 'Ľ',
  'ľ' => 'ľ',
  'Ń' => 'Ń',
  'ń' => 'ń',
  'Ņ' => 'Ņ',
  'ņ' => 'ņ',
  'Ň' => 'Ň',
  'ň' => 'ň',
  'Ō' => 'Ō',
  'ō' => 'ō',
  'Ŏ' => 'Ŏ',
  'ŏ' => 'ŏ',
  'Ő' => 'Ő',
  'ő' => 'ő',
  'Ŕ' => 'Ŕ',
  'ŕ' => 'ŕ',
  'Ŗ' => 'Ŗ',
  'ŗ' => 'ŗ',
  'Ř' => 'Ř',
  'ř' => 'ř',
  'Ś' => 'Ś',
  'ś' => 'ś',
  'Ŝ' => 'Ŝ',
  'ŝ' => 'ŝ',
  'Ş' => 'Ş',
  'ş' => 'ş',
  'Š' => 'Š',
  'š' => 'š',
  'Ţ' => 'Ţ',
  'ţ' => 'ţ',
  'Ť' => 'Ť',
  'ť' => 'ť',
  'Ũ' => 'Ũ',
  'ũ' => 'ũ',
  'Ū' => 'Ū',
  'ū' => 'ū',
  'Ŭ' => 'Ŭ',
  'ŭ' => 'ŭ',
  'Ů' => 'Ů',
  'ů' => 'ů',
  'Ű' => 'Ű',
  'ű' => 'ű',
  'Ų' => 'Ų',
  'ų' => 'ų',
  'Ŵ' => 'Ŵ',
  'ŵ' => 'ŵ',
  'Ŷ' => 'Ŷ',
  'ŷ' => 'ŷ',
  'Ÿ' => 'Ÿ',
  'Ź' => 'Ź',
  'ź' => 'ź',
  'Ż' => 'Ż',
  'ż' => 'ż',
  'Ž' => 'Ž',
  'ž' => 'ž',
  'Ơ' => 'Ơ',
  'ơ' => 'ơ',
  'Ư' => 'Ư',
  'ư' => 'ư',
  'Ǎ' => 'Ǎ',
  'ǎ' => 'ǎ',
  'Ǐ' => 'Ǐ',
  'ǐ' => 'ǐ',
  'Ǒ' => 'Ǒ',
  'ǒ' => 'ǒ',
  'Ǔ' => 'Ǔ',
  'ǔ' => 'ǔ',
  'Ǖ' => 'Ǖ',
  'ǖ' => 'ǖ',
  'Ǘ' => 'Ǘ',
  'ǘ' => 'ǘ',
  'Ǚ' => 'Ǚ',
  'ǚ' => 'ǚ',
  'Ǜ' => 'Ǜ',
  'ǜ' => 'ǜ',
  'Ǟ' => 'Ǟ',
  'ǟ' => 'ǟ',
  'Ǡ' => 'Ǡ',
  'ǡ' => 'ǡ',
  'Ǣ' => 'Ǣ',
  'ǣ' => 'ǣ',
  'Ǧ' => 'Ǧ',
  'ǧ' => 'ǧ',
  'Ǩ' => 'Ǩ',
  'ǩ' => 'ǩ',
  'Ǫ' => 'Ǫ',
  'ǫ' => 'ǫ',
  'Ǭ' => 'Ǭ',
  'ǭ' => 'ǭ',
  'Ǯ' => 'Ǯ',
  'ǯ' => 'ǯ',
  'ǰ' => 'ǰ',
  'Ǵ' => 'Ǵ',
  'ǵ' => 'ǵ',
  'Ǹ' => 'Ǹ',
  'ǹ' => 'ǹ',
  'Ǻ' => 'Ǻ',
  'ǻ' => 'ǻ',
  'Ǽ' => 'Ǽ',
  'ǽ' => 'ǽ',
  'Ǿ' => 'Ǿ',
  'ǿ' => 'ǿ',
  'Ȁ' => 'Ȁ',
  'ȁ' => 'ȁ',
  'Ȃ' => 'Ȃ',
  'ȃ' => 'ȃ',
  'Ȅ' => 'Ȅ',
  'ȅ' => 'ȅ',
  'Ȇ' => 'Ȇ',
  'ȇ' => 'ȇ',
  'Ȉ' => 'Ȉ',
  'ȉ' => 'ȉ',
  'Ȋ' => 'Ȋ',
  'ȋ' => 'ȋ',
  'Ȍ' => 'Ȍ',
  'ȍ' => 'ȍ',
  'Ȏ' => 'Ȏ',
  'ȏ' => 'ȏ',
  'Ȑ' => 'Ȑ',
  'ȑ' => 'ȑ',
  'Ȓ' => 'Ȓ',
  'ȓ' => 'ȓ',
  'Ȕ' => 'Ȕ',
  'ȕ' => 'ȕ',
  'Ȗ' => 'Ȗ',
  'ȗ' => 'ȗ',
  'Ș' => 'Ș',
  'ș' => 'ș',
  'Ț' => 'Ț',
  'ț' => 'ț',
  'Ȟ' => 'Ȟ',
  'ȟ' => 'ȟ',
  'Ȧ' => 'Ȧ',
  'ȧ' => 'ȧ',
  'Ȩ' => 'Ȩ',
  'ȩ' => 'ȩ',
  'Ȫ' => 'Ȫ',
  'ȫ' => 'ȫ',
  'Ȭ' => 'Ȭ',
  'ȭ' => 'ȭ',
  'Ȯ' => 'Ȯ',
  'ȯ' => 'ȯ',
  'Ȱ' => 'Ȱ',
  'ȱ' => 'ȱ',
  'Ȳ' => 'Ȳ',
  'ȳ' => 'ȳ',
  '̀' => '̀',
  '́' => '́',
  '̓' => '̓',
  '̈́' => '̈́',
  'ʹ' => 'ʹ',
  ';' => ';',
  '΅' => '΅',
  'Ά' => 'Ά',
  '·' => '·',
  'Έ' => 'Έ',
  'Ή' => 'Ή',
  'Ί' => 'Ί',
  'Ό' => 'Ό',
  'Ύ' => 'Ύ',
  'Ώ' => 'Ώ',
  'ΐ' => 'ΐ',
  'Ϊ' => 'Ϊ',
  'Ϋ' => 'Ϋ',
  'ά' => 'ά',
  'έ' => 'έ',
  'ή' => 'ή',
  'ί' => 'ί',
  'ΰ' => 'ΰ',
  'ϊ' => 'ϊ',
  'ϋ' => 'ϋ',
  'ό' => 'ό',
  'ύ' => 'ύ',
  'ώ' => 'ώ',
  'ϓ' => 'ϓ',
  'ϔ' => 'ϔ',
  'Ѐ' => 'Ѐ',
  'Ё' => 'Ё',
  'Ѓ' => 'Ѓ',
  'Ї' => 'Ї',
  'Ќ' => 'Ќ',
  'Ѝ' => 'Ѝ',
  'Ў' => 'Ў',
  'Й' => 'Й',
  'й' => 'й',
  'ѐ' => 'ѐ',
  'ё' => 'ё',
  'ѓ' => 'ѓ',
  'ї' => 'ї',
  'ќ' => 'ќ',
  'ѝ' => 'ѝ',
  'ў' => 'ў',
  'Ѷ' => 'Ѷ',
  'ѷ' => 'ѷ',
  'Ӂ' => 'Ӂ',
  'ӂ' => 'ӂ',
  'Ӑ' => 'Ӑ',
  'ӑ' => 'ӑ',
  'Ӓ' => 'Ӓ',
  'ӓ' => 'ӓ',
  'Ӗ' => 'Ӗ',
  'ӗ' => 'ӗ',
  'Ӛ' => 'Ӛ',
  'ӛ' => 'ӛ',
  'Ӝ' => 'Ӝ',
  'ӝ' => 'ӝ',
  'Ӟ' => 'Ӟ',
  'ӟ' => 'ӟ',
  'Ӣ' => 'Ӣ',
  'ӣ' => 'ӣ',
  'Ӥ' => 'Ӥ',
  'ӥ' => 'ӥ',
  'Ӧ' => 'Ӧ',
  'ӧ' => 'ӧ',
  'Ӫ' => 'Ӫ',
  'ӫ' => 'ӫ',
  'Ӭ' => 'Ӭ',
  'ӭ' => 'ӭ',
  'Ӯ' => 'Ӯ',
  'ӯ' => 'ӯ',
  'Ӱ' => 'Ӱ',
  'ӱ' => 'ӱ',
  'Ӳ' => 'Ӳ',
  'ӳ' => 'ӳ',
  'Ӵ' => 'Ӵ',
  'ӵ' => 'ӵ',
  'Ӹ' => 'Ӹ',
  'ӹ' => 'ӹ',
  'آ' => 'آ',
  'أ' => 'أ',
  'ؤ' => 'ؤ',
  'إ' => 'إ',
  'ئ' => 'ئ',
  'ۀ' => 'ۀ',
  'ۂ' => 'ۂ',
  'ۓ' => 'ۓ',
  'ऩ' => 'ऩ',
  'ऱ' => 'ऱ',
  'ऴ' => 'ऴ',
  'क़' => 'क़',
  'ख़' => 'ख़',
  'ग़' => 'ग़',
  'ज़' => 'ज़',
  'ड़' => 'ड़',
  'ढ़' => 'ढ़',
  'फ़' => 'फ़',
  'य़' => 'य़',
  'ো' => 'ো',
  'ৌ' => 'ৌ',
  'ড়' => 'ড়',
  'ঢ়' => 'ঢ়',
  'য়' => 'য়',
  'ਲ਼' => 'ਲ਼',
  'ਸ਼' => 'ਸ਼',
  'ਖ਼' => 'ਖ਼',
  'ਗ਼' => 'ਗ਼',
  'ਜ਼' => 'ਜ਼',
  'ਫ਼' => 'ਫ਼',
  'ୈ' => 'ୈ',
  'ୋ' => 'ୋ',
  'ୌ' => 'ୌ',
  'ଡ଼' => 'ଡ଼',
  'ଢ଼' => 'ଢ଼',
  'ஔ' => 'ஔ',
  'ொ' => 'ொ',
  'ோ' => 'ோ',
  'ௌ' => 'ௌ',
  'ై' => 'ై',
  'ೀ' => 'ೀ',
  'ೇ' => 'ೇ',
  'ೈ' => 'ೈ',
  'ೊ' => 'ೊ',
  'ೋ' => 'ೋ',
  'ൊ' => 'ൊ',
  'ോ' => 'ോ',
  'ൌ' => 'ൌ',
  'ේ' => 'ේ',
  'ො' => 'ො',
  'ෝ' => 'ෝ',
  'ෞ' => 'ෞ',
  'གྷ' => 'གྷ',
  'ཌྷ' => 'ཌྷ',
  'དྷ' => 'དྷ',
  'བྷ' => 'བྷ',
  'ཛྷ' => 'ཛྷ',
  'ཀྵ' => 'ཀྵ',
  'ཱི' => 'ཱི',
  'ཱུ' => 'ཱུ',
  'ྲྀ' => 'ྲྀ',
  'ླྀ' => 'ླྀ',
  'ཱྀ' => 'ཱྀ',
  'ྒྷ' => 'ྒྷ',
  'ྜྷ' => 'ྜྷ',
  'ྡྷ' => 'ྡྷ',
  'ྦྷ' => 'ྦྷ',
  'ྫྷ' => 'ྫྷ',
  'ྐྵ' => 'ྐྵ',
  'ဦ' => 'ဦ',
  'ᬆ' => 'ᬆ',
  'ᬈ' => 'ᬈ',
  'ᬊ' => 'ᬊ',
  'ᬌ' => 'ᬌ',
  'ᬎ' => 'ᬎ',
  'ᬒ' => 'ᬒ',
  'ᬻ' => 'ᬻ',
  'ᬽ' => 'ᬽ',
  'ᭀ' => 'ᭀ',
  'ᭁ' => 'ᭁ',
  'ᭃ' => 'ᭃ',
  'Ḁ' => 'Ḁ',
  'ḁ' => 'ḁ',
  'Ḃ' => 'Ḃ',
  'ḃ' => 'ḃ',
  'Ḅ' => 'Ḅ',
  'ḅ' => 'ḅ',
  'Ḇ' => 'Ḇ',
  'ḇ' => 'ḇ',
  'Ḉ' => 'Ḉ',
  'ḉ' => 'ḉ',
  'Ḋ' => 'Ḋ',
  'ḋ' => 'ḋ',
  'Ḍ' => 'Ḍ',
  'ḍ' => 'ḍ',
  'Ḏ' => 'Ḏ',
  'ḏ' => 'ḏ',
  'Ḑ' => 'Ḑ',
  'ḑ' => 'ḑ',
  'Ḓ' => 'Ḓ',
  'ḓ' => 'ḓ',
  'Ḕ' => 'Ḕ',
  'ḕ' => 'ḕ',
  'Ḗ' => 'Ḗ',
  'ḗ' => 'ḗ',
  'Ḙ' => 'Ḙ',
  'ḙ' => 'ḙ',
  'Ḛ' => 'Ḛ',
  'ḛ' => 'ḛ',
  'Ḝ' => 'Ḝ',
  'ḝ' => 'ḝ',
  'Ḟ' => 'Ḟ',
  'ḟ' => 'ḟ',
  'Ḡ' => 'Ḡ',
  'ḡ' => 'ḡ',
  'Ḣ' => 'Ḣ',
  'ḣ' => 'ḣ',
  'Ḥ' => 'Ḥ',
  'ḥ' => 'ḥ',
  'Ḧ' => 'Ḧ',
  'ḧ' => 'ḧ',
  'Ḩ' => 'Ḩ',
  'ḩ' => 'ḩ',
  'Ḫ' => 'Ḫ',
  'ḫ' => 'ḫ',
  'Ḭ' => 'Ḭ',
  'ḭ' => 'ḭ',
  'Ḯ' => 'Ḯ',
  'ḯ' => 'ḯ',
  'Ḱ' => 'Ḱ',
  'ḱ' => 'ḱ',
  'Ḳ' => 'Ḳ',
  'ḳ' => 'ḳ',
  'Ḵ' => 'Ḵ',
  'ḵ' => 'ḵ',
  'Ḷ' => 'Ḷ',
  'ḷ' => 'ḷ',
  'Ḹ' => 'Ḹ',
  'ḹ' => 'ḹ',
  'Ḻ' => 'Ḻ',
  'ḻ' => 'ḻ',
  'Ḽ' => 'Ḽ',
  'ḽ' => 'ḽ',
  'Ḿ' => 'Ḿ',
  'ḿ' => 'ḿ',
  'Ṁ' => 'Ṁ',
  'ṁ' => 'ṁ',
  'Ṃ' => 'Ṃ',
  'ṃ' => 'ṃ',
  'Ṅ' => 'Ṅ',
  'ṅ' => 'ṅ',
  'Ṇ' => 'Ṇ',
  'ṇ' => 'ṇ',
  'Ṉ' => 'Ṉ',
  'ṉ' => 'ṉ',
  'Ṋ' => 'Ṋ',
  'ṋ' => 'ṋ',
  'Ṍ' => 'Ṍ',
  'ṍ' => 'ṍ',
  'Ṏ' => 'Ṏ',
  'ṏ' => 'ṏ',
  'Ṑ' => 'Ṑ',
  'ṑ' => 'ṑ',
  'Ṓ' => 'Ṓ',
  'ṓ' => 'ṓ',
  'Ṕ' => 'Ṕ',
  'ṕ' => 'ṕ',
  'Ṗ' => 'Ṗ',
  'ṗ' => 'ṗ',
  'Ṙ' => 'Ṙ',
  'ṙ' => 'ṙ',
  'Ṛ' => 'Ṛ',
  'ṛ' => 'ṛ',
  'Ṝ' => 'Ṝ',
  'ṝ' => 'ṝ',
  'Ṟ' => 'Ṟ',
  'ṟ' => 'ṟ',
  'Ṡ' => 'Ṡ',
  'ṡ' => 'ṡ',
  'Ṣ' => 'Ṣ',
  'ṣ' => 'ṣ',
  'Ṥ' => 'Ṥ',
  'ṥ' => 'ṥ',
  'Ṧ' => 'Ṧ',
  'ṧ' => 'ṧ',
  'Ṩ' => 'Ṩ',
  'ṩ' => 'ṩ',
  'Ṫ' => 'Ṫ',
  'ṫ' => 'ṫ',
  'Ṭ' => 'Ṭ',
  'ṭ' => 'ṭ',
  'Ṯ' => 'Ṯ',
  'ṯ' => 'ṯ',
  'Ṱ' => 'Ṱ',
  'ṱ' => 'ṱ',
  'Ṳ' => 'Ṳ',
  'ṳ' => 'ṳ',
  'Ṵ' => 'Ṵ',
  'ṵ' => 'ṵ',
  'Ṷ' => 'Ṷ',
  'ṷ' => 'ṷ',
  'Ṹ' => 'Ṹ',
  'ṹ' => 'ṹ',
  'Ṻ' => 'Ṻ',
  'ṻ' => 'ṻ',
  'Ṽ' => 'Ṽ',
  'ṽ' => 'ṽ',
  'Ṿ' => 'Ṿ',
  'ṿ' => 'ṿ',
  'Ẁ' => 'Ẁ',
  'ẁ' => 'ẁ',
  'Ẃ' => 'Ẃ',
  'ẃ' => 'ẃ',
  'Ẅ' => 'Ẅ',
  'ẅ' => 'ẅ',
  'Ẇ' => 'Ẇ',
  'ẇ' => 'ẇ',
  'Ẉ' => 'Ẉ',
  'ẉ' => 'ẉ',
  'Ẋ' => 'Ẋ',
  'ẋ' => 'ẋ',
  'Ẍ' => 'Ẍ',
  'ẍ' => 'ẍ',
  'Ẏ' => 'Ẏ',
  'ẏ' => 'ẏ',
  'Ẑ' => 'Ẑ',
  'ẑ' => 'ẑ',
  'Ẓ' => 'Ẓ',
  'ẓ' => 'ẓ',
  'Ẕ' => 'Ẕ',
  'ẕ' => 'ẕ',
  'ẖ' => 'ẖ',
  'ẗ' => 'ẗ',
  'ẘ' => 'ẘ',
  'ẙ' => 'ẙ',
  'ẛ' => 'ẛ',
  'Ạ' => 'Ạ',
  'ạ' => 'ạ',
  'Ả' => 'Ả',
  'ả' => 'ả',
  'Ấ' => 'Ấ',
  'ấ' => 'ấ',
  'Ầ' => 'Ầ',
  'ầ' => 'ầ',
  'Ẩ' => 'Ẩ',
  'ẩ' => 'ẩ',
  'Ẫ' => 'Ẫ',
  'ẫ' => 'ẫ',
  'Ậ' => 'Ậ',
  'ậ' => 'ậ',
  'Ắ' => 'Ắ',
  'ắ' => 'ắ',
  'Ằ' => 'Ằ',
  'ằ' => 'ằ',
  'Ẳ' => 'Ẳ',
  'ẳ' => 'ẳ',
  'Ẵ' => 'Ẵ',
  'ẵ' => 'ẵ',
  'Ặ' => 'Ặ',
  'ặ' => 'ặ',
  'Ẹ' => 'Ẹ',
  'ẹ' => 'ẹ',
  'Ẻ' => 'Ẻ',
  'ẻ' => 'ẻ',
  'Ẽ' => 'Ẽ',
  'ẽ' => 'ẽ',
  'Ế' => 'Ế',
  'ế' => 'ế',
  'Ề' => 'Ề',
  'ề' => 'ề',
  'Ể' => 'Ể',
  'ể' => 'ể',
  'Ễ' => 'Ễ',
  'ễ' => 'ễ',
  'Ệ' => 'Ệ',
  'ệ' => 'ệ',
  'Ỉ' => 'Ỉ',
  'ỉ' => 'ỉ',
  'Ị' => 'Ị',
  'ị' => 'ị',
  'Ọ' => 'Ọ',
  'ọ' => 'ọ',
  'Ỏ' => 'Ỏ',
  'ỏ' => 'ỏ',
  'Ố' => 'Ố',
  'ố' => 'ố',
  'Ồ' => 'Ồ',
  'ồ' => 'ồ',
  'Ổ' => 'Ổ',
  'ổ' => 'ổ',
  'Ỗ' => 'Ỗ',
  'ỗ' => 'ỗ',
  'Ộ' => 'Ộ',
  'ộ' => 'ộ',
  'Ớ' => 'Ớ',
  'ớ' => 'ớ',
  'Ờ' => 'Ờ',
  'ờ' => 'ờ',
  'Ở' => 'Ở',
  'ở' => 'ở',
  'Ỡ' => 'Ỡ',
  'ỡ' => 'ỡ',
  'Ợ' => 'Ợ',
  'ợ' => 'ợ',
  'Ụ' => 'Ụ',
  'ụ' => 'ụ',
  'Ủ' => 'Ủ',
  'ủ' => 'ủ',
  'Ứ' => 'Ứ',
  'ứ' => 'ứ',
  'Ừ' => 'Ừ',
  'ừ' => 'ừ',
  'Ử' => 'Ử',
  'ử' => 'ử',
  'Ữ' => 'Ữ',
  'ữ' => 'ữ',
  'Ự' => 'Ự',
  'ự' => 'ự',
  'Ỳ' => 'Ỳ',
  'ỳ' => 'ỳ',
  'Ỵ' => 'Ỵ',
  'ỵ' => 'ỵ',
  'Ỷ' => 'Ỷ',
  'ỷ' => 'ỷ',
  'Ỹ' => 'Ỹ',
  'ỹ' => 'ỹ',
  'ἀ' => 'ἀ',
  'ἁ' => 'ἁ',
  'ἂ' => 'ἂ',
  'ἃ' => 'ἃ',
  'ἄ' => 'ἄ',
  'ἅ' => 'ἅ',
  'ἆ' => 'ἆ',
  'ἇ' => 'ἇ',
  'Ἀ' => 'Ἀ',
  'Ἁ' => 'Ἁ',
  'Ἂ' => 'Ἂ',
  'Ἃ' => 'Ἃ',
  'Ἄ' => 'Ἄ',
  'Ἅ' => 'Ἅ',
  'Ἆ' => 'Ἆ',
  'Ἇ' => 'Ἇ',
  'ἐ' => 'ἐ',
  'ἑ' => 'ἑ',
  'ἒ' => 'ἒ',
  'ἓ' => 'ἓ',
  'ἔ' => 'ἔ',
  'ἕ' => 'ἕ',
  'Ἐ' => 'Ἐ',
  'Ἑ' => 'Ἑ',
  'Ἒ' => 'Ἒ',
  'Ἓ' => 'Ἓ',
  'Ἔ' => 'Ἔ',
  'Ἕ' => 'Ἕ',
  'ἠ' => 'ἠ',
  'ἡ' => 'ἡ',
  'ἢ' => 'ἢ',
  'ἣ' => 'ἣ',
  'ἤ' => 'ἤ',
  'ἥ' => 'ἥ',
  'ἦ' => 'ἦ',
  'ἧ' => 'ἧ',
  'Ἠ' => 'Ἠ',
  'Ἡ' => 'Ἡ',
  'Ἢ' => 'Ἢ',
  'Ἣ' => 'Ἣ',
  'Ἤ' => 'Ἤ',
  'Ἥ' => 'Ἥ',
  'Ἦ' => 'Ἦ',
  'Ἧ' => 'Ἧ',
  'ἰ' => 'ἰ',
  'ἱ' => 'ἱ',
  'ἲ' => 'ἲ',
  'ἳ' => 'ἳ',
  'ἴ' => 'ἴ',
  'ἵ' => 'ἵ',
  'ἶ' => 'ἶ',
  'ἷ' => 'ἷ',
  'Ἰ' => 'Ἰ',
  'Ἱ' => 'Ἱ',
  'Ἲ' => 'Ἲ',
  'Ἳ' => 'Ἳ',
  'Ἴ' => 'Ἴ',
  'Ἵ' => 'Ἵ',
  'Ἶ' => 'Ἶ',
  'Ἷ' => 'Ἷ',
  'ὀ' => 'ὀ',
  'ὁ' => 'ὁ',
  'ὂ' => 'ὂ',
  'ὃ' => 'ὃ',
  'ὄ' => 'ὄ',
  'ὅ' => 'ὅ',
  'Ὀ' => 'Ὀ',
  'Ὁ' => 'Ὁ',
  'Ὂ' => 'Ὂ',
  'Ὃ' => 'Ὃ',
  'Ὄ' => 'Ὄ',
  'Ὅ' => 'Ὅ',
  'ὐ' => 'ὐ',
  'ὑ' => 'ὑ',
  'ὒ' => 'ὒ',
  'ὓ' => 'ὓ',
  'ὔ' => 'ὔ',
  'ὕ' => 'ὕ',
  'ὖ' => 'ὖ',
  'ὗ' => 'ὗ',
  'Ὑ' => 'Ὑ',
  'Ὓ' => 'Ὓ',
  'Ὕ' => 'Ὕ',
  'Ὗ' => 'Ὗ',
  'ὠ' => 'ὠ',
  'ὡ' => 'ὡ',
  'ὢ' => 'ὢ',
  'ὣ' => 'ὣ',
  'ὤ' => 'ὤ',
  'ὥ' => 'ὥ',
  'ὦ' => 'ὦ',
  'ὧ' => 'ὧ',
  'Ὠ' => 'Ὠ',
  'Ὡ' => 'Ὡ',
  'Ὢ' => 'Ὢ',
  'Ὣ' => 'Ὣ',
  'Ὤ' => 'Ὤ',
  'Ὥ' => 'Ὥ',
  'Ὦ' => 'Ὦ',
  'Ὧ' => 'Ὧ',
  'ὰ' => 'ὰ',
  'ά' => 'ά',
  'ὲ' => 'ὲ',
  'έ' => 'έ',
  'ὴ' => 'ὴ',
  'ή' => 'ή',
  'ὶ' => 'ὶ',
  'ί' => 'ί',
  'ὸ' => 'ὸ',
  'ό' => 'ό',
  'ὺ' => 'ὺ',
  'ύ' => 'ύ',
  'ὼ' => 'ὼ',
  'ώ' => 'ώ',
  'ᾀ' => 'ᾀ',
  'ᾁ' => 'ᾁ',
  'ᾂ' => 'ᾂ',
  'ᾃ' => 'ᾃ',
  'ᾄ' => 'ᾄ',
  'ᾅ' => 'ᾅ',
  'ᾆ' => 'ᾆ',
  'ᾇ' => 'ᾇ',
  'ᾈ' => 'ᾈ',
  'ᾉ' => 'ᾉ',
  'ᾊ' => 'ᾊ',
  'ᾋ' => 'ᾋ',
  'ᾌ' => 'ᾌ',
  'ᾍ' => 'ᾍ',
  'ᾎ' => 'ᾎ',
  'ᾏ' => 'ᾏ',
  'ᾐ' => 'ᾐ',
  'ᾑ' => 'ᾑ',
  'ᾒ' => 'ᾒ',
  'ᾓ' => 'ᾓ',
  'ᾔ' => 'ᾔ',
  'ᾕ' => 'ᾕ',
  'ᾖ' => 'ᾖ',
  'ᾗ' => 'ᾗ',
  'ᾘ' => 'ᾘ',
  'ᾙ' => 'ᾙ',
  'ᾚ' => 'ᾚ',
  'ᾛ' => 'ᾛ',
  'ᾜ' => 'ᾜ',
  'ᾝ' => 'ᾝ',
  'ᾞ' => 'ᾞ',
  'ᾟ' => 'ᾟ',
  'ᾠ' => 'ᾠ',
  'ᾡ' => 'ᾡ',
  'ᾢ' => 'ᾢ',
  'ᾣ' => 'ᾣ',
  'ᾤ' => 'ᾤ',
  'ᾥ' => 'ᾥ',
  'ᾦ' => 'ᾦ',
  'ᾧ' => 'ᾧ',
  'ᾨ' => 'ᾨ',
  'ᾩ' => 'ᾩ',
  'ᾪ' => 'ᾪ',
  'ᾫ' => 'ᾫ',
  'ᾬ' => 'ᾬ',
  'ᾭ' => 'ᾭ',
  'ᾮ' => 'ᾮ',
  'ᾯ' => 'ᾯ',
  'ᾰ' => 'ᾰ',
  'ᾱ' => 'ᾱ',
  'ᾲ' => 'ᾲ',
  'ᾳ' => 'ᾳ',
  'ᾴ' => 'ᾴ',
  'ᾶ' => 'ᾶ',
  'ᾷ' => 'ᾷ',
  'Ᾰ' => 'Ᾰ',
  'Ᾱ' => 'Ᾱ',
  'Ὰ' => 'Ὰ',
  'Ά' => 'Ά',
  'ᾼ' => 'ᾼ',
  'ι' => 'ι',
  '῁' => '῁',
  'ῂ' => 'ῂ',
  'ῃ' => 'ῃ',
  'ῄ' => 'ῄ',
  'ῆ' => 'ῆ',
  'ῇ' => 'ῇ',
  'Ὲ' => 'Ὲ',
  'Έ' => 'Έ',
  'Ὴ' => 'Ὴ',
  'Ή' => 'Ή',
  'ῌ' => 'ῌ',
  '῍' => '῍',
  '῎' => '῎',
  '῏' => '῏',
  'ῐ' => 'ῐ',
  'ῑ' => 'ῑ',
  'ῒ' => 'ῒ',
  'ΐ' => 'ΐ',
  'ῖ' => 'ῖ',
  'ῗ' => 'ῗ',
  'Ῐ' => 'Ῐ',
  'Ῑ' => 'Ῑ',
  'Ὶ' => 'Ὶ',
  'Ί' => 'Ί',
  '῝' => '῝',
  '῞' => '῞',
  '῟' => '῟',
  'ῠ' => 'ῠ',
  'ῡ' => 'ῡ',
  'ῢ' => 'ῢ',
  'ΰ' => 'ΰ',
  'ῤ' => 'ῤ',
  'ῥ' => 'ῥ',
  'ῦ' => 'ῦ',
  'ῧ' => 'ῧ',
  'Ῠ' => 'Ῠ',
  'Ῡ' => 'Ῡ',
  'Ὺ' => 'Ὺ',
  'Ύ' => 'Ύ',
  'Ῥ' => 'Ῥ',
  '῭' => '῭',
  '΅' => '΅',
  '`' => '`',
  'ῲ' => 'ῲ',
  'ῳ' => 'ῳ',
  'ῴ' => 'ῴ',
  'ῶ' => 'ῶ',
  'ῷ' => 'ῷ',
  'Ὸ' => 'Ὸ',
  'Ό' => 'Ό',
  'Ὼ' => 'Ὼ',
  'Ώ' => 'Ώ',
  'ῼ' => 'ῼ',
  '´' => '´',
  ' ' => ' ',
  ' ' => ' ',
  'Ω' => 'Ω',
  'K' => 'K',
  'Å' => 'Å',
  '↚' => '↚',
  '↛' => '↛',
  '↮' => '↮',
  '⇍' => '⇍',
  '⇎' => '⇎',
  '⇏' => '⇏',
  '∄' => '∄',
  '∉' => '∉',
  '∌' => '∌',
  '∤' => '∤',
  '∦' => '∦',
  '≁' => '≁',
  '≄' => '≄',
  '≇' => '≇',
  '≉' => '≉',
  '≠' => '≠',
  '≢' => '≢',
  '≭' => '≭',
  '≮' => '≮',
  '≯' => '≯',
  '≰' => '≰',
  '≱' => '≱',
  '≴' => '≴',
  '≵' => '≵',
  '≸' => '≸',
  '≹' => '≹',
  '⊀' => '⊀',
  '⊁' => '⊁',
  '⊄' => '⊄',
  '⊅' => '⊅',
  '⊈' => '⊈',
  '⊉' => '⊉',
  '⊬' => '⊬',
  '⊭' => '⊭',
  '⊮' => '⊮',
  '⊯' => '⊯',
  '⋠' => '⋠',
  '⋡' => '⋡',
  '⋢' => '⋢',
  '⋣' => '⋣',
  '⋪' => '⋪',
  '⋫' => '⋫',
  '⋬' => '⋬',
  '⋭' => '⋭',
  '〈' => '〈',
  '〉' => '〉',
  '⫝̸' => '⫝̸',
  'が' => 'が',
  'ぎ' => 'ぎ',
  'ぐ' => 'ぐ',
  'げ' => 'げ',
  'ご' => 'ご',
  'ざ' => 'ざ',
  'じ' => 'じ',
  'ず' => 'ず',
  'ぜ' => 'ぜ',
  'ぞ' => 'ぞ',
  'だ' => 'だ',
  'ぢ' => 'ぢ',
  'づ' => 'づ',
  'で' => 'で',
  'ど' => 'ど',
  'ば' => 'ば',
  'ぱ' => 'ぱ',
  'び' => 'び',
  'ぴ' => 'ぴ',
  'ぶ' => 'ぶ',
  'ぷ' => 'ぷ',
  'べ' => 'べ',
  'ぺ' => 'ぺ',
  'ぼ' => 'ぼ',
  'ぽ' => 'ぽ',
  'ゔ' => 'ゔ',
  'ゞ' => 'ゞ',
  'ガ' => 'ガ',
  'ギ' => 'ギ',
  'グ' => 'グ',
  'ゲ' => 'ゲ',
  'ゴ' => 'ゴ',
  'ザ' => 'ザ',
  'ジ' => 'ジ',
  'ズ' => 'ズ',
  'ゼ' => 'ゼ',
  'ゾ' => 'ゾ',
  'ダ' => 'ダ',
  'ヂ' => 'ヂ',
  'ヅ' => 'ヅ',
  'デ' => 'デ',
  'ド' => 'ド',
  'バ' => 'バ',
  'パ' => 'パ',
  'ビ' => 'ビ',
  'ピ' => 'ピ',
  'ブ' => 'ブ',
  'プ' => 'プ',
  'ベ' => 'ベ',
  'ペ' => 'ペ',
  'ボ' => 'ボ',
  'ポ' => 'ポ',
  'ヴ' => 'ヴ',
  'ヷ' => 'ヷ',
  'ヸ' => 'ヸ',
  'ヹ' => 'ヹ',
  'ヺ' => 'ヺ',
  'ヾ' => 'ヾ',
  '豈' => '豈',
  '更' => '更',
  '車' => '車',
  '賈' => '賈',
  '滑' => '滑',
  '串' => '串',
  '句' => '句',
  '龜' => '龜',
  '龜' => '龜',
  '契' => '契',
  '金' => '金',
  '喇' => '喇',
  '奈' => '奈',
  '懶' => '懶',
  '癩' => '癩',
  '羅' => '羅',
  '蘿' => '蘿',
  '螺' => '螺',
  '裸' => '裸',
  '邏' => '邏',
  '樂' => '樂',
  '洛' => '洛',
  '烙' => '烙',
  '珞' => '珞',
  '落' => '落',
  '酪' => '酪',
  '駱' => '駱',
  '亂' => '亂',
  '卵' => '卵',
  '欄' => '欄',
  '爛' => '爛',
  '蘭' => '蘭',
  '鸞' => '鸞',
  '嵐' => '嵐',
  '濫' => '濫',
  '藍' => '藍',
  '襤' => '襤',
  '拉' => '拉',
  '臘' => '臘',
  '蠟' => '蠟',
  '廊' => '廊',
  '朗' => '朗',
  '浪' => '浪',
  '狼' => '狼',
  '郎' => '郎',
  '來' => '來',
  '冷' => '冷',
  '勞' => '勞',
  '擄' => '擄',
  '櫓' => '櫓',
  '爐' => '爐',
  '盧' => '盧',
  '老' => '老',
  '蘆' => '蘆',
  '虜' => '虜',
  '路' => '路',
  '露' => '露',
  '魯' => '魯',
  '鷺' => '鷺',
  '碌' => '碌',
  '祿' => '祿',
  '綠' => '綠',
  '菉' => '菉',
  '錄' => '錄',
  '鹿' => '鹿',
  '論' => '論',
  '壟' => '壟',
  '弄' => '弄',
  '籠' => '籠',
  '聾' => '聾',
  '牢' => '牢',
  '磊' => '磊',
  '賂' => '賂',
  '雷' => '雷',
  '壘' => '壘',
  '屢' => '屢',
  '樓' => '樓',
  '淚' => '淚',
  '漏' => '漏',
  '累' => '累',
  '縷' => '縷',
  '陋' => '陋',
  '勒' => '勒',
  '肋' => '肋',
  '凜' => '凜',
  '凌' => '凌',
  '稜' => '稜',
  '綾' => '綾',
  '菱' => '菱',
  '陵' => '陵',
  '讀' => '讀',
  '拏' => '拏',
  '樂' => '樂',
  '諾' => '諾',
  '丹' => '丹',
  '寧' => '寧',
  '怒' => '怒',
  '率' => '率',
  '異' => '異',
  '北' => '北',
  '磻' => '磻',
  '便' => '便',
  '復' => '復',
  '不' => '不',
  '泌' => '泌',
  '數' => '數',
  '索' => '索',
  '參' => '參',
  '塞' => '塞',
  '省' => '省',
  '葉' => '葉',
  '說' => '說',
  '殺' => '殺',
  '辰' => '辰',
  '沈' => '沈',
  '拾' => '拾',
  '若' => '若',
  '掠' => '掠',
  '略' => '略',
  '亮' => '亮',
  '兩' => '兩',
  '凉' => '凉',
  '梁' => '梁',
  '糧' => '糧',
  '良' => '良',
  '諒' => '諒',
  '量' => '量',
  '勵' => '勵',
  '呂' => '呂',
  '女' => '女',
  '廬' => '廬',
  '旅' => '旅',
  '濾' => '濾',
  '礪' => '礪',
  '閭' => '閭',
  '驪' => '驪',
  '麗' => '麗',
  '黎' => '黎',
  '力' => '力',
  '曆' => '曆',
  '歷' => '歷',
  '轢' => '轢',
  '年' => '年',
  '憐' => '憐',
  '戀' => '戀',
  '撚' => '撚',
  '漣' => '漣',
  '煉' => '煉',
  '璉' => '璉',
  '秊' => '秊',
  '練' => '練',
  '聯' => '聯',
  '輦' => '輦',
  '蓮' => '蓮',
  '連' => '連',
  '鍊' => '鍊',
  '列' => '列',
  '劣' => '劣',
  '咽' => '咽',
  '烈' => '烈',
  '裂' => '裂',
  '說' => '說',
  '廉' => '廉',
  '念' => '念',
  '捻' => '捻',
  '殮' => '殮',
  '簾' => '簾',
  '獵' => '獵',
  '令' => '令',
  '囹' => '囹',
  '寧' => '寧',
  '嶺' => '嶺',
  '怜' => '怜',
  '玲' => '玲',
  '瑩' => '瑩',
  '羚' => '羚',
  '聆' => '聆',
  '鈴' => '鈴',
  '零' => '零',
  '靈' => '靈',
  '領' => '領',
  '例' => '例',
  '禮' => '禮',
  '醴' => '醴',
  '隸' => '隸',
  '惡' => '惡',
  '了' => '了',
  '僚' => '僚',
  '寮' => '寮',
  '尿' => '尿',
  '料' => '料',
  '樂' => '樂',
  '燎' => '燎',
  '療' => '療',
  '蓼' => '蓼',
  '遼' => '遼',
  '龍' => '龍',
  '暈' => '暈',
  '阮' => '阮',
  '劉' => '劉',
  '杻' => '杻',
  '柳' => '柳',
  '流' => '流',
  '溜' => '溜',
  '琉' => '琉',
  '留' => '留',
  '硫' => '硫',
  '紐' => '紐',
  '類' => '類',
  '六' => '六',
  '戮' => '戮',
  '陸' => '陸',
  '倫' => '倫',
  '崙' => '崙',
  '淪' => '淪',
  '輪' => '輪',
  '律' => '律',
  '慄' => '慄',
  '栗' => '栗',
  '率' => '率',
  '隆' => '隆',
  '利' => '利',
  '吏' => '吏',
  '履' => '履',
  '易' => '易',
  '李' => '李',
  '梨' => '梨',
  '泥' => '泥',
  '理' => '理',
  '痢' => '痢',
  '罹' => '罹',
  '裏' => '裏',
  '裡' => '裡',
  '里' => '里',
  '離' => '離',
  '匿' => '匿',
  '溺' => '溺',
  '吝' => '吝',
  '燐' => '燐',
  '璘' => '璘',
  '藺' => '藺',
  '隣' => '隣',
  '鱗' => '鱗',
  '麟' => '麟',
  '林' => '林',
  '淋' => '淋',
  '臨' => '臨',
  '立' => '立',
  '笠' => '笠',
  '粒' => '粒',
  '狀' => '狀',
  '炙' => '炙',
  '識' => '識',
  '什' => '什',
  '茶' => '茶',
  '刺' => '刺',
  '切' => '切',
  '度' => '度',
  '拓' => '拓',
  '糖' => '糖',
  '宅' => '宅',
  '洞' => '洞',
  '暴' => '暴',
  '輻' => '輻',
  '行' => '行',
  '降' => '降',
  '見' => '見',
  '廓' => '廓',
  '兀' => '兀',
  '嗀' => '嗀',
  '塚' => '塚',
  '晴' => '晴',
  '凞' => '凞',
  '猪' => '猪',
  '益' => '益',
  '礼' => '礼',
  '神' => '神',
  '祥' => '祥',
  '福' => '福',
  '靖' => '靖',
  '精' => '精',
  '羽' => '羽',
  '蘒' => '蘒',
  '諸' => '諸',
  '逸' => '逸',
  '都' => '都',
  '飯' => '飯',
  '飼' => '飼',
  '館' => '館',
  '鶴' => '鶴',
  '郞' => '郞',
  '隷' => '隷',
  '侮' => '侮',
  '僧' => '僧',
  '免' => '免',
  '勉' => '勉',
  '勤' => '勤',
  '卑' => '卑',
  '喝' => '喝',
  '嘆' => '嘆',
  '器' => '器',
  '塀' => '塀',
  '墨' => '墨',
  '層' => '層',
  '屮' => '屮',
  '悔' => '悔',
  '慨' => '慨',
  '憎' => '憎',
  '懲' => '懲',
  '敏' => '敏',
  '既' => '既',
  '暑' => '暑',
  '梅' => '梅',
  '海' => '海',
  '渚' => '渚',
  '漢' => '漢',
  '煮' => '煮',
  '爫' => '爫',
  '琢' => '琢',
  '碑' => '碑',
  '社' => '社',
  '祉' => '祉',
  '祈' => '祈',
  '祐' => '祐',
  '祖' => '祖',
  '祝' => '祝',
  '禍' => '禍',
  '禎' => '禎',
  '穀' => '穀',
  '突' => '突',
  '節' => '節',
  '練' => '練',
  '縉' => '縉',
  '繁' => '繁',
  '署' => '署',
  '者' => '者',
  '臭' => '臭',
  '艹' => '艹',
  '艹' => '艹',
  '著' => '著',
  '褐' => '褐',
  '視' => '視',
  '謁' => '謁',
  '謹' => '謹',
  '賓' => '賓',
  '贈' => '贈',
  '辶' => '辶',
  '逸' => '逸',
  '難' => '難',
  '響' => '響',
  '頻' => '頻',
  '恵' => '恵',
  '𤋮' => '𤋮',
  '舘' => '舘',
  '並' => '並',
  '况' => '况',
  '全' => '全',
  '侀' => '侀',
  '充' => '充',
  '冀' => '冀',
  '勇' => '勇',
  '勺' => '勺',
  '喝' => '喝',
  '啕' => '啕',
  '喙' => '喙',
  '嗢' => '嗢',
  '塚' => '塚',
  '墳' => '墳',
  '奄' => '奄',
  '奔' => '奔',
  '婢' => '婢',
  '嬨' => '嬨',
  '廒' => '廒',
  '廙' => '廙',
  '彩' => '彩',
  '徭' => '徭',
  '惘' => '惘',
  '慎' => '慎',
  '愈' => '愈',
  '憎' => '憎',
  '慠' => '慠',
  '懲' => '懲',
  '戴' => '戴',
  '揄' => '揄',
  '搜' => '搜',
  '摒' => '摒',
  '敖' => '敖',
  '晴' => '晴',
  '朗' => '朗',
  '望' => '望',
  '杖' => '杖',
  '歹' => '歹',
  '殺' => '殺',
  '流' => '流',
  '滛' => '滛',
  '滋' => '滋',
  '漢' => '漢',
  '瀞' => '瀞',
  '煮' => '煮',
  '瞧' => '瞧',
  '爵' => '爵',
  '犯' => '犯',
  '猪' => '猪',
  '瑱' => '瑱',
  '甆' => '甆',
  '画' => '画',
  '瘝' => '瘝',
  '瘟' => '瘟',
  '益' => '益',
  '盛' => '盛',
  '直' => '直',
  '睊' => '睊',
  '着' => '着',
  '磌' => '磌',
  '窱' => '窱',
  '節' => '節',
  '类' => '类',
  '絛' => '絛',
  '練' => '練',
  '缾' => '缾',
  '者' => '者',
  '荒' => '荒',
  '華' => '華',
  '蝹' => '蝹',
  '襁' => '襁',
  '覆' => '覆',
  '視' => '視',
  '調' => '調',
  '諸' => '諸',
  '請' => '請',
  '謁' => '謁',
  '諾' => '諾',
  '諭' => '諭',
  '謹' => '謹',
  '變' => '變',
  '贈' => '贈',
  '輸' => '輸',
  '遲' => '遲',
  '醙' => '醙',
  '鉶' => '鉶',
  '陼' => '陼',
  '難' => '難',
  '靖' => '靖',
  '韛' => '韛',
  '響' => '響',
  '頋' => '頋',
  '頻' => '頻',
  '鬒' => '鬒',
  '龜' => '龜',
  '𢡊' => '𢡊',
  '𢡄' => '𢡄',
  '𣏕' => '𣏕',
  '㮝' => '㮝',
  '䀘' => '䀘',
  '䀹' => '䀹',
  '𥉉' => '𥉉',
  '𥳐' => '𥳐',
  '𧻓' => '𧻓',
  '齃' => '齃',
  '龎' => '龎',
  'יִ' => 'יִ',
  'ײַ' => 'ײַ',
  'שׁ' => 'שׁ',
  'שׂ' => 'שׂ',
  'שּׁ' => 'שּׁ',
  'שּׂ' => 'שּׂ',
  'אַ' => 'אַ',
  'אָ' => 'אָ',
  'אּ' => 'אּ',
  'בּ' => 'בּ',
  'גּ' => 'גּ',
  'דּ' => 'דּ',
  'הּ' => 'הּ',
  'וּ' => 'וּ',
  'זּ' => 'זּ',
  'טּ' => 'טּ',
  'יּ' => 'יּ',
  'ךּ' => 'ךּ',
  'כּ' => 'כּ',
  'לּ' => 'לּ',
  'מּ' => 'מּ',
  'נּ' => 'נּ',
  'סּ' => 'סּ',
  'ףּ' => 'ףּ',
  'פּ' => 'פּ',
  'צּ' => 'צּ',
  'קּ' => 'קּ',
  'רּ' => 'רּ',
  'שּ' => 'שּ',
  'תּ' => 'תּ',
  'וֹ' => 'וֹ',
  'בֿ' => 'בֿ',
  'כֿ' => 'כֿ',
  'פֿ' => 'פֿ',
  '𑂚' => '𑂚',
  '𑂜' => '𑂜',
  '𑂫' => '𑂫',
  '𑄮' => '𑄮',
  '𑄯' => '𑄯',
  '𑍋' => '𑍋',
  '𑍌' => '𑍌',
  '𑒻' => '𑒻',
  '𑒼' => '𑒼',
  '𑒾' => '𑒾',
  '𑖺' => '𑖺',
  '𑖻' => '𑖻',
  '𑤸' => '𑤸',
  '𝅗𝅥' => '𝅗𝅥',
  '𝅘𝅥' => '𝅘𝅥',
  '𝅘𝅥𝅮' => '𝅘𝅥𝅮',
  '𝅘𝅥𝅯' => '𝅘𝅥𝅯',
  '𝅘𝅥𝅰' => '𝅘𝅥𝅰',
  '𝅘𝅥𝅱' => '𝅘𝅥𝅱',
  '𝅘𝅥𝅲' => '𝅘𝅥𝅲',
  '𝆹𝅥' => '𝆹𝅥',
  '𝆺𝅥' => '𝆺𝅥',
  '𝆹𝅥𝅮' => '𝆹𝅥𝅮',
  '𝆺𝅥𝅮' => '𝆺𝅥𝅮',
  '𝆹𝅥𝅯' => '𝆹𝅥𝅯',
  '𝆺𝅥𝅯' => '𝆺𝅥𝅯',
  '丽' => '丽',
  '丸' => '丸',
  '乁' => '乁',
  '𠄢' => '𠄢',
  '你' => '你',
  '侮' => '侮',
  '侻' => '侻',
  '倂' => '倂',
  '偺' => '偺',
  '備' => '備',
  '僧' => '僧',
  '像' => '像',
  '㒞' => '㒞',
  '𠘺' => '𠘺',
  '免' => '免',
  '兔' => '兔',
  '兤' => '兤',
  '具' => '具',
  '𠔜' => '𠔜',
  '㒹' => '㒹',
  '內' => '內',
  '再' => '再',
  '𠕋' => '𠕋',
  '冗' => '冗',
  '冤' => '冤',
  '仌' => '仌',
  '冬' => '冬',
  '况' => '况',
  '𩇟' => '𩇟',
  '凵' => '凵',
  '刃' => '刃',
  '㓟' => '㓟',
  '刻' => '刻',
  '剆' => '剆',
  '割' => '割',
  '剷' => '剷',
  '㔕' => '㔕',
  '勇' => '勇',
  '勉' => '勉',
  '勤' => '勤',
  '勺' => '勺',
  '包' => '包',
  '匆' => '匆',
  '北' => '北',
  '卉' => '卉',
  '卑' => '卑',
  '博' => '博',
  '即' => '即',
  '卽' => '卽',
  '卿' => '卿',
  '卿' => '卿',
  '卿' => '卿',
  '𠨬' => '𠨬',
  '灰' => '灰',
  '及' => '及',
  '叟' => '叟',
  '𠭣' => '𠭣',
  '叫' => '叫',
  '叱' => '叱',
  '吆' => '吆',
  '咞' => '咞',
  '吸' => '吸',
  '呈' => '呈',
  '周' => '周',
  '咢' => '咢',
  '哶' => '哶',
  '唐' => '唐',
  '啓' => '啓',
  '啣' => '啣',
  '善' => '善',
  '善' => '善',
  '喙' => '喙',
  '喫' => '喫',
  '喳' => '喳',
  '嗂' => '嗂',
  '圖' => '圖',
  '嘆' => '嘆',
  '圗' => '圗',
  '噑' => '噑',
  '噴' => '噴',
  '切' => '切',
  '壮' => '壮',
  '城' => '城',
  '埴' => '埴',
  '堍' => '堍',
  '型' => '型',
  '堲' => '堲',
  '報' => '報',
  '墬' => '墬',
  '𡓤' => '𡓤',
  '売' => '売',
  '壷' => '壷',
  '夆' => '夆',
  '多' => '多',
  '夢' => '夢',
  '奢' => '奢',
  '𡚨' => '𡚨',
  '𡛪' => '𡛪',
  '姬' => '姬',
  '娛' => '娛',
  '娧' => '娧',
  '姘' => '姘',
  '婦' => '婦',
  '㛮' => '㛮',
  '㛼' => '㛼',
  '嬈' => '嬈',
  '嬾' => '嬾',
  '嬾' => '嬾',
  '𡧈' => '𡧈',
  '寃' => '寃',
  '寘' => '寘',
  '寧' => '寧',
  '寳' => '寳',
  '𡬘' => '𡬘',
  '寿' => '寿',
  '将' => '将',
  '当' => '当',
  '尢' => '尢',
  '㞁' => '㞁',
  '屠' => '屠',
  '屮' => '屮',
  '峀' => '峀',
  '岍' => '岍',
  '𡷤' => '𡷤',
  '嵃' => '嵃',
  '𡷦' => '𡷦',
  '嵮' => '嵮',
  '嵫' => '嵫',
  '嵼' => '嵼',
  '巡' => '巡',
  '巢' => '巢',
  '㠯' => '㠯',
  '巽' => '巽',
  '帨' => '帨',
  '帽' => '帽',
  '幩' => '幩',
  '㡢' => '㡢',
  '𢆃' => '𢆃',
  '㡼' => '㡼',
  '庰' => '庰',
  '庳' => '庳',
  '庶' => '庶',
  '廊' => '廊',
  '𪎒' => '𪎒',
  '廾' => '廾',
  '𢌱' => '𢌱',
  '𢌱' => '𢌱',
  '舁' => '舁',
  '弢' => '弢',
  '弢' => '弢',
  '㣇' => '㣇',
  '𣊸' => '𣊸',
  '𦇚' => '𦇚',
  '形' => '形',
  '彫' => '彫',
  '㣣' => '㣣',
  '徚' => '徚',
  '忍' => '忍',
  '志' => '志',
  '忹' => '忹',
  '悁' => '悁',
  '㤺' => '㤺',
  '㤜' => '㤜',
  '悔' => '悔',
  '𢛔' => '𢛔',
  '惇' => '惇',
  '慈' => '慈',
  '慌' => '慌',
  '慎' => '慎',
  '慌' => '慌',
  '慺' => '慺',
  '憎' => '憎',
  '憲' => '憲',
  '憤' => '憤',
  '憯' => '憯',
  '懞' => '懞',
  '懲' => '懲',
  '懶' => '懶',
  '成' => '成',
  '戛' => '戛',
  '扝' => '扝',
  '抱' => '抱',
  '拔' => '拔',
  '捐' => '捐',
  '𢬌' => '𢬌',
  '挽' => '挽',
  '拼' => '拼',
  '捨' => '捨',
  '掃' => '掃',
  '揤' => '揤',
  '𢯱' => '𢯱',
  '搢' => '搢',
  '揅' => '揅',
  '掩' => '掩',
  '㨮' => '㨮',
  '摩' => '摩',
  '摾' => '摾',
  '撝' => '撝',
  '摷' => '摷',
  '㩬' => '㩬',
  '敏' => '敏',
  '敬' => '敬',
  '𣀊' => '𣀊',
  '旣' => '旣',
  '書' => '書',
  '晉' => '晉',
  '㬙' => '㬙',
  '暑' => '暑',
  '㬈' => '㬈',
  '㫤' => '㫤',
  '冒' => '冒',
  '冕' => '冕',
  '最' => '最',
  '暜' => '暜',
  '肭' => '肭',
  '䏙' => '䏙',
  '朗' => '朗',
  '望' => '望',
  '朡' => '朡',
  '杞' => '杞',
  '杓' => '杓',
  '𣏃' => '𣏃',
  '㭉' => '㭉',
  '柺' => '柺',
  '枅' => '枅',
  '桒' => '桒',
  '梅' => '梅',
  '𣑭' => '𣑭',
  '梎' => '梎',
  '栟' => '栟',
  '椔' => '椔',
  '㮝' => '㮝',
  '楂' => '楂',
  '榣' => '榣',
  '槪' => '槪',
  '檨' => '檨',
  '𣚣' => '𣚣',
  '櫛' => '櫛',
  '㰘' => '㰘',
  '次' => '次',
  '𣢧' => '𣢧',
  '歔' => '歔',
  '㱎' => '㱎',
  '歲' => '歲',
  '殟' => '殟',
  '殺' => '殺',
  '殻' => '殻',
  '𣪍' => '𣪍',
  '𡴋' => '𡴋',
  '𣫺' => '𣫺',
  '汎' => '汎',
  '𣲼' => '𣲼',
  '沿' => '沿',
  '泍' => '泍',
  '汧' => '汧',
  '洖' => '洖',
  '派' => '派',
  '海' => '海',
  '流' => '流',
  '浩' => '浩',
  '浸' => '浸',
  '涅' => '涅',
  '𣴞' => '𣴞',
  '洴' => '洴',
  '港' => '港',
  '湮' => '湮',
  '㴳' => '㴳',
  '滋' => '滋',
  '滇' => '滇',
  '𣻑' => '𣻑',
  '淹' => '淹',
  '潮' => '潮',
  '𣽞' => '𣽞',
  '𣾎' => '𣾎',
  '濆' => '濆',
  '瀹' => '瀹',
  '瀞' => '瀞',
  '瀛' => '瀛',
  '㶖' => '㶖',
  '灊' => '灊',
  '災' => '災',
  '灷' => '灷',
  '炭' => '炭',
  '𠔥' => '𠔥',
  '煅' => '煅',
  '𤉣' => '𤉣',
  '熜' => '熜',
  '𤎫' => '𤎫',
  '爨' => '爨',
  '爵' => '爵',
  '牐' => '牐',
  '𤘈' => '𤘈',
  '犀' => '犀',
  '犕' => '犕',
  '𤜵' => '𤜵',
  '𤠔' => '𤠔',
  '獺' => '獺',
  '王' => '王',
  '㺬' => '㺬',
  '玥' => '玥',
  '㺸' => '㺸',
  '㺸' => '㺸',
  '瑇' => '瑇',
  '瑜' => '瑜',
  '瑱' => '瑱',
  '璅' => '璅',
  '瓊' => '瓊',
  '㼛' => '㼛',
  '甤' => '甤',
  '𤰶' => '𤰶',
  '甾' => '甾',
  '𤲒' => '𤲒',
  '異' => '異',
  '𢆟' => '𢆟',
  '瘐' => '瘐',
  '𤾡' => '𤾡',
  '𤾸' => '𤾸',
  '𥁄' => '𥁄',
  '㿼' => '㿼',
  '䀈' => '䀈',
  '直' => '直',
  '𥃳' => '𥃳',
  '𥃲' => '𥃲',
  '𥄙' => '𥄙',
  '𥄳' => '𥄳',
  '眞' => '眞',
  '真' => '真',
  '真' => '真',
  '睊' => '睊',
  '䀹' => '䀹',
  '瞋' => '瞋',
  '䁆' => '䁆',
  '䂖' => '䂖',
  '𥐝' => '𥐝',
  '硎' => '硎',
  '碌' => '碌',
  '磌' => '磌',
  '䃣' => '䃣',
  '𥘦' => '𥘦',
  '祖' => '祖',
  '𥚚' => '𥚚',
  '𥛅' => '𥛅',
  '福' => '福',
  '秫' => '秫',
  '䄯' => '䄯',
  '穀' => '穀',
  '穊' => '穊',
  '穏' => '穏',
  '𥥼' => '𥥼',
  '𥪧' => '𥪧',
  '𥪧' => '𥪧',
  '竮' => '竮',
  '䈂' => '䈂',
  '𥮫' => '𥮫',
  '篆' => '篆',
  '築' => '築',
  '䈧' => '䈧',
  '𥲀' => '𥲀',
  '糒' => '糒',
  '䊠' => '䊠',
  '糨' => '糨',
  '糣' => '糣',
  '紀' => '紀',
  '𥾆' => '𥾆',
  '絣' => '絣',
  '䌁' => '䌁',
  '緇' => '緇',
  '縂' => '縂',
  '繅' => '繅',
  '䌴' => '䌴',
  '𦈨' => '𦈨',
  '𦉇' => '𦉇',
  '䍙' => '䍙',
  '𦋙' => '𦋙',
  '罺' => '罺',
  '𦌾' => '𦌾',
  '羕' => '羕',
  '翺' => '翺',
  '者' => '者',
  '𦓚' => '𦓚',
  '𦔣' => '𦔣',
  '聠' => '聠',
  '𦖨' => '𦖨',
  '聰' => '聰',
  '𣍟' => '𣍟',
  '䏕' => '䏕',
  '育' => '育',
  '脃' => '脃',
  '䐋' => '䐋',
  '脾' => '脾',
  '媵' => '媵',
  '𦞧' => '𦞧',
  '𦞵' => '𦞵',
  '𣎓' => '𣎓',
  '𣎜' => '𣎜',
  '舁' => '舁',
  '舄' => '舄',
  '辞' => '辞',
  '䑫' => '䑫',
  '芑' => '芑',
  '芋' => '芋',
  '芝' => '芝',
  '劳' => '劳',
  '花' => '花',
  '芳' => '芳',
  '芽' => '芽',
  '苦' => '苦',
  '𦬼' => '𦬼',
  '若' => '若',
  '茝' => '茝',
  '荣' => '荣',
  '莭' => '莭',
  '茣' => '茣',
  '莽' => '莽',
  '菧' => '菧',
  '著' => '著',
  '荓' => '荓',
  '菊' => '菊',
  '菌' => '菌',
  '菜' => '菜',
  '𦰶' => '𦰶',
  '𦵫' => '𦵫',
  '𦳕' => '𦳕',
  '䔫' => '䔫',
  '蓱' => '蓱',
  '蓳' => '蓳',
  '蔖' => '蔖',
  '𧏊' => '𧏊',
  '蕤' => '蕤',
  '𦼬' => '𦼬',
  '䕝' => '䕝',
  '䕡' => '䕡',
  '𦾱' => '𦾱',
  '𧃒' => '𧃒',
  '䕫' => '䕫',
  '虐' => '虐',
  '虜' => '虜',
  '虧' => '虧',
  '虩' => '虩',
  '蚩' => '蚩',
  '蚈' => '蚈',
  '蜎' => '蜎',
  '蛢' => '蛢',
  '蝹' => '蝹',
  '蜨' => '蜨',
  '蝫' => '蝫',
  '螆' => '螆',
  '䗗' => '䗗',
  '蟡' => '蟡',
  '蠁' => '蠁',
  '䗹' => '䗹',
  '衠' => '衠',
  '衣' => '衣',
  '𧙧' => '𧙧',
  '裗' => '裗',
  '裞' => '裞',
  '䘵' => '䘵',
  '裺' => '裺',
  '㒻' => '㒻',
  '𧢮' => '𧢮',
  '𧥦' => '𧥦',
  '䚾' => '䚾',
  '䛇' => '䛇',
  '誠' => '誠',
  '諭' => '諭',
  '變' => '變',
  '豕' => '豕',
  '𧲨' => '𧲨',
  '貫' => '貫',
  '賁' => '賁',
  '贛' => '贛',
  '起' => '起',
  '𧼯' => '𧼯',
  '𠠄' => '𠠄',
  '跋' => '跋',
  '趼' => '趼',
  '跰' => '跰',
  '𠣞' => '𠣞',
  '軔' => '軔',
  '輸' => '輸',
  '𨗒' => '𨗒',
  '𨗭' => '𨗭',
  '邔' => '邔',
  '郱' => '郱',
  '鄑' => '鄑',
  '𨜮' => '𨜮',
  '鄛' => '鄛',
  '鈸' => '鈸',
  '鋗' => '鋗',
  '鋘' => '鋘',
  '鉼' => '鉼',
  '鏹' => '鏹',
  '鐕' => '鐕',
  '𨯺' => '𨯺',
  '開' => '開',
  '䦕' => '䦕',
  '閷' => '閷',
  '𨵷' => '𨵷',
  '䧦' => '䧦',
  '雃' => '雃',
  '嶲' => '嶲',
  '霣' => '霣',
  '𩅅' => '𩅅',
  '𩈚' => '𩈚',
  '䩮' => '䩮',
  '䩶' => '䩶',
  '韠' => '韠',
  '𩐊' => '𩐊',
  '䪲' => '䪲',
  '𩒖' => '𩒖',
  '頋' => '頋',
  '頋' => '頋',
  '頩' => '頩',
  '𩖶' => '𩖶',
  '飢' => '飢',
  '䬳' => '䬳',
  '餩' => '餩',
  '馧' => '馧',
  '駂' => '駂',
  '駾' => '駾',
  '䯎' => '䯎',
  '𩬰' => '𩬰',
  '鬒' => '鬒',
  '鱀' => '鱀',
  '鳽' => '鳽',
  '䳎' => '䳎',
  '䳭' => '䳭',
  '鵧' => '鵧',
  '𪃎' => '𪃎',
  '䳸' => '䳸',
  '𪄅' => '𪄅',
  '𪈎' => '𪈎',
  '𪊑' => '𪊑',
  '麻' => '麻',
  '䵖' => '䵖',
  '黹' => '黹',
  '黾' => '黾',
  '鼅' => '鼅',
  '鼏' => '鼏',
  '鼖' => '鼖',
  '鼻' => '鼻',
  '𪘀' => '𪘀',
);
<?php

return array (
  '̀' => 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,
);
<?php

return array (
  ' ' => ' ',
  '¨' => ' ̈',
  'ª' => 'a',
  '¯' => ' ̄',
  '²' => '2',
  '³' => '3',
  '´' => ' ́',
  'µ' => 'μ',
  '¸' => ' ̧',
  '¹' => '1',
  'º' => 'o',
  '¼' => '1⁄4',
  '½' => '1⁄2',
  '¾' => '3⁄4',
  'Ĳ' => 'IJ',
  'ĳ' => 'ij',
  'Ŀ' => 'L·',
  'ŀ' => 'l·',
  'ŉ' => 'ʼn',
  'ſ' => 's',
  'Ǆ' => 'DŽ',
  'ǅ' => 'Dž',
  'ǆ' => 'dž',
  'Ǉ' => 'LJ',
  'ǈ' => 'Lj',
  'ǉ' => 'lj',
  'Ǌ' => 'NJ',
  'ǋ' => 'Nj',
  'ǌ' => 'nj',
  'Ǳ' => '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ʾ',
  'ẛ' => 'ṡ',
  '᾽' => ' ̓',
  '᾿' => ' ̓',
  '῀' => ' ͂',
  '῁' => ' ̈͂',
  '῍' => ' ̓̀',
  '῎' => ' ̓́',
  '῏' => ' ̓͂',
  '῝' => ' ̔̀',
  '῞' => ' ̔́',
  '῟' => ' ̔͂',
  '῭' => ' ̈̀',
  '΅' => ' ̈́',
  '´' => ' ́',
  '῾' => ' ̔',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  ' ' => ' ',
  '‑' => '‐',
  '‗' => ' ̳',
  '․' => '.',
  '‥' => '..',
  '…' => '...',
  ' ' => ' ',
  '″' => '′′',
  '‴' => '′′′',
  '‶' => '‵‵',
  '‷' => '‵‵‵',
  '‼' => '!!',
  '‾' => ' ̅',
  '⁇' => '??',
  '⁈' => '?!',
  '⁉' => '!?',
  '⁗' => '′′′′',
  ' ' => ' ',
  '⁰' => '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',
  'ﬁ' => 'fi',
  'ﬂ' => 'fl',
  'ﬃ' => 'ffi',
  'ﬄ' => 'ffl',
  'ﬅ' => 'st',
  'ﬆ' => 'st',
  'ﬓ' => 'մն',
  'ﬔ' => 'մե',
  'ﬕ' => 'մի',
  'ﬖ' => 'վն',
  'ﬗ' => 'մխ',
  'ﬠ' => 'ע',
  'ﬡ' => 'א',
  'ﬢ' => 'ד',
  'ﬣ' => 'ה',
  'ﬤ' => 'כ',
  'ﬥ' => 'ל',
  'ﬦ' => 'ם',
  'ﬧ' => 'ר',
  'ﬨ' => 'ת',
  '﬩' => '+',
  'ﭏ' => 'אל',
  'ﭐ' => 'ٱ',
  'ﭑ' => 'ٱ',
  'ﭒ' => 'ٻ',
  'ﭓ' => 'ٻ',
  'ﭔ' => 'ٻ',
  'ﭕ' => 'ٻ',
  'ﭖ' => 'پ',
  'ﭗ' => 'پ',
  'ﭘ' => 'پ',
  'ﭙ' => 'پ',
  'ﭚ' => 'ڀ',
  'ﭛ' => 'ڀ',
  'ﭜ' => 'ڀ',
  'ﭝ' => 'ڀ',
  'ﭞ' => 'ٺ',
  'ﭟ' => 'ٺ',
  'ﭠ' => 'ٺ',
  'ﭡ' => 'ٺ',
  'ﭢ' => 'ٿ',
  'ﭣ' => 'ٿ',
  'ﭤ' => 'ٿ',
  'ﭥ' => 'ٿ',
  'ﭦ' => 'ٹ',
  'ﭧ' => 'ٹ',
  'ﭨ' => 'ٹ',
  'ﭩ' => 'ٹ',
  'ﭪ' => 'ڤ',
  'ﭫ' => 'ڤ',
  'ﭬ' => 'ڤ',
  'ﭭ' => 'ڤ',
  'ﭮ' => 'ڦ',
  'ﭯ' => 'ڦ',
  'ﭰ' => 'ڦ',
  'ﭱ' => 'ڦ',
  'ﭲ' => 'ڄ',
  'ﭳ' => 'ڄ',
  'ﭴ' => 'ڄ',
  'ﭵ' => 'ڄ',
  'ﭶ' => 'ڃ',
  'ﭷ' => 'ڃ',
  'ﭸ' => 'ڃ',
  'ﭹ' => 'ڃ',
  'ﭺ' => 'چ',
  'ﭻ' => 'چ',
  'ﭼ' => 'چ',
  'ﭽ' => 'چ',
  'ﭾ' => 'ڇ',
  'ﭿ' => 'ڇ',
  'ﮀ' => 'ڇ',
  'ﮁ' => 'ڇ',
  'ﮂ' => 'ڍ',
  'ﮃ' => 'ڍ',
  'ﮄ' => 'ڌ',
  'ﮅ' => 'ڌ',
  'ﮆ' => 'ڎ',
  'ﮇ' => 'ڎ',
  'ﮈ' => 'ڈ',
  'ﮉ' => 'ڈ',
  'ﮊ' => 'ژ',
  'ﮋ' => 'ژ',
  'ﮌ' => 'ڑ',
  'ﮍ' => 'ڑ',
  'ﮎ' => 'ک',
  'ﮏ' => 'ک',
  'ﮐ' => 'ک',
  'ﮑ' => 'ک',
  'ﮒ' => 'گ',
  'ﮓ' => 'گ',
  'ﮔ' => 'گ',
  'ﮕ' => 'گ',
  'ﮖ' => 'ڳ',
  'ﮗ' => 'ڳ',
  'ﮘ' => 'ڳ',
  'ﮙ' => 'ڳ',
  'ﮚ' => 'ڱ',
  'ﮛ' => 'ڱ',
  'ﮜ' => 'ڱ',
  'ﮝ' => 'ڱ',
  'ﮞ' => 'ں',
  'ﮟ' => 'ں',
  'ﮠ' => 'ڻ',
  'ﮡ' => 'ڻ',
  'ﮢ' => 'ڻ',
  'ﮣ' => 'ڻ',
  'ﮤ' => 'ۀ',
  'ﮥ' => 'ۀ',
  'ﮦ' => 'ہ',
  'ﮧ' => 'ہ',
  'ﮨ' => 'ہ',
  'ﮩ' => 'ہ',
  'ﮪ' => 'ھ',
  'ﮫ' => 'ھ',
  'ﮬ' => 'ھ',
  'ﮭ' => 'ھ',
  'ﮮ' => 'ے',
  'ﮯ' => 'ے',
  'ﮰ' => 'ۓ',
  'ﮱ' => 'ۓ',
  'ﯓ' => 'ڭ',
  'ﯔ' => 'ڭ',
  'ﯕ' => 'ڭ',
  'ﯖ' => 'ڭ',
  'ﯗ' => 'ۇ',
  'ﯘ' => 'ۇ',
  'ﯙ' => 'ۆ',
  'ﯚ' => 'ۆ',
  'ﯛ' => 'ۈ',
  'ﯜ' => 'ۈ',
  'ﯝ' => 'ۇٴ',
  'ﯞ' => 'ۋ',
  'ﯟ' => 'ۋ',
  'ﯠ' => 'ۅ',
  'ﯡ' => 'ۅ',
  'ﯢ' => 'ۉ',
  'ﯣ' => 'ۉ',
  'ﯤ' => 'ې',
  'ﯥ' => 'ې',
  'ﯦ' => 'ې',
  'ﯧ' => 'ې',
  'ﯨ' => 'ى',
  'ﯩ' => 'ى',
  'ﯪ' => 'ئا',
  'ﯫ' => 'ئا',
  'ﯬ' => 'ئە',
  'ﯭ' => 'ئە',
  'ﯮ' => 'ئو',
  'ﯯ' => 'ئو',
  'ﯰ' => 'ئۇ',
  'ﯱ' => 'ئۇ',
  'ﯲ' => 'ئۆ',
  'ﯳ' => 'ئۆ',
  'ﯴ' => 'ئۈ',
  'ﯵ' => 'ئۈ',
  'ﯶ' => 'ئې',
  'ﯷ' => 'ئې',
  'ﯸ' => 'ئې',
  'ﯹ' => 'ئى',
  'ﯺ' => 'ئى',
  'ﯻ' => 'ئى',
  'ﯼ' => 'ی',
  'ﯽ' => 'ی',
  'ﯾ' => 'ی',
  'ﯿ' => 'ی',
  'ﰀ' => 'ئج',
  'ﰁ' => 'ئح',
  'ﰂ' => 'ئم',
  'ﰃ' => 'ئى',
  'ﰄ' => 'ئي',
  'ﰅ' => 'بج',
  'ﰆ' => 'بح',
  'ﰇ' => 'بخ',
  'ﰈ' => 'بم',
  'ﰉ' => 'بى',
  'ﰊ' => 'بي',
  'ﰋ' => 'تج',
  'ﰌ' => 'تح',
  'ﰍ' => 'تخ',
  'ﰎ' => 'تم',
  'ﰏ' => 'تى',
  'ﰐ' => 'تي',
  'ﰑ' => 'ثج',
  'ﰒ' => 'ثم',
  'ﰓ' => 'ثى',
  'ﰔ' => 'ثي',
  'ﰕ' => 'جح',
  'ﰖ' => 'جم',
  'ﰗ' => 'حج',
  'ﰘ' => 'حم',
  'ﰙ' => 'خج',
  'ﰚ' => 'خح',
  'ﰛ' => 'خم',
  'ﰜ' => 'سج',
  'ﰝ' => 'سح',
  'ﰞ' => 'سخ',
  'ﰟ' => 'سم',
  'ﰠ' => 'صح',
  'ﰡ' => 'صم',
  'ﰢ' => 'ضج',
  'ﰣ' => 'ضح',
  'ﰤ' => 'ضخ',
  'ﰥ' => 'ضم',
  'ﰦ' => 'طح',
  'ﰧ' => 'طم',
  'ﰨ' => 'ظم',
  'ﰩ' => 'عج',
  'ﰪ' => 'عم',
  'ﰫ' => 'غج',
  'ﰬ' => 'غم',
  'ﰭ' => 'فج',
  'ﰮ' => 'فح',
  'ﰯ' => 'فخ',
  'ﰰ' => 'فم',
  'ﰱ' => 'فى',
  'ﰲ' => 'في',
  'ﰳ' => 'قح',
  'ﰴ' => 'قم',
  'ﰵ' => 'قى',
  'ﰶ' => 'قي',
  'ﰷ' => 'كا',
  'ﰸ' => 'كج',
  'ﰹ' => 'كح',
  'ﰺ' => 'كخ',
  'ﰻ' => 'كل',
  'ﰼ' => 'كم',
  'ﰽ' => 'كى',
  'ﰾ' => 'كي',
  'ﰿ' => 'لج',
  'ﱀ' => 'لح',
  'ﱁ' => 'لخ',
  'ﱂ' => 'لم',
  'ﱃ' => 'لى',
  'ﱄ' => 'لي',
  'ﱅ' => 'مج',
  'ﱆ' => 'مح',
  'ﱇ' => 'مخ',
  'ﱈ' => 'مم',
  'ﱉ' => 'مى',
  'ﱊ' => 'مي',
  'ﱋ' => 'نج',
  'ﱌ' => 'نح',
  'ﱍ' => 'نخ',
  'ﱎ' => 'نم',
  'ﱏ' => 'نى',
  'ﱐ' => 'ني',
  'ﱑ' => 'هج',
  'ﱒ' => 'هم',
  'ﱓ' => 'هى',
  'ﱔ' => 'هي',
  'ﱕ' => 'يج',
  'ﱖ' => 'يح',
  'ﱗ' => 'يخ',
  'ﱘ' => 'يم',
  'ﱙ' => 'يى',
  'ﱚ' => 'يي',
  'ﱛ' => 'ذٰ',
  'ﱜ' => 'رٰ',
  'ﱝ' => 'ىٰ',
  'ﱞ' => ' ٌّ',
  'ﱟ' => ' ٍّ',
  'ﱠ' => ' َّ',
  'ﱡ' => ' ُّ',
  'ﱢ' => ' ِّ',
  'ﱣ' => ' ّٰ',
  'ﱤ' => 'ئر',
  'ﱥ' => 'ئز',
  'ﱦ' => 'ئم',
  'ﱧ' => 'ئن',
  'ﱨ' => 'ئى',
  'ﱩ' => 'ئي',
  'ﱪ' => 'بر',
  'ﱫ' => 'بز',
  'ﱬ' => 'بم',
  'ﱭ' => 'بن',
  'ﱮ' => 'بى',
  'ﱯ' => 'بي',
  'ﱰ' => 'تر',
  'ﱱ' => 'تز',
  'ﱲ' => 'تم',
  'ﱳ' => 'تن',
  'ﱴ' => 'تى',
  'ﱵ' => 'تي',
  'ﱶ' => 'ثر',
  'ﱷ' => 'ثز',
  'ﱸ' => 'ثم',
  'ﱹ' => 'ثن',
  'ﱺ' => 'ثى',
  'ﱻ' => 'ثي',
  'ﱼ' => 'فى',
  'ﱽ' => 'في',
  'ﱾ' => 'قى',
  'ﱿ' => 'قي',
  'ﲀ' => 'كا',
  'ﲁ' => 'كل',
  'ﲂ' => 'كم',
  'ﲃ' => 'كى',
  'ﲄ' => 'كي',
  'ﲅ' => 'لم',
  'ﲆ' => 'لى',
  'ﲇ' => 'لي',
  'ﲈ' => 'ما',
  'ﲉ' => 'مم',
  'ﲊ' => 'نر',
  'ﲋ' => 'نز',
  'ﲌ' => 'نم',
  'ﲍ' => 'نن',
  'ﲎ' => 'نى',
  'ﲏ' => 'ني',
  'ﲐ' => 'ىٰ',
  'ﲑ' => 'ير',
  'ﲒ' => 'يز',
  'ﲓ' => 'يم',
  'ﲔ' => 'ين',
  'ﲕ' => 'يى',
  'ﲖ' => 'يي',
  'ﲗ' => 'ئج',
  'ﲘ' => 'ئح',
  'ﲙ' => 'ئخ',
  'ﲚ' => 'ئم',
  'ﲛ' => 'ئه',
  'ﲜ' => 'بج',
  'ﲝ' => 'بح',
  'ﲞ' => 'بخ',
  'ﲟ' => 'بم',
  'ﲠ' => 'به',
  'ﲡ' => 'تج',
  'ﲢ' => 'تح',
  'ﲣ' => 'تخ',
  'ﲤ' => 'تم',
  'ﲥ' => 'ته',
  'ﲦ' => 'ثم',
  'ﲧ' => 'جح',
  'ﲨ' => 'جم',
  'ﲩ' => 'حج',
  'ﲪ' => 'حم',
  'ﲫ' => 'خج',
  'ﲬ' => 'خم',
  'ﲭ' => 'سج',
  'ﲮ' => 'سح',
  'ﲯ' => 'سخ',
  'ﲰ' => 'سم',
  'ﲱ' => 'صح',
  'ﲲ' => 'صخ',
  'ﲳ' => 'صم',
  'ﲴ' => 'ضج',
  'ﲵ' => 'ضح',
  'ﲶ' => 'ضخ',
  'ﲷ' => 'ضم',
  'ﲸ' => 'طح',
  'ﲹ' => 'ظم',
  'ﲺ' => 'عج',
  'ﲻ' => 'عم',
  'ﲼ' => 'غج',
  'ﲽ' => 'غم',
  'ﲾ' => 'فج',
  'ﲿ' => 'فح',
  'ﳀ' => 'فخ',
  'ﳁ' => 'فم',
  'ﳂ' => 'قح',
  'ﳃ' => 'قم',
  'ﳄ' => 'كج',
  'ﳅ' => 'كح',
  'ﳆ' => 'كخ',
  'ﳇ' => 'كل',
  'ﳈ' => 'كم',
  'ﳉ' => 'لج',
  'ﳊ' => 'لح',
  'ﳋ' => 'لخ',
  'ﳌ' => 'لم',
  'ﳍ' => 'له',
  'ﳎ' => 'مج',
  'ﳏ' => 'مح',
  'ﳐ' => 'مخ',
  'ﳑ' => 'مم',
  'ﳒ' => 'نج',
  'ﳓ' => 'نح',
  'ﳔ' => 'نخ',
  'ﳕ' => 'نم',
  'ﳖ' => 'نه',
  'ﳗ' => 'هج',
  'ﳘ' => 'هم',
  'ﳙ' => 'هٰ',
  'ﳚ' => 'يج',
  'ﳛ' => 'يح',
  'ﳜ' => 'يخ',
  'ﳝ' => 'يم',
  'ﳞ' => 'يه',
  'ﳟ' => 'ئم',
  'ﳠ' => 'ئه',
  'ﳡ' => 'بم',
  'ﳢ' => 'به',
  'ﳣ' => 'تم',
  'ﳤ' => 'ته',
  'ﳥ' => 'ثم',
  'ﳦ' => 'ثه',
  'ﳧ' => 'سم',
  'ﳨ' => 'سه',
  'ﳩ' => 'شم',
  'ﳪ' => 'شه',
  'ﳫ' => 'كل',
  'ﳬ' => 'كم',
  'ﳭ' => 'لم',
  'ﳮ' => 'نم',
  'ﳯ' => 'نه',
  'ﳰ' => 'يم',
  'ﳱ' => 'يه',
  'ﳲ' => 'ـَّ',
  'ﳳ' => 'ـُّ',
  'ﳴ' => 'ـِّ',
  'ﳵ' => 'طى',
  'ﳶ' => 'طي',
  'ﳷ' => 'عى',
  'ﳸ' => 'عي',
  'ﳹ' => 'غى',
  'ﳺ' => 'غي',
  'ﳻ' => 'سى',
  'ﳼ' => 'سي',
  'ﳽ' => 'شى',
  'ﳾ' => 'شي',
  'ﳿ' => 'حى',
  'ﴀ' => 'حي',
  'ﴁ' => 'جى',
  'ﴂ' => 'جي',
  'ﴃ' => 'خى',
  'ﴄ' => 'خي',
  'ﴅ' => 'صى',
  'ﴆ' => 'صي',
  'ﴇ' => 'ضى',
  'ﴈ' => 'ضي',
  'ﴉ' => 'شج',
  'ﴊ' => 'شح',
  'ﴋ' => 'شخ',
  'ﴌ' => 'شم',
  'ﴍ' => 'شر',
  'ﴎ' => 'سر',
  'ﴏ' => 'صر',
  'ﴐ' => 'ضر',
  'ﴑ' => 'طى',
  'ﴒ' => 'طي',
  'ﴓ' => 'عى',
  'ﴔ' => 'عي',
  'ﴕ' => 'غى',
  'ﴖ' => 'غي',
  'ﴗ' => 'سى',
  'ﴘ' => 'سي',
  'ﴙ' => 'شى',
  'ﴚ' => 'شي',
  'ﴛ' => 'حى',
  'ﴜ' => 'حي',
  'ﴝ' => 'جى',
  'ﴞ' => 'جي',
  'ﴟ' => 'خى',
  'ﴠ' => 'خي',
  'ﴡ' => 'صى',
  'ﴢ' => 'صي',
  'ﴣ' => 'ضى',
  'ﴤ' => 'ضي',
  'ﴥ' => 'شج',
  'ﴦ' => 'شح',
  'ﴧ' => 'شخ',
  'ﴨ' => 'شم',
  'ﴩ' => 'شر',
  'ﴪ' => 'سر',
  'ﴫ' => 'صر',
  'ﴬ' => 'ضر',
  'ﴭ' => 'شج',
  'ﴮ' => 'شح',
  'ﴯ' => 'شخ',
  'ﴰ' => 'شم',
  'ﴱ' => 'سه',
  'ﴲ' => 'شه',
  'ﴳ' => 'طم',
  'ﴴ' => 'سج',
  'ﴵ' => 'سح',
  'ﴶ' => 'سخ',
  'ﴷ' => 'شج',
  'ﴸ' => 'شح',
  'ﴹ' => 'شخ',
  'ﴺ' => 'طم',
  'ﴻ' => 'ظم',
  'ﴼ' => 'اً',
  'ﴽ' => 'اً',
  'ﵐ' => 'تجم',
  'ﵑ' => 'تحج',
  'ﵒ' => 'تحج',
  'ﵓ' => 'تحم',
  'ﵔ' => 'تخم',
  'ﵕ' => 'تمج',
  'ﵖ' => 'تمح',
  'ﵗ' => 'تمخ',
  'ﵘ' => 'جمح',
  'ﵙ' => 'جمح',
  'ﵚ' => 'حمي',
  'ﵛ' => 'حمى',
  'ﵜ' => 'سحج',
  'ﵝ' => 'سجح',
  'ﵞ' => 'سجى',
  'ﵟ' => 'سمح',
  'ﵠ' => 'سمح',
  'ﵡ' => 'سمج',
  'ﵢ' => 'سمم',
  'ﵣ' => 'سمم',
  'ﵤ' => 'صحح',
  'ﵥ' => 'صحح',
  'ﵦ' => 'صمم',
  'ﵧ' => 'شحم',
  'ﵨ' => 'شحم',
  'ﵩ' => 'شجي',
  'ﵪ' => 'شمخ',
  'ﵫ' => 'شمخ',
  'ﵬ' => 'شمم',
  'ﵭ' => 'شمم',
  'ﵮ' => 'ضحى',
  'ﵯ' => 'ضخم',
  'ﵰ' => 'ضخم',
  'ﵱ' => 'طمح',
  'ﵲ' => 'طمح',
  'ﵳ' => 'طمم',
  'ﵴ' => 'طمي',
  'ﵵ' => 'عجم',
  'ﵶ' => 'عمم',
  'ﵷ' => 'عمم',
  'ﵸ' => 'عمى',
  'ﵹ' => 'غمم',
  'ﵺ' => 'غمي',
  'ﵻ' => 'غمى',
  'ﵼ' => 'فخم',
  'ﵽ' => 'فخم',
  'ﵾ' => 'قمح',
  'ﵿ' => 'قمم',
  'ﶀ' => 'لحم',
  'ﶁ' => 'لحي',
  'ﶂ' => 'لحى',
  'ﶃ' => 'لجج',
  'ﶄ' => 'لجج',
  'ﶅ' => 'لخم',
  'ﶆ' => 'لخم',
  'ﶇ' => 'لمح',
  'ﶈ' => 'لمح',
  'ﶉ' => 'محج',
  'ﶊ' => 'محم',
  'ﶋ' => 'محي',
  'ﶌ' => 'مجح',
  'ﶍ' => 'مجم',
  'ﶎ' => 'مخج',
  'ﶏ' => 'مخم',
  'ﶒ' => 'مجخ',
  'ﶓ' => 'همج',
  'ﶔ' => 'همم',
  'ﶕ' => 'نحم',
  'ﶖ' => 'نحى',
  'ﶗ' => 'نجم',
  'ﶘ' => 'نجم',
  'ﶙ' => 'نجى',
  'ﶚ' => 'نمي',
  'ﶛ' => 'نمى',
  'ﶜ' => 'يمم',
  'ﶝ' => 'يمم',
  'ﶞ' => 'بخي',
  'ﶟ' => 'تجي',
  'ﶠ' => 'تجى',
  'ﶡ' => 'تخي',
  'ﶢ' => 'تخى',
  'ﶣ' => 'تمي',
  'ﶤ' => 'تمى',
  'ﶥ' => 'جمي',
  'ﶦ' => 'جحى',
  'ﶧ' => 'جمى',
  'ﶨ' => 'سخى',
  'ﶩ' => 'صحي',
  'ﶪ' => 'شحي',
  'ﶫ' => 'ضحي',
  'ﶬ' => 'لجي',
  'ﶭ' => 'لمي',
  'ﶮ' => 'يحي',
  'ﶯ' => 'يجي',
  'ﶰ' => 'يمي',
  'ﶱ' => 'ممي',
  'ﶲ' => 'قمي',
  'ﶳ' => 'نحي',
  'ﶴ' => 'قمح',
  'ﶵ' => 'لحم',
  'ﶶ' => 'عمي',
  'ﶷ' => 'كمي',
  'ﶸ' => 'نجح',
  'ﶹ' => 'مخي',
  'ﶺ' => 'لجم',
  'ﶻ' => 'كمم',
  'ﶼ' => 'لجم',
  'ﶽ' => 'نجح',
  'ﶾ' => 'جحي',
  'ﶿ' => 'حجي',
  'ﷀ' => 'مجي',
  'ﷁ' => 'فمي',
  'ﷂ' => 'بحي',
  'ﷃ' => 'كمم',
  'ﷄ' => 'عجم',
  'ﷅ' => 'صمم',
  'ﷆ' => 'سخي',
  'ﷇ' => 'نجي',
  'ﷰ' => 'صلے',
  'ﷱ' => 'قلے',
  'ﷲ' => 'الله',
  'ﷳ' => 'اكبر',
  'ﷴ' => 'محمد',
  'ﷵ' => 'صلعم',
  'ﷶ' => 'رسول',
  'ﷷ' => 'عليه',
  'ﷸ' => 'وسلم',
  'ﷹ' => 'صلى',
  'ﷺ' => 'صلى الله عليه وسلم',
  'ﷻ' => 'جل جلاله',
  '﷼' => 'ریال',
  '︐' => ',',
  '︑' => '、',
  '︒' => '。',
  '︓' => ':',
  '︔' => ';',
  '︕' => '!',
  '︖' => '?',
  '︗' => '〖',
  '︘' => '〗',
  '︙' => '...',
  '︰' => '..',
  '︱' => '—',
  '︲' => '–',
  '︳' => '_',
  '︴' => '_',
  '︵' => '(',
  '︶' => ')',
  '︷' => '{',
  '︸' => '}',
  '︹' => '〔',
  '︺' => '〕',
  '︻' => '【',
  '︼' => '】',
  '︽' => '《',
  '︾' => '》',
  '︿' => '〈',
  '﹀' => '〉',
  '﹁' => '「',
  '﹂' => '」',
  '﹃' => '『',
  '﹄' => '』',
  '﹇' => '[',
  '﹈' => ']',
  '﹉' => ' ̅',
  '﹊' => ' ̅',
  '﹋' => ' ̅',
  '﹌' => ' ̅',
  '﹍' => '_',
  '﹎' => '_',
  '﹏' => '_',
  '﹐' => ',',
  '﹑' => '、',
  '﹒' => '.',
  '﹔' => ';',
  '﹕' => ':',
  '﹖' => '?',
  '﹗' => '!',
  '﹘' => '—',
  '﹙' => '(',
  '﹚' => ')',
  '﹛' => '{',
  '﹜' => '}',
  '﹝' => '〔',
  '﹞' => '〕',
  '﹟' => '#',
  '﹠' => '&',
  '﹡' => '*',
  '﹢' => '+',
  '﹣' => '-',
  '﹤' => '<',
  '﹥' => '>',
  '﹦' => '=',
  '﹨' => '\\',
  '﹩' => '$',
  '﹪' => '%',
  '﹫' => '@',
  'ﹰ' => ' ً',
  'ﹱ' => 'ـً',
  'ﹲ' => ' ٌ',
  'ﹴ' => ' ٍ',
  'ﹶ' => ' َ',
  'ﹷ' => 'ـَ',
  'ﹸ' => ' ُ',
  'ﹹ' => 'ـُ',
  'ﹺ' => ' ِ',
  'ﹻ' => 'ـِ',
  'ﹼ' => ' ّ',
  'ﹽ' => 'ـّ',
  'ﹾ' => ' ْ',
  'ﹿ' => 'ـْ',
  'ﺀ' => 'ء',
  'ﺁ' => 'آ',
  'ﺂ' => 'آ',
  'ﺃ' => 'أ',
  'ﺄ' => 'أ',
  'ﺅ' => 'ؤ',
  'ﺆ' => 'ؤ',
  'ﺇ' => 'إ',
  'ﺈ' => 'إ',
  'ﺉ' => 'ئ',
  'ﺊ' => 'ئ',
  'ﺋ' => 'ئ',
  'ﺌ' => 'ئ',
  'ﺍ' => 'ا',
  'ﺎ' => 'ا',
  'ﺏ' => 'ب',
  'ﺐ' => 'ب',
  'ﺑ' => 'ب',
  'ﺒ' => 'ب',
  'ﺓ' => 'ة',
  'ﺔ' => 'ة',
  'ﺕ' => 'ت',
  'ﺖ' => 'ت',
  'ﺗ' => 'ت',
  'ﺘ' => 'ت',
  'ﺙ' => 'ث',
  'ﺚ' => 'ث',
  'ﺛ' => 'ث',
  'ﺜ' => 'ث',
  'ﺝ' => 'ج',
  'ﺞ' => 'ج',
  'ﺟ' => 'ج',
  'ﺠ' => 'ج',
  'ﺡ' => 'ح',
  'ﺢ' => 'ح',
  'ﺣ' => 'ح',
  'ﺤ' => 'ح',
  'ﺥ' => 'خ',
  'ﺦ' => 'خ',
  'ﺧ' => 'خ',
  'ﺨ' => 'خ',
  'ﺩ' => 'د',
  'ﺪ' => 'د',
  'ﺫ' => 'ذ',
  'ﺬ' => 'ذ',
  'ﺭ' => 'ر',
  'ﺮ' => 'ر',
  'ﺯ' => 'ز',
  'ﺰ' => 'ز',
  'ﺱ' => 'س',
  'ﺲ' => 'س',
  'ﺳ' => 'س',
  'ﺴ' => 'س',
  'ﺵ' => 'ش',
  'ﺶ' => 'ش',
  'ﺷ' => 'ش',
  'ﺸ' => 'ش',
  'ﺹ' => 'ص',
  'ﺺ' => 'ص',
  'ﺻ' => 'ص',
  'ﺼ' => 'ص',
  'ﺽ' => 'ض',
  'ﺾ' => 'ض',
  'ﺿ' => 'ض',
  'ﻀ' => 'ض',
  'ﻁ' => 'ط',
  'ﻂ' => 'ط',
  'ﻃ' => 'ط',
  'ﻄ' => 'ط',
  'ﻅ' => 'ظ',
  'ﻆ' => 'ظ',
  'ﻇ' => 'ظ',
  'ﻈ' => 'ظ',
  'ﻉ' => 'ع',
  'ﻊ' => 'ع',
  'ﻋ' => 'ع',
  'ﻌ' => 'ع',
  'ﻍ' => 'غ',
  'ﻎ' => 'غ',
  'ﻏ' => 'غ',
  'ﻐ' => 'غ',
  'ﻑ' => 'ف',
  'ﻒ' => 'ف',
  'ﻓ' => 'ف',
  'ﻔ' => 'ف',
  'ﻕ' => 'ق',
  'ﻖ' => 'ق',
  'ﻗ' => 'ق',
  'ﻘ' => 'ق',
  'ﻙ' => 'ك',
  'ﻚ' => 'ك',
  'ﻛ' => 'ك',
  'ﻜ' => 'ك',
  'ﻝ' => 'ل',
  'ﻞ' => 'ل',
  'ﻟ' => 'ل',
  'ﻠ' => 'ل',
  'ﻡ' => 'م',
  'ﻢ' => 'م',
  'ﻣ' => 'م',
  'ﻤ' => 'م',
  'ﻥ' => 'ن',
  'ﻦ' => 'ن',
  'ﻧ' => 'ن',
  'ﻨ' => 'ن',
  'ﻩ' => 'ه',
  'ﻪ' => 'ه',
  'ﻫ' => 'ه',
  'ﻬ' => 'ه',
  'ﻭ' => 'و',
  'ﻮ' => 'و',
  'ﻯ' => 'ى',
  'ﻰ' => 'ى',
  'ﻱ' => 'ي',
  'ﻲ' => 'ي',
  'ﻳ' => 'ي',
  'ﻴ' => 'ي',
  'ﻵ' => 'لآ',
  'ﻶ' => 'لآ',
  'ﻷ' => 'لأ',
  'ﻸ' => 'لأ',
  'ﻹ' => 'لإ',
  'ﻺ' => 'لإ',
  'ﻻ' => 'لا',
  'ﻼ' => 'لا',
  '！' => '!',
  '＂' => '"',
  '＃' => '#',
  '＄' => '$',
  '％' => '%',
  '＆' => '&',
  '＇' => '\'',
  '（' => '(',
  '）' => ')',
  '＊' => '*',
  '＋' => '+',
  '，' => ',',
  '－' => '-',
  '．' => '.',
  '／' => '/',
  '０' => '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',
  '［' => '[',
  '＼' => '\\',
  '］' => ']',
  '＾' => '^',
  '＿' => '_',
  '｀' => '`',
  'ａ' => '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',
  '𝑖' => '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',
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Mbstring as p;

if (\PHP_VERSION_ID >= 80000) {
    return require __DIR__.'/bootstrap80.php';
}

if (!function_exists('mb_convert_encoding')) {
    function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
    function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
}
if (!function_exists('mb_encode_mimeheader')) {
    function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
    function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
    function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
}
if (!function_exists('mb_convert_case')) {
    function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
    function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
    function mb_language($language = null) { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
    function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
    function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
}
if (!function_exists('mb_check_encoding')) {
    function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
    function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
}
if (!function_exists('mb_detect_order')) {
    function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
    function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
    function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
}
if (!function_exists('mb_strpos')) {
    function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
    function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
    function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
    function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
    function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
    function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
    function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
    function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
    function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
    function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
    function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
    function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
    function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
}
if (!function_exists('mb_http_output')) {
    function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
    function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
    function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
    function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
}
if (!function_exists('mb_http_input')) {
    function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
}

if (!function_exists('mb_convert_variables')) {
    function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
}

if (!function_exists('mb_ord')) {
    function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
    function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
    function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
    function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}

if (!function_exists('mb_str_pad')) {
    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}

if (!function_exists('mb_ucfirst')) {
    function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
}

if (!function_exists('mb_lcfirst')) {
    function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
}

if (!function_exists('mb_trim')) {
    function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
}

if (!function_exists('mb_ltrim')) {
    function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
}

if (!function_exists('mb_rtrim')) {
    function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
}


if (extension_loaded('mbstring')) {
    return;
}

if (!defined('MB_CASE_UPPER')) {
    define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
    define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
    define('MB_CASE_TITLE', 2);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Symfony\Polyfill\Mbstring as p;

if (!function_exists('mb_convert_encoding')) {
    function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
    function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
}
if (!function_exists('mb_encode_mimeheader')) {
    function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
    function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
    function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
}
if (!function_exists('mb_convert_case')) {
    function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
    function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
    function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
    function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
    function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
}
if (!function_exists('mb_check_encoding')) {
    function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
    function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
}
if (!function_exists('mb_detect_order')) {
    function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
    function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
    function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
}
if (!function_exists('mb_strpos')) {
    function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
    function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
    function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
    function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
    function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
    function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
    function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
    function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
    function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
    function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
    function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
    function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
    function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); }
}
if (!function_exists('mb_http_output')) {
    function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
    function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
    function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
    function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
}
if (!function_exists('mb_http_input')) {
    function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
}

if (!function_exists('mb_convert_variables')) {
    function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
}

if (!function_exists('mb_ord')) {
    function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
}
if (!function_exists('mb_chr')) {
    function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
    function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
    function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}

if (!function_exists('mb_str_pad')) {
    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}

if (!function_exists('mb_ucfirst')) {
    function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
}

if (!function_exists('mb_lcfirst')) {
    function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
}

if (!function_exists('mb_trim')) {
    function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
}

if (!function_exists('mb_ltrim')) {
    function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
}

if (!function_exists('mb_rtrim')) {
    function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
}

if (extension_loaded('mbstring')) {
    return;
}

if (!defined('MB_CASE_UPPER')) {
    define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
    define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
    define('MB_CASE_TITLE', 2);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Mbstring;

/**
 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
 *
 * Implemented:
 * - mb_chr                  - Returns a specific character from its Unicode code point
 * - mb_convert_encoding     - Convert character encoding
 * - mb_convert_variables    - Convert character code in variable(s)
 * - mb_decode_mimeheader    - Decode string in MIME header field
 * - mb_encode_mimeheader    - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
 * - mb_decode_numericentity - Decode HTML numeric string reference to character
 * - mb_encode_numericentity - Encode character to HTML numeric string reference
 * - mb_convert_case         - Perform case folding on a string
 * - mb_detect_encoding      - Detect character encoding
 * - mb_get_info             - Get internal settings of mbstring
 * - mb_http_input           - Detect HTTP input character encoding
 * - mb_http_output          - Set/Get HTTP output character encoding
 * - mb_internal_encoding    - Set/Get internal character encoding
 * - mb_list_encodings       - Returns an array of all supported encodings
 * - mb_ord                  - Returns the Unicode code point of a character
 * - mb_output_handler       - Callback function converts character encoding in output buffer
 * - mb_scrub                - Replaces ill-formed byte sequences with substitute characters
 * - mb_strlen               - Get string length
 * - mb_strpos               - Find position of first occurrence of string in a string
 * - mb_strrpos              - Find position of last occurrence of a string in a string
 * - mb_str_split            - Convert a string to an array
 * - mb_strtolower           - Make a string lowercase
 * - mb_strtoupper           - Make a string uppercase
 * - mb_substitute_character - Set/Get substitution character
 * - mb_substr               - Get part of string
 * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive
 * - mb_stristr              - Finds first occurrence of a string within another, case insensitive
 * - mb_strrchr              - Finds the last occurrence of a character in a string within another
 * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive
 * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive
 * - mb_strstr               - Finds first occurrence of a string within another
 * - mb_strwidth             - Return width of string
 * - mb_substr_count         - Count the number of substring occurrences
 * - mb_ucfirst              - Make a string's first character uppercase
 * - mb_lcfirst              - Make a string's first character lowercase
 * - mb_trim                 - Strip whitespace (or other characters) from the beginning and end of a string
 * - mb_ltrim                - Strip whitespace (or other characters) from the beginning of a string
 * - mb_rtrim                - Strip whitespace (or other characters) from the end of a string
 *
 * Not implemented:
 * - mb_convert_kana         - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
 * - mb_ereg_*               - Regular expression with multibyte support
 * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable
 * - mb_preferred_mime_name  - Get MIME charset string
 * - mb_regex_encoding       - Returns current encoding for multibyte regex as string
 * - mb_regex_set_options    - Set/Get the default options for mbregex functions
 * - mb_send_mail            - Send encoded mail
 * - mb_split                - Split multibyte string using regular expression
 * - mb_strcut               - Get part of string
 * - mb_strimwidth           - Get truncated string with specified width
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
final class Mbstring
{
    public const MB_CASE_FOLD = \PHP_INT_MAX;

    private const SIMPLE_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", 'ι'],
    ];

    private static $encodingList = ['ASCII', 'UTF-8'];
    private static $language = 'neutral';
    private static $internalEncoding = 'UTF-8';

    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
    {
        if (\is_array($s)) {
            $r = [];
            foreach ($s as $str) {
                $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);
            }

            return $r;
        }

        if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
        } else {
            $fromEncoding = self::getEncoding($fromEncoding);
        }

        $toEncoding = self::getEncoding($toEncoding);

        if ('BASE64' === $fromEncoding) {
            $s = base64_decode($s);
            $fromEncoding = $toEncoding;
        }

        if ('BASE64' === $toEncoding) {
            return base64_encode($s);
        }

        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
                $fromEncoding = 'Windows-1252';
            }
            if ('UTF-8' !== $fromEncoding) {
                $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
            }

            return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
        }

        if ('HTML-ENTITIES' === $fromEncoding) {
            $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
            $fromEncoding = 'UTF-8';
        }

        return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
    }

    public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
    {
        $ok = true;
        array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
            if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
                $ok = false;
            }
        });

        return $ok ? $fromEncoding : false;
    }

    public static function mb_decode_mimeheader($s)
    {
        return iconv_mime_decode($s, 2, self::$internalEncoding);
    }

    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
    {
        trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
    }

    public static function mb_decode_numericentity($s, $convmap, $encoding = null)
    {
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
            trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);

            return null;
        }

        if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
            return false;
        }

        if (null !== $encoding && !\is_scalar($encoding)) {
            trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);

            return '';  // Instead of null (cf. mb_encode_numericentity).
        }

        $s = (string) $s;
        if ('' === $s) {
            return '';
        }

        $encoding = self::getEncoding($encoding);

        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!preg_match('//u', $s)) {
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
        }

        $cnt = floor(\count($convmap) / 4) * 4;

        for ($i = 0; $i < $cnt; $i += 4) {
            // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
            $convmap[$i] += $convmap[$i + 2];
            $convmap[$i + 1] += $convmap[$i + 2];
        }

        $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
            $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
            for ($i = 0; $i < $cnt; $i += 4) {
                if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
                    return self::mb_chr($c - $convmap[$i + 2]);
                }
            }

            return $m[0];
        }, $s);

        if (null === $encoding) {
            return $s;
        }

        return iconv('UTF-8', $encoding.'//IGNORE', $s);
    }

    public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
    {
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
            trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);

            return null;
        }

        if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
            return false;
        }

        if (null !== $encoding && !\is_scalar($encoding)) {
            trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);

            return null;  // Instead of '' (cf. mb_decode_numericentity).
        }

        if (null !== $is_hex && !\is_scalar($is_hex)) {
            trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);

            return null;
        }

        $s = (string) $s;
        if ('' === $s) {
            return '';
        }

        $encoding = self::getEncoding($encoding);

        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!preg_match('//u', $s)) {
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
        }

        static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];

        $cnt = floor(\count($convmap) / 4) * 4;
        $i = 0;
        $len = \strlen($s);
        $result = '';

        while ($i < $len) {
            $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
            $uchr = substr($s, $i, $ulen);
            $i += $ulen;
            $c = self::mb_ord($uchr);

            for ($j = 0; $j < $cnt; $j += 4) {
                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
                    $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
                    $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
                    continue 2;
                }
            }
            $result .= $uchr;
        }

        if (null === $encoding) {
            return $result;
        }

        return iconv('UTF-8', $encoding.'//IGNORE', $result);
    }

    public static function mb_convert_case($s, $mode, $encoding = null)
    {
        $s = (string) $s;
        if ('' === $s) {
            return '';
        }

        $encoding = self::getEncoding($encoding);

        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!preg_match('//u', $s)) {
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
        }

        if (\MB_CASE_TITLE == $mode) {
            static $titleRegexp = null;
            if (null === $titleRegexp) {
                $titleRegexp = self::getData('titleCaseRegexp');
            }
            $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
        } else {
            if (\MB_CASE_UPPER == $mode) {
                static $upper = null;
                if (null === $upper) {
                    $upper = self::getData('upperCase');
                }
                $map = $upper;
            } else {
                if (self::MB_CASE_FOLD === $mode) {
                    static $caseFolding = null;
                    if (null === $caseFolding) {
                        $caseFolding = self::getData('caseFolding');
                    }
                    $s = strtr($s, $caseFolding);
                }

                static $lower = null;
                if (null === $lower) {
                    $lower = self::getData('lowerCase');
                }
                $map = $lower;
            }

            static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];

            $i = 0;
            $len = \strlen($s);

            while ($i < $len) {
                $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
                $uchr = substr($s, $i, $ulen);
                $i += $ulen;

                if (isset($map[$uchr])) {
                    $uchr = $map[$uchr];
                    $nlen = \strlen($uchr);

                    if ($nlen == $ulen) {
                        $nlen = $i;
                        do {
                            $s[--$nlen] = $uchr[--$ulen];
                        } while ($ulen);
                    } else {
                        $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
                        $len += $nlen - $ulen;
                        $i += $nlen - $ulen;
                    }
                }
            }
        }

        if (null === $encoding) {
            return $s;
        }

        return iconv('UTF-8', $encoding.'//IGNORE', $s);
    }

    public static function mb_internal_encoding($encoding = null)
    {
        if (null === $encoding) {
            return self::$internalEncoding;
        }

        $normalizedEncoding = self::getEncoding($encoding);

        if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
            self::$internalEncoding = $normalizedEncoding;

            return true;
        }

        if (80000 > \PHP_VERSION_ID) {
            return false;
        }

        throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
    }

    public static function mb_language($lang = null)
    {
        if (null === $lang) {
            return self::$language;
        }

        switch ($normalizedLang = strtolower($lang)) {
            case 'uni':
            case 'neutral':
                self::$language = $normalizedLang;

                return true;
        }

        if (80000 > \PHP_VERSION_ID) {
            return false;
        }

        throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
    }

    public static function mb_list_encodings()
    {
        return ['UTF-8'];
    }

    public static function mb_encoding_aliases($encoding)
    {
        switch (strtoupper($encoding)) {
            case 'UTF8':
            case 'UTF-8':
                return ['utf8'];
        }

        return false;
    }

    public static function mb_check_encoding($var = null, $encoding = null)
    {
        if (null === $encoding) {
            if (null === $var) {
                return false;
            }
            $encoding = self::$internalEncoding;
        }

        if (!\is_array($var)) {
            return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
        }

        foreach ($var as $key => $value) {
            if (!self::mb_check_encoding($key, $encoding)) {
                return false;
            }
            if (!self::mb_check_encoding($value, $encoding)) {
                return false;
            }
        }

        return true;
    }

    public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
    {
        if (null === $encodingList) {
            $encodingList = self::$encodingList;
        } else {
            if (!\is_array($encodingList)) {
                $encodingList = array_map('trim', explode(',', $encodingList));
            }
            $encodingList = array_map('strtoupper', $encodingList);
        }

        foreach ($encodingList as $enc) {
            switch ($enc) {
                case 'ASCII':
                    if (!preg_match('/[\x80-\xFF]/', $str)) {
                        return $enc;
                    }
                    break;

                case 'UTF8':
                case 'UTF-8':
                    if (preg_match('//u', $str)) {
                        return 'UTF-8';
                    }
                    break;

                default:
                    if (0 === strncmp($enc, 'ISO-8859-', 9)) {
                        return $enc;
                    }
            }
        }

        return false;
    }

    public static function mb_detect_order($encodingList = null)
    {
        if (null === $encodingList) {
            return self::$encodingList;
        }

        if (!\is_array($encodingList)) {
            $encodingList = array_map('trim', explode(',', $encodingList));
        }
        $encodingList = array_map('strtoupper', $encodingList);

        foreach ($encodingList as $enc) {
            switch ($enc) {
                default:
                    if (strncmp($enc, 'ISO-8859-', 9)) {
                        return false;
                    }
                    // no break
                case 'ASCII':
                case 'UTF8':
                case 'UTF-8':
            }
        }

        self::$encodingList = $encodingList;

        return true;
    }

    public static function mb_strlen($s, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return \strlen($s);
        }

        return @iconv_strlen($s, $encoding);
    }

    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return strpos($haystack, $needle, $offset);
        }

        $needle = (string) $needle;
        if ('' === $needle) {
            if (80000 > \PHP_VERSION_ID) {
                trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);

                return false;
            }

            return 0;
        }

        return iconv_strpos($haystack, $needle, $offset, $encoding);
    }

    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return strrpos($haystack, $needle, $offset);
        }

        if ($offset != (int) $offset) {
            $offset = 0;
        } elseif ($offset = (int) $offset) {
            if ($offset < 0) {
                if (0 > $offset += self::mb_strlen($needle)) {
                    $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
                }
                $offset = 0;
            } else {
                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
            }
        }

        $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
            ? iconv_strrpos($haystack, $needle, $encoding)
            : self::mb_strlen($haystack, $encoding);

        return false !== $pos ? $offset + $pos : false;
    }

    public static function mb_str_split($string, $split_length = 1, $encoding = null)
    {
        if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
            trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);

            return null;
        }

        if (1 > $split_length = (int) $split_length) {
            if (80000 > \PHP_VERSION_ID) {
                trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);

                return false;
            }

            throw new \ValueError('Argument #2 ($length) must be greater than 0');
        }

        if (null === $encoding) {
            $encoding = mb_internal_encoding();
        }

        if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
            $rx = '/(';
            while (65535 < $split_length) {
                $rx .= '.{65535}';
                $split_length -= 65535;
            }
            $rx .= '.{'.$split_length.'})/us';

            return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
        }

        $result = [];
        $length = mb_strlen($string, $encoding);

        for ($i = 0; $i < $length; $i += $split_length) {
            $result[] = mb_substr($string, $i, $split_length, $encoding);
        }

        return $result;
    }

    public static function mb_strtolower($s, $encoding = null)
    {
        return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
    }

    public static function mb_strtoupper($s, $encoding = null)
    {
        return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
    }

    public static function mb_substitute_character($c = null)
    {
        if (null === $c) {
            return 'none';
        }
        if (0 === strcasecmp($c, 'none')) {
            return true;
        }
        if (80000 > \PHP_VERSION_ID) {
            return false;
        }
        if (\is_int($c) || 'long' === $c || 'entity' === $c) {
            return false;
        }

        throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
    }

    public static function mb_substr($s, $start, $length = null, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return (string) substr($s, $start, null === $length ? 2147483647 : $length);
        }

        if ($start < 0) {
            $start = iconv_strlen($s, $encoding) + $start;
            if ($start < 0) {
                $start = 0;
            }
        }

        if (null === $length) {
            $length = 2147483647;
        } elseif ($length < 0) {
            $length = iconv_strlen($s, $encoding) + $length - $start;
            if ($length < 0) {
                return '';
            }
        }

        return (string) iconv_substr($s, $start, $length, $encoding);
    }

    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
            self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
            self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
        ]);

        return self::mb_strpos($haystack, $needle, $offset, $encoding);
    }

    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
    {
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);

        return self::getSubpart($pos, $part, $haystack, $encoding);
    }

    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            $pos = strrpos($haystack, $needle);
        } else {
            $needle = self::mb_substr($needle, 0, 1, $encoding);
            $pos = iconv_strrpos($haystack, $needle, $encoding);
        }

        return self::getSubpart($pos, $part, $haystack, $encoding);
    }

    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
    {
        $needle = self::mb_substr($needle, 0, 1, $encoding);
        $pos = self::mb_strripos($haystack, $needle, $encoding);

        return self::getSubpart($pos, $part, $haystack, $encoding);
    }

    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
        $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);

        $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
        $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);

        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
    }

    public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
    {
        $pos = strpos($haystack, $needle);
        if (false === $pos) {
            return false;
        }
        if ($part) {
            return substr($haystack, 0, $pos);
        }

        return substr($haystack, $pos);
    }

    public static function mb_get_info($type = 'all')
    {
        $info = [
            'internal_encoding' => self::$internalEncoding,
            'http_output' => 'pass',
            'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
            'func_overload' => 0,
            'func_overload_list' => 'no overload',
            'mail_charset' => 'UTF-8',
            'mail_header_encoding' => 'BASE64',
            'mail_body_encoding' => 'BASE64',
            'illegal_chars' => 0,
            'encoding_translation' => 'Off',
            'language' => self::$language,
            'detect_order' => self::$encodingList,
            'substitute_character' => 'none',
            'strict_detection' => 'Off',
        ];

        if ('all' === $type) {
            return $info;
        }
        if (isset($info[$type])) {
            return $info[$type];
        }

        return false;
    }

    public static function mb_http_input($type = '')
    {
        return false;
    }

    public static function mb_http_output($encoding = null)
    {
        return null !== $encoding ? 'pass' === $encoding : 'pass';
    }

    public static function mb_strwidth($s, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);

        if ('UTF-8' !== $encoding) {
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
        }

        $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);

        return ($wide << 1) + iconv_strlen($s, 'UTF-8');
    }

    public static function mb_substr_count($haystack, $needle, $encoding = null)
    {
        return substr_count($haystack, $needle);
    }

    public static function mb_output_handler($contents, $status)
    {
        return $contents;
    }

    public static function mb_chr($code, $encoding = null)
    {
        if (0x80 > $code %= 0x200000) {
            $s = \chr($code);
        } elseif (0x800 > $code) {
            $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
        } elseif (0x10000 > $code) {
            $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
        } else {
            $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
        }

        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
            $s = mb_convert_encoding($s, $encoding, 'UTF-8');
        }

        return $s;
    }

    public static function mb_ord($s, $encoding = null)
    {
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
            $s = mb_convert_encoding($s, 'UTF-8', $encoding);
        }

        if (1 === \strlen($s)) {
            return \ord($s);
        }

        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
        if (0xF0 <= $code) {
            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
        }
        if (0xE0 <= $code) {
            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
        }
        if (0xC0 <= $code) {
            return (($code - 0xC0) << 6) + $s[2] - 0x80;
        }

        return $code;
    }

    public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
    {
        if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
            throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
        }

        if (null === $encoding) {
            $encoding = self::mb_internal_encoding();
        } else {
            self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given');
        }

        if (self::mb_strlen($pad_string, $encoding) <= 0) {
            throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
        }

        $paddingRequired = $length - self::mb_strlen($string, $encoding);

        if ($paddingRequired < 1) {
            return $string;
        }

        switch ($pad_type) {
            case \STR_PAD_LEFT:
                return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
            case \STR_PAD_RIGHT:
                return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
            default:
                $leftPaddingLength = floor($paddingRequired / 2);
                $rightPaddingLength = $paddingRequired - $leftPaddingLength;

                return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
        }
    }

    public static function mb_ucfirst(string $string, ?string $encoding = null): string
    {
        if (null === $encoding) {
            $encoding = self::mb_internal_encoding();
        } else {
            self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
        }

        $firstChar = mb_substr($string, 0, 1, $encoding);
        $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding);

        return $firstChar.mb_substr($string, 1, null, $encoding);
    }

    public static function mb_lcfirst(string $string, ?string $encoding = null): string
    {
        if (null === $encoding) {
            $encoding = self::mb_internal_encoding();
        } else {
            self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
        }

        $firstChar = mb_substr($string, 0, 1, $encoding);
        $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding);

        return $firstChar.mb_substr($string, 1, null, $encoding);
    }

    private static function getSubpart($pos, $part, $haystack, $encoding)
    {
        if (false === $pos) {
            return false;
        }
        if ($part) {
            return self::mb_substr($haystack, 0, $pos, $encoding);
        }

        return self::mb_substr($haystack, $pos, null, $encoding);
    }

    private static function html_encoding_callback(array $m)
    {
        $i = 1;
        $entities = '';
        $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));

        while (isset($m[$i])) {
            if (0x80 > $m[$i]) {
                $entities .= \chr($m[$i++]);
                continue;
            }
            if (0xF0 <= $m[$i]) {
                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
            } elseif (0xE0 <= $m[$i]) {
                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
            } else {
                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
            }

            $entities .= '&#'.$c.';';
        }

        return $entities;
    }

    private static function title_case(array $s)
    {
        return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
    }

    private static function getData($file)
    {
        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
            return require $file;
        }

        return false;
    }

    private static function getEncoding($encoding)
    {
        if (null === $encoding) {
            return self::$internalEncoding;
        }

        if ('UTF-8' === $encoding) {
            return 'UTF-8';
        }

        $encoding = strtoupper($encoding);

        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
            return 'CP850';
        }

        if ('UTF8' === $encoding) {
            return 'UTF-8';
        }

        return $encoding;
    }

    public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
    {
        return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
    }

    public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
    {
        return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
    }

    public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
    {
        return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
    }

    private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string
    {
        if (null === $encoding) {
            $encoding = self::mb_internal_encoding();
        } else {
            self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given');
        }

        if ('' === $characters) {
            return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding);
        }

        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!preg_match('//u', $string)) {
                $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string);
            }
            if (null !== $characters && !preg_match('//u', $characters)) {
                $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters);
            }
        } else {
            $string = iconv($encoding, 'UTF-8//IGNORE', $string);

            if (null !== $characters) {
                $characters = iconv($encoding, 'UTF-8//IGNORE', $characters);
            }
        }

        if (null === $characters) {
            $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}";
        } else {
            $characters = preg_quote($characters);
        }

        $string = preg_replace(sprintf($regex, $characters), '', $string);

        if (null === $encoding) {
            return $string;
        }

        return iconv('UTF-8', $encoding.'//IGNORE', $string);
    }

    private static function assertEncoding(string $encoding, string $errorFormat): void
    {
        try {
            $validEncoding = @self::mb_check_encoding('', $encoding);
        } catch (\ValueError $e) {
            throw new \ValueError(sprintf($errorFormat, $encoding));
        }

        // BC for PHP 7.3 and lower
        if (!$validEncoding) {
            throw new \ValueError(sprintf($errorFormat, $encoding));
        }
    }
}
<?php

return [
    'İ' => 'i̇',
    'µ' => 'μ',
    'ſ' => 's',
    'ͅ' => 'ι',
    'ς' => 'σ',
    'ϐ' => 'β',
    'ϑ' => 'θ',
    'ϕ' => 'φ',
    'ϖ' => 'π',
    'ϰ' => 'κ',
    'ϱ' => 'ρ',
    'ϵ' => 'ε',
    'ẛ' => 'ṡ',
    'ι' => 'ι',
    'ß' => 'ss',
    'ŉ' => 'ʼn',
    'ǰ' => 'ǰ',
    'ΐ' => 'ΐ',
    'ΰ' => 'ΰ',
    'և' => 'եւ',
    'ẖ' => 'ẖ',
    'ẗ' => 'ẗ',
    'ẘ' => 'ẘ',
    'ẙ' => 'ẙ',
    'ẚ' => 'aʾ',
    'ẞ' => 'ss',
    'ὐ' => 'ὐ',
    'ὒ' => 'ὒ',
    'ὔ' => 'ὔ',
    'ὖ' => 'ὖ',
    'ᾀ' => 'ἀι',
    'ᾁ' => 'ἁι',
    'ᾂ' => 'ἂι',
    'ᾃ' => 'ἃι',
    'ᾄ' => 'ἄι',
    'ᾅ' => 'ἅι',
    'ᾆ' => 'ἆι',
    'ᾇ' => 'ἇι',
    'ᾈ' => 'ἀι',
    'ᾉ' => 'ἁι',
    'ᾊ' => 'ἂι',
    'ᾋ' => 'ἃι',
    'ᾌ' => 'ἄι',
    'ᾍ' => 'ἅι',
    'ᾎ' => 'ἆι',
    'ᾏ' => 'ἇι',
    'ᾐ' => 'ἠι',
    'ᾑ' => 'ἡι',
    'ᾒ' => 'ἢι',
    'ᾓ' => 'ἣι',
    'ᾔ' => 'ἤι',
    'ᾕ' => 'ἥι',
    'ᾖ' => 'ἦι',
    'ᾗ' => 'ἧι',
    'ᾘ' => 'ἠι',
    'ᾙ' => 'ἡι',
    'ᾚ' => 'ἢι',
    'ᾛ' => 'ἣι',
    'ᾜ' => 'ἤι',
    'ᾝ' => 'ἥι',
    'ᾞ' => 'ἦι',
    'ᾟ' => 'ἧι',
    'ᾠ' => 'ὠι',
    'ᾡ' => 'ὡι',
    'ᾢ' => 'ὢι',
    'ᾣ' => 'ὣι',
    'ᾤ' => 'ὤι',
    'ᾥ' => 'ὥι',
    'ᾦ' => 'ὦι',
    'ᾧ' => 'ὧι',
    'ᾨ' => 'ὠι',
    'ᾩ' => 'ὡι',
    'ᾪ' => 'ὢι',
    'ᾫ' => 'ὣι',
    'ᾬ' => 'ὤι',
    'ᾭ' => 'ὥι',
    'ᾮ' => 'ὦι',
    'ᾯ' => 'ὧι',
    'ᾲ' => 'ὰι',
    'ᾳ' => 'αι',
    'ᾴ' => 'άι',
    'ᾶ' => 'ᾶ',
    'ᾷ' => 'ᾶι',
    'ᾼ' => 'αι',
    'ῂ' => 'ὴι',
    'ῃ' => 'ηι',
    'ῄ' => 'ήι',
    'ῆ' => 'ῆ',
    'ῇ' => 'ῆι',
    'ῌ' => 'ηι',
    'ῒ' => 'ῒ',
    'ῖ' => 'ῖ',
    'ῗ' => 'ῗ',
    'ῢ' => 'ῢ',
    'ῤ' => 'ῤ',
    'ῦ' => 'ῦ',
    'ῧ' => 'ῧ',
    'ῲ' => 'ὼι',
    'ῳ' => 'ωι',
    'ῴ' => 'ώι',
    'ῶ' => 'ῶ',
    'ῷ' => 'ῶι',
    'ῼ' => 'ωι',
    'ﬀ' => 'ff',
    'ﬁ' => 'fi',
    'ﬂ' => 'fl',
    'ﬃ' => 'ffi',
    'ﬄ' => 'ffl',
    'ﬅ' => 'st',
    'ﬆ' => 'st',
    'ﬓ' => 'մն',
    'ﬔ' => 'մե',
    'ﬕ' => 'մի',
    'ﬖ' => 'վն',
    'ﬗ' => 'մխ',
];
<?php

return array (
  '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',
  'À' => 'à',
  'Á' => 'á',
  'Â' => 'â',
  'Ã' => 'ã',
  'Ä' => 'ä',
  'Å' => 'å',
  'Æ' => 'æ',
  'Ç' => 'ç',
  'È' => 'è',
  'É' => 'é',
  'Ê' => 'ê',
  'Ë' => 'ë',
  'Ì' => 'ì',
  'Í' => 'í',
  'Î' => 'î',
  'Ï' => 'ï',
  'Ð' => 'ð',
  'Ñ' => 'ñ',
  'Ò' => 'ò',
  'Ó' => 'ó',
  'Ô' => 'ô',
  'Õ' => 'õ',
  'Ö' => 'ö',
  'Ø' => 'ø',
  'Ù' => 'ù',
  'Ú' => 'ú',
  'Û' => 'û',
  'Ü' => 'ü',
  'Ý' => 'ý',
  'Þ' => 'þ',
  'Ā' => 'ā',
  'Ă' => 'ă',
  'Ą' => 'ą',
  'Ć' => 'ć',
  'Ĉ' => 'ĉ',
  'Ċ' => 'ċ',
  'Č' => 'č',
  'Ď' => 'ď',
  'Đ' => 'đ',
  'Ē' => 'ē',
  'Ĕ' => 'ĕ',
  'Ė' => 'ė',
  'Ę' => 'ę',
  'Ě' => 'ě',
  'Ĝ' => 'ĝ',
  'Ğ' => 'ğ',
  'Ġ' => 'ġ',
  'Ģ' => 'ģ',
  'Ĥ' => 'ĥ',
  'Ħ' => 'ħ',
  'Ĩ' => 'ĩ',
  'Ī' => 'ī',
  'Ĭ' => 'ĭ',
  'Į' => 'į',
  'İ' => 'i̇',
  'Ĳ' => 'ĳ',
  'Ĵ' => 'ĵ',
  'Ķ' => 'ķ',
  'Ĺ' => 'ĺ',
  'Ļ' => 'ļ',
  'Ľ' => 'ľ',
  'Ŀ' => 'ŀ',
  'Ł' => 'ł',
  'Ń' => 'ń',
  'Ņ' => 'ņ',
  'Ň' => 'ň',
  'Ŋ' => 'ŋ',
  'Ō' => 'ō',
  'Ŏ' => 'ŏ',
  'Ő' => 'ő',
  'Œ' => 'œ',
  'Ŕ' => 'ŕ',
  'Ŗ' => 'ŗ',
  'Ř' => 'ř',
  'Ś' => 'ś',
  'Ŝ' => 'ŝ',
  'Ş' => 'ş',
  'Š' => 'š',
  'Ţ' => 'ţ',
  'Ť' => 'ť',
  'Ŧ' => 'ŧ',
  'Ũ' => 'ũ',
  'Ū' => 'ū',
  'Ŭ' => 'ŭ',
  'Ů' => 'ů',
  'Ű' => 'ű',
  'Ų' => 'ų',
  'Ŵ' => 'ŵ',
  'Ŷ' => 'ŷ',
  'Ÿ' => 'ÿ',
  'Ź' => 'ź',
  'Ż' => 'ż',
  'Ž' => 'ž',
  'Ɓ' => 'ɓ',
  'Ƃ' => 'ƃ',
  'Ƅ' => 'ƅ',
  'Ɔ' => 'ɔ',
  'Ƈ' => 'ƈ',
  'Ɖ' => 'ɖ',
  'Ɗ' => 'ɗ',
  'Ƌ' => 'ƌ',
  'Ǝ' => 'ǝ',
  'Ə' => 'ə',
  'Ɛ' => 'ɛ',
  'Ƒ' => 'ƒ',
  'Ɠ' => 'ɠ',
  'Ɣ' => 'ɣ',
  'Ɩ' => 'ɩ',
  'Ɨ' => 'ɨ',
  'Ƙ' => 'ƙ',
  'Ɯ' => 'ɯ',
  'Ɲ' => 'ɲ',
  'Ɵ' => 'ɵ',
  'Ơ' => 'ơ',
  'Ƣ' => 'ƣ',
  'Ƥ' => 'ƥ',
  'Ʀ' => 'ʀ',
  'Ƨ' => 'ƨ',
  'Ʃ' => 'ʃ',
  'Ƭ' => 'ƭ',
  'Ʈ' => 'ʈ',
  'Ư' => 'ư',
  'Ʊ' => 'ʊ',
  'Ʋ' => 'ʋ',
  'Ƴ' => 'ƴ',
  'Ƶ' => 'ƶ',
  'Ʒ' => 'ʒ',
  'Ƹ' => 'ƹ',
  'Ƽ' => 'ƽ',
  'Ǆ' => 'ǆ',
  'ǅ' => 'ǆ',
  'Ǉ' => 'ǉ',
  'ǈ' => 'ǉ',
  'Ǌ' => 'ǌ',
  'ǋ' => 'ǌ',
  'Ǎ' => 'ǎ',
  'Ǐ' => 'ǐ',
  'Ǒ' => 'ǒ',
  'Ǔ' => 'ǔ',
  'Ǖ' => 'ǖ',
  'Ǘ' => 'ǘ',
  'Ǚ' => 'ǚ',
  'Ǜ' => 'ǜ',
  'Ǟ' => 'ǟ',
  'Ǡ' => 'ǡ',
  'Ǣ' => 'ǣ',
  'Ǥ' => 'ǥ',
  'Ǧ' => 'ǧ',
  'Ǩ' => 'ǩ',
  'Ǫ' => 'ǫ',
  'Ǭ' => 'ǭ',
  'Ǯ' => 'ǯ',
  'Ǳ' => 'ǳ',
  'ǲ' => 'ǳ',
  'Ǵ' => 'ǵ',
  'Ƕ' => 'ƕ',
  'Ƿ' => 'ƿ',
  'Ǹ' => 'ǹ',
  'Ǻ' => 'ǻ',
  'Ǽ' => 'ǽ',
  'Ǿ' => 'ǿ',
  'Ȁ' => 'ȁ',
  'Ȃ' => 'ȃ',
  'Ȅ' => 'ȅ',
  'Ȇ' => 'ȇ',
  'Ȉ' => 'ȉ',
  'Ȋ' => 'ȋ',
  'Ȍ' => 'ȍ',
  'Ȏ' => 'ȏ',
  'Ȑ' => 'ȑ',
  'Ȓ' => 'ȓ',
  'Ȕ' => 'ȕ',
  'Ȗ' => 'ȗ',
  'Ș' => 'ș',
  'Ț' => 'ț',
  'Ȝ' => 'ȝ',
  'Ȟ' => 'ȟ',
  'Ƞ' => 'ƞ',
  'Ȣ' => 'ȣ',
  'Ȥ' => 'ȥ',
  'Ȧ' => 'ȧ',
  'Ȩ' => 'ȩ',
  'Ȫ' => 'ȫ',
  'Ȭ' => 'ȭ',
  'Ȯ' => 'ȯ',
  'Ȱ' => 'ȱ',
  'Ȳ' => 'ȳ',
  'Ⱥ' => 'ⱥ',
  'Ȼ' => 'ȼ',
  'Ƚ' => 'ƚ',
  'Ⱦ' => 'ⱦ',
  'Ɂ' => 'ɂ',
  'Ƀ' => 'ƀ',
  'Ʉ' => 'ʉ',
  'Ʌ' => 'ʌ',
  'Ɇ' => 'ɇ',
  'Ɉ' => 'ɉ',
  'Ɋ' => 'ɋ',
  'Ɍ' => 'ɍ',
  'Ɏ' => 'ɏ',
  'Ͱ' => 'ͱ',
  'Ͳ' => 'ͳ',
  'Ͷ' => 'ͷ',
  'Ϳ' => 'ϳ',
  'Ά' => 'ά',
  'Έ' => 'έ',
  'Ή' => 'ή',
  'Ί' => 'ί',
  'Ό' => 'ό',
  'Ύ' => 'ύ',
  'Ώ' => 'ώ',
  'Α' => 'α',
  'Β' => 'β',
  'Γ' => 'γ',
  'Δ' => 'δ',
  'Ε' => 'ε',
  'Ζ' => 'ζ',
  'Η' => 'η',
  'Θ' => 'θ',
  'Ι' => 'ι',
  'Κ' => 'κ',
  'Λ' => 'λ',
  'Μ' => 'μ',
  'Ν' => 'ν',
  'Ξ' => 'ξ',
  'Ο' => 'ο',
  'Π' => 'π',
  'Ρ' => 'ρ',
  'Σ' => 'σ',
  'Τ' => 'τ',
  'Υ' => 'υ',
  'Φ' => 'φ',
  'Χ' => 'χ',
  'Ψ' => 'ψ',
  'Ω' => 'ω',
  'Ϊ' => 'ϊ',
  'Ϋ' => 'ϋ',
  'Ϗ' => 'ϗ',
  'Ϙ' => 'ϙ',
  'Ϛ' => 'ϛ',
  'Ϝ' => 'ϝ',
  'Ϟ' => 'ϟ',
  'Ϡ' => 'ϡ',
  'Ϣ' => 'ϣ',
  'Ϥ' => 'ϥ',
  'Ϧ' => 'ϧ',
  'Ϩ' => 'ϩ',
  'Ϫ' => 'ϫ',
  'Ϭ' => 'ϭ',
  'Ϯ' => 'ϯ',
  'ϴ' => 'θ',
  'Ϸ' => 'ϸ',
  'Ϲ' => 'ϲ',
  'Ϻ' => 'ϻ',
  'Ͻ' => 'ͻ',
  'Ͼ' => 'ͼ',
  'Ͽ' => 'ͽ',
  'Ѐ' => 'ѐ',
  'Ё' => 'ё',
  'Ђ' => 'ђ',
  'Ѓ' => 'ѓ',
  'Є' => 'є',
  'Ѕ' => 'ѕ',
  'І' => 'і',
  'Ї' => 'ї',
  'Ј' => 'ј',
  'Љ' => 'љ',
  'Њ' => 'њ',
  'Ћ' => 'ћ',
  'Ќ' => 'ќ',
  'Ѝ' => 'ѝ',
  'Ў' => 'ў',
  'Џ' => 'џ',
  'А' => 'а',
  'Б' => 'б',
  'В' => 'в',
  'Г' => 'г',
  'Д' => 'д',
  'Е' => 'е',
  'Ж' => 'ж',
  'З' => 'з',
  'И' => 'и',
  'Й' => 'й',
  'К' => 'к',
  'Л' => 'л',
  'М' => 'м',
  'Н' => 'н',
  'О' => 'о',
  'П' => 'п',
  'Р' => 'р',
  'С' => 'с',
  'Т' => 'т',
  'У' => 'у',
  'Ф' => 'ф',
  'Х' => 'х',
  'Ц' => 'ц',
  'Ч' => 'ч',
  'Ш' => 'ш',
  'Щ' => 'щ',
  'Ъ' => 'ъ',
  'Ы' => 'ы',
  'Ь' => 'ь',
  'Э' => 'э',
  'Ю' => 'ю',
  'Я' => 'я',
  'Ѡ' => 'ѡ',
  'Ѣ' => 'ѣ',
  'Ѥ' => 'ѥ',
  'Ѧ' => 'ѧ',
  'Ѩ' => 'ѩ',
  'Ѫ' => 'ѫ',
  'Ѭ' => 'ѭ',
  'Ѯ' => 'ѯ',
  'Ѱ' => 'ѱ',
  'Ѳ' => 'ѳ',
  'Ѵ' => 'ѵ',
  'Ѷ' => 'ѷ',
  'Ѹ' => 'ѹ',
  'Ѻ' => 'ѻ',
  'Ѽ' => 'ѽ',
  'Ѿ' => 'ѿ',
  'Ҁ' => 'ҁ',
  'Ҋ' => 'ҋ',
  'Ҍ' => 'ҍ',
  'Ҏ' => 'ҏ',
  'Ґ' => 'ґ',
  'Ғ' => 'ғ',
  'Ҕ' => 'ҕ',
  'Җ' => 'җ',
  'Ҙ' => 'ҙ',
  'Қ' => 'қ',
  'Ҝ' => 'ҝ',
  'Ҟ' => 'ҟ',
  'Ҡ' => 'ҡ',
  'Ң' => 'ң',
  'Ҥ' => 'ҥ',
  'Ҧ' => 'ҧ',
  'Ҩ' => 'ҩ',
  'Ҫ' => 'ҫ',
  'Ҭ' => 'ҭ',
  'Ү' => 'ү',
  'Ұ' => 'ұ',
  'Ҳ' => 'ҳ',
  'Ҵ' => 'ҵ',
  'Ҷ' => 'ҷ',
  'Ҹ' => 'ҹ',
  'Һ' => 'һ',
  'Ҽ' => 'ҽ',
  'Ҿ' => 'ҿ',
  'Ӏ' => 'ӏ',
  'Ӂ' => 'ӂ',
  'Ӄ' => 'ӄ',
  'Ӆ' => 'ӆ',
  'Ӈ' => 'ӈ',
  'Ӊ' => 'ӊ',
  'Ӌ' => 'ӌ',
  'Ӎ' => 'ӎ',
  'Ӑ' => 'ӑ',
  'Ӓ' => 'ӓ',
  'Ӕ' => 'ӕ',
  'Ӗ' => 'ӗ',
  'Ә' => 'ә',
  'Ӛ' => 'ӛ',
  'Ӝ' => 'ӝ',
  'Ӟ' => 'ӟ',
  'Ӡ' => 'ӡ',
  'Ӣ' => 'ӣ',
  'Ӥ' => 'ӥ',
  'Ӧ' => 'ӧ',
  'Ө' => 'ө',
  'Ӫ' => 'ӫ',
  'Ӭ' => 'ӭ',
  'Ӯ' => 'ӯ',
  'Ӱ' => 'ӱ',
  'Ӳ' => 'ӳ',
  'Ӵ' => 'ӵ',
  'Ӷ' => 'ӷ',
  'Ӹ' => 'ӹ',
  'Ӻ' => 'ӻ',
  'Ӽ' => 'ӽ',
  'Ӿ' => 'ӿ',
  'Ԁ' => 'ԁ',
  'Ԃ' => 'ԃ',
  'Ԅ' => 'ԅ',
  'Ԇ' => 'ԇ',
  'Ԉ' => 'ԉ',
  'Ԋ' => 'ԋ',
  'Ԍ' => 'ԍ',
  'Ԏ' => 'ԏ',
  'Ԑ' => 'ԑ',
  'Ԓ' => 'ԓ',
  'Ԕ' => 'ԕ',
  'Ԗ' => 'ԗ',
  'Ԙ' => 'ԙ',
  'Ԛ' => 'ԛ',
  'Ԝ' => 'ԝ',
  'Ԟ' => 'ԟ',
  'Ԡ' => 'ԡ',
  'Ԣ' => 'ԣ',
  'Ԥ' => 'ԥ',
  'Ԧ' => 'ԧ',
  'Ԩ' => 'ԩ',
  'Ԫ' => 'ԫ',
  'Ԭ' => 'ԭ',
  'Ԯ' => 'ԯ',
  'Ա' => 'ա',
  'Բ' => 'բ',
  'Գ' => 'գ',
  'Դ' => 'դ',
  'Ե' => 'ե',
  'Զ' => 'զ',
  'Է' => 'է',
  'Ը' => 'ը',
  'Թ' => 'թ',
  'Ժ' => 'ժ',
  'Ի' => 'ի',
  'Լ' => 'լ',
  'Խ' => 'խ',
  'Ծ' => 'ծ',
  'Կ' => 'կ',
  'Հ' => 'հ',
  'Ձ' => 'ձ',
  'Ղ' => 'ղ',
  'Ճ' => 'ճ',
  'Մ' => 'մ',
  'Յ' => 'յ',
  'Ն' => 'ն',
  'Շ' => 'շ',
  'Ո' => 'ո',
  'Չ' => 'չ',
  'Պ' => 'պ',
  'Ջ' => 'ջ',
  'Ռ' => 'ռ',
  'Ս' => 'ս',
  'Վ' => 'վ',
  'Տ' => 'տ',
  'Ր' => 'ր',
  'Ց' => 'ց',
  'Ւ' => 'ւ',
  'Փ' => 'փ',
  'Ք' => 'ք',
  'Օ' => 'օ',
  'Ֆ' => 'ֆ',
  'Ⴀ' => 'ⴀ',
  'Ⴁ' => 'ⴁ',
  'Ⴂ' => 'ⴂ',
  'Ⴃ' => 'ⴃ',
  'Ⴄ' => 'ⴄ',
  'Ⴅ' => 'ⴅ',
  'Ⴆ' => 'ⴆ',
  'Ⴇ' => 'ⴇ',
  'Ⴈ' => 'ⴈ',
  'Ⴉ' => 'ⴉ',
  'Ⴊ' => 'ⴊ',
  'Ⴋ' => 'ⴋ',
  'Ⴌ' => 'ⴌ',
  'Ⴍ' => 'ⴍ',
  'Ⴎ' => 'ⴎ',
  'Ⴏ' => 'ⴏ',
  'Ⴐ' => 'ⴐ',
  'Ⴑ' => 'ⴑ',
  'Ⴒ' => 'ⴒ',
  'Ⴓ' => 'ⴓ',
  'Ⴔ' => 'ⴔ',
  'Ⴕ' => 'ⴕ',
  'Ⴖ' => 'ⴖ',
  'Ⴗ' => 'ⴗ',
  'Ⴘ' => 'ⴘ',
  'Ⴙ' => 'ⴙ',
  'Ⴚ' => 'ⴚ',
  'Ⴛ' => 'ⴛ',
  'Ⴜ' => 'ⴜ',
  'Ⴝ' => 'ⴝ',
  'Ⴞ' => 'ⴞ',
  'Ⴟ' => 'ⴟ',
  'Ⴠ' => 'ⴠ',
  'Ⴡ' => 'ⴡ',
  'Ⴢ' => 'ⴢ',
  'Ⴣ' => 'ⴣ',
  'Ⴤ' => 'ⴤ',
  'Ⴥ' => 'ⴥ',
  'Ⴧ' => 'ⴧ',
  'Ⴭ' => 'ⴭ',
  'Ꭰ' => 'ꭰ',
  'Ꭱ' => 'ꭱ',
  'Ꭲ' => 'ꭲ',
  'Ꭳ' => 'ꭳ',
  'Ꭴ' => 'ꭴ',
  'Ꭵ' => 'ꭵ',
  'Ꭶ' => 'ꭶ',
  'Ꭷ' => 'ꭷ',
  'Ꭸ' => 'ꭸ',
  'Ꭹ' => 'ꭹ',
  'Ꭺ' => 'ꭺ',
  'Ꭻ' => 'ꭻ',
  'Ꭼ' => 'ꭼ',
  'Ꭽ' => 'ꭽ',
  'Ꭾ' => 'ꭾ',
  'Ꭿ' => 'ꭿ',
  'Ꮀ' => 'ꮀ',
  'Ꮁ' => 'ꮁ',
  'Ꮂ' => 'ꮂ',
  'Ꮃ' => 'ꮃ',
  'Ꮄ' => 'ꮄ',
  'Ꮅ' => 'ꮅ',
  'Ꮆ' => 'ꮆ',
  'Ꮇ' => 'ꮇ',
  'Ꮈ' => 'ꮈ',
  'Ꮉ' => 'ꮉ',
  'Ꮊ' => 'ꮊ',
  'Ꮋ' => 'ꮋ',
  'Ꮌ' => 'ꮌ',
  'Ꮍ' => 'ꮍ',
  'Ꮎ' => 'ꮎ',
  'Ꮏ' => 'ꮏ',
  'Ꮐ' => 'ꮐ',
  'Ꮑ' => 'ꮑ',
  'Ꮒ' => 'ꮒ',
  'Ꮓ' => 'ꮓ',
  'Ꮔ' => 'ꮔ',
  'Ꮕ' => 'ꮕ',
  'Ꮖ' => 'ꮖ',
  'Ꮗ' => 'ꮗ',
  'Ꮘ' => 'ꮘ',
  'Ꮙ' => 'ꮙ',
  'Ꮚ' => 'ꮚ',
  'Ꮛ' => 'ꮛ',
  'Ꮜ' => 'ꮜ',
  'Ꮝ' => 'ꮝ',
  'Ꮞ' => 'ꮞ',
  'Ꮟ' => 'ꮟ',
  'Ꮠ' => 'ꮠ',
  'Ꮡ' => 'ꮡ',
  'Ꮢ' => 'ꮢ',
  'Ꮣ' => 'ꮣ',
  'Ꮤ' => 'ꮤ',
  'Ꮥ' => 'ꮥ',
  'Ꮦ' => 'ꮦ',
  'Ꮧ' => 'ꮧ',
  'Ꮨ' => 'ꮨ',
  'Ꮩ' => 'ꮩ',
  'Ꮪ' => 'ꮪ',
  'Ꮫ' => 'ꮫ',
  'Ꮬ' => 'ꮬ',
  'Ꮭ' => 'ꮭ',
  'Ꮮ' => 'ꮮ',
  'Ꮯ' => 'ꮯ',
  'Ꮰ' => 'ꮰ',
  'Ꮱ' => 'ꮱ',
  'Ꮲ' => 'ꮲ',
  'Ꮳ' => 'ꮳ',
  'Ꮴ' => 'ꮴ',
  'Ꮵ' => 'ꮵ',
  'Ꮶ' => 'ꮶ',
  'Ꮷ' => 'ꮷ',
  'Ꮸ' => 'ꮸ',
  'Ꮹ' => 'ꮹ',
  'Ꮺ' => 'ꮺ',
  'Ꮻ' => 'ꮻ',
  'Ꮼ' => 'ꮼ',
  'Ꮽ' => 'ꮽ',
  'Ꮾ' => 'ꮾ',
  'Ꮿ' => 'ꮿ',
  'Ᏸ' => 'ᏸ',
  'Ᏹ' => 'ᏹ',
  'Ᏺ' => 'ᏺ',
  'Ᏻ' => 'ᏻ',
  'Ᏼ' => 'ᏼ',
  'Ᏽ' => 'ᏽ',
  'Ა' => 'ა',
  'Ბ' => 'ბ',
  'Გ' => 'გ',
  'Დ' => 'დ',
  'Ე' => 'ე',
  'Ვ' => 'ვ',
  'Ზ' => 'ზ',
  'Თ' => 'თ',
  'Ი' => 'ი',
  'Კ' => 'კ',
  'Ლ' => 'ლ',
  'Მ' => 'მ',
  'Ნ' => 'ნ',
  'Ო' => 'ო',
  'Პ' => 'პ',
  'Ჟ' => 'ჟ',
  'Რ' => 'რ',
  'Ს' => 'ს',
  'Ტ' => 'ტ',
  'Უ' => 'უ',
  'Ფ' => 'ფ',
  'Ქ' => 'ქ',
  'Ღ' => 'ღ',
  'Ყ' => 'ყ',
  'Შ' => 'შ',
  'Ჩ' => 'ჩ',
  'Ც' => 'ც',
  'Ძ' => 'ძ',
  'Წ' => 'წ',
  'Ჭ' => 'ჭ',
  'Ხ' => 'ხ',
  'Ჯ' => 'ჯ',
  'Ჰ' => 'ჰ',
  'Ჱ' => 'ჱ',
  'Ჲ' => 'ჲ',
  'Ჳ' => 'ჳ',
  'Ჴ' => 'ჴ',
  'Ჵ' => 'ჵ',
  'Ჶ' => 'ჶ',
  'Ჷ' => 'ჷ',
  'Ჸ' => 'ჸ',
  'Ჹ' => 'ჹ',
  'Ჺ' => 'ჺ',
  'Ჽ' => 'ჽ',
  'Ჾ' => 'ჾ',
  'Ჿ' => 'ჿ',
  'Ḁ' => 'ḁ',
  'Ḃ' => 'ḃ',
  'Ḅ' => 'ḅ',
  'Ḇ' => 'ḇ',
  'Ḉ' => 'ḉ',
  'Ḋ' => 'ḋ',
  'Ḍ' => 'ḍ',
  'Ḏ' => 'ḏ',
  'Ḑ' => 'ḑ',
  'Ḓ' => 'ḓ',
  'Ḕ' => 'ḕ',
  'Ḗ' => 'ḗ',
  'Ḙ' => 'ḙ',
  'Ḛ' => 'ḛ',
  'Ḝ' => 'ḝ',
  'Ḟ' => 'ḟ',
  'Ḡ' => 'ḡ',
  'Ḣ' => 'ḣ',
  'Ḥ' => 'ḥ',
  'Ḧ' => 'ḧ',
  'Ḩ' => 'ḩ',
  'Ḫ' => 'ḫ',
  'Ḭ' => 'ḭ',
  'Ḯ' => 'ḯ',
  'Ḱ' => 'ḱ',
  'Ḳ' => 'ḳ',
  'Ḵ' => 'ḵ',
  'Ḷ' => 'ḷ',
  'Ḹ' => 'ḹ',
  'Ḻ' => 'ḻ',
  'Ḽ' => 'ḽ',
  'Ḿ' => 'ḿ',
  'Ṁ' => 'ṁ',
  'Ṃ' => 'ṃ',
  'Ṅ' => 'ṅ',
  'Ṇ' => 'ṇ',
  'Ṉ' => 'ṉ',
  'Ṋ' => 'ṋ',
  'Ṍ' => 'ṍ',
  'Ṏ' => 'ṏ',
  'Ṑ' => 'ṑ',
  'Ṓ' => 'ṓ',
  'Ṕ' => 'ṕ',
  'Ṗ' => 'ṗ',
  'Ṙ' => 'ṙ',
  'Ṛ' => 'ṛ',
  'Ṝ' => 'ṝ',
  'Ṟ' => 'ṟ',
  'Ṡ' => 'ṡ',
  'Ṣ' => 'ṣ',
  'Ṥ' => 'ṥ',
  'Ṧ' => 'ṧ',
  'Ṩ' => 'ṩ',
  'Ṫ' => 'ṫ',
  'Ṭ' => 'ṭ',
  'Ṯ' => 'ṯ',
  'Ṱ' => 'ṱ',
  'Ṳ' => 'ṳ',
  'Ṵ' => 'ṵ',
  'Ṷ' => 'ṷ',
  'Ṹ' => 'ṹ',
  'Ṻ' => 'ṻ',
  'Ṽ' => 'ṽ',
  'Ṿ' => 'ṿ',
  'Ẁ' => 'ẁ',
  'Ẃ' => 'ẃ',
  'Ẅ' => 'ẅ',
  'Ẇ' => 'ẇ',
  'Ẉ' => 'ẉ',
  'Ẋ' => 'ẋ',
  'Ẍ' => 'ẍ',
  'Ẏ' => 'ẏ',
  'Ẑ' => 'ẑ',
  'Ẓ' => 'ẓ',
  'Ẕ' => 'ẕ',
  'ẞ' => 'ß',
  'Ạ' => 'ạ',
  'Ả' => 'ả',
  'Ấ' => 'ấ',
  'Ầ' => 'ầ',
  'Ẩ' => 'ẩ',
  'Ẫ' => 'ẫ',
  'Ậ' => 'ậ',
  'Ắ' => 'ắ',
  'Ằ' => 'ằ',
  'Ẳ' => 'ẳ',
  'Ẵ' => 'ẵ',
  'Ặ' => 'ặ',
  'Ẹ' => 'ẹ',
  'Ẻ' => 'ẻ',
  'Ẽ' => 'ẽ',
  'Ế' => 'ế',
  'Ề' => 'ề',
  'Ể' => 'ể',
  'Ễ' => 'ễ',
  'Ệ' => 'ệ',
  'Ỉ' => 'ỉ',
  'Ị' => 'ị',
  'Ọ' => 'ọ',
  'Ỏ' => 'ỏ',
  'Ố' => 'ố',
  'Ồ' => 'ồ',
  'Ổ' => 'ổ',
  'Ỗ' => 'ỗ',
  'Ộ' => 'ộ',
  'Ớ' => 'ớ',
  'Ờ' => 'ờ',
  'Ở' => 'ở',
  'Ỡ' => 'ỡ',
  'Ợ' => 'ợ',
  'Ụ' => 'ụ',
  'Ủ' => 'ủ',
  'Ứ' => 'ứ',
  'Ừ' => 'ừ',
  'Ử' => 'ử',
  'Ữ' => 'ữ',
  'Ự' => 'ự',
  'Ỳ' => 'ỳ',
  'Ỵ' => 'ỵ',
  'Ỷ' => 'ỷ',
  'Ỹ' => 'ỹ',
  'Ỻ' => 'ỻ',
  'Ỽ' => 'ỽ',
  'Ỿ' => 'ỿ',
  'Ἀ' => 'ἀ',
  'Ἁ' => 'ἁ',
  'Ἂ' => 'ἂ',
  'Ἃ' => 'ἃ',
  'Ἄ' => 'ἄ',
  'Ἅ' => 'ἅ',
  'Ἆ' => 'ἆ',
  'Ἇ' => 'ἇ',
  'Ἐ' => 'ἐ',
  'Ἑ' => 'ἑ',
  'Ἒ' => 'ἒ',
  'Ἓ' => 'ἓ',
  'Ἔ' => 'ἔ',
  'Ἕ' => 'ἕ',
  'Ἠ' => 'ἠ',
  'Ἡ' => 'ἡ',
  'Ἢ' => 'ἢ',
  'Ἣ' => 'ἣ',
  'Ἤ' => 'ἤ',
  'Ἥ' => 'ἥ',
  'Ἦ' => 'ἦ',
  'Ἧ' => 'ἧ',
  'Ἰ' => 'ἰ',
  'Ἱ' => 'ἱ',
  'Ἲ' => 'ἲ',
  'Ἳ' => 'ἳ',
  'Ἴ' => 'ἴ',
  'Ἵ' => 'ἵ',
  'Ἶ' => 'ἶ',
  'Ἷ' => 'ἷ',
  'Ὀ' => 'ὀ',
  'Ὁ' => 'ὁ',
  'Ὂ' => 'ὂ',
  'Ὃ' => 'ὃ',
  'Ὄ' => 'ὄ',
  'Ὅ' => 'ὅ',
  'Ὑ' => 'ὑ',
  'Ὓ' => 'ὓ',
  'Ὕ' => 'ὕ',
  'Ὗ' => 'ὗ',
  'Ὠ' => 'ὠ',
  'Ὡ' => 'ὡ',
  'Ὢ' => 'ὢ',
  'Ὣ' => 'ὣ',
  'Ὤ' => 'ὤ',
  'Ὥ' => 'ὥ',
  'Ὦ' => 'ὦ',
  'Ὧ' => 'ὧ',
  'ᾈ' => 'ᾀ',
  'ᾉ' => 'ᾁ',
  'ᾊ' => 'ᾂ',
  'ᾋ' => 'ᾃ',
  'ᾌ' => 'ᾄ',
  'ᾍ' => 'ᾅ',
  'ᾎ' => 'ᾆ',
  'ᾏ' => 'ᾇ',
  'ᾘ' => 'ᾐ',
  'ᾙ' => 'ᾑ',
  'ᾚ' => 'ᾒ',
  'ᾛ' => 'ᾓ',
  'ᾜ' => 'ᾔ',
  'ᾝ' => 'ᾕ',
  'ᾞ' => 'ᾖ',
  'ᾟ' => 'ᾗ',
  'ᾨ' => 'ᾠ',
  'ᾩ' => 'ᾡ',
  'ᾪ' => 'ᾢ',
  'ᾫ' => 'ᾣ',
  'ᾬ' => 'ᾤ',
  'ᾭ' => 'ᾥ',
  'ᾮ' => 'ᾦ',
  'ᾯ' => 'ᾧ',
  'Ᾰ' => 'ᾰ',
  'Ᾱ' => 'ᾱ',
  'Ὰ' => 'ὰ',
  'Ά' => 'ά',
  'ᾼ' => 'ᾳ',
  'Ὲ' => 'ὲ',
  'Έ' => 'έ',
  'Ὴ' => 'ὴ',
  'Ή' => 'ή',
  'ῌ' => 'ῃ',
  'Ῐ' => 'ῐ',
  'Ῑ' => 'ῑ',
  'Ὶ' => 'ὶ',
  'Ί' => 'ί',
  'Ῠ' => 'ῠ',
  'Ῡ' => 'ῡ',
  'Ὺ' => 'ὺ',
  'Ύ' => 'ύ',
  'Ῥ' => 'ῥ',
  'Ὸ' => 'ὸ',
  'Ό' => 'ό',
  'Ὼ' => 'ὼ',
  'Ώ' => 'ώ',
  'ῼ' => 'ῳ',
  'Ω' => 'ω',
  'K' => 'k',
  'Å' => 'å',
  'Ⅎ' => 'ⅎ',
  'Ⅰ' => 'ⅰ',
  'Ⅱ' => 'ⅱ',
  'Ⅲ' => 'ⅲ',
  'Ⅳ' => 'ⅳ',
  'Ⅴ' => 'ⅴ',
  'Ⅵ' => 'ⅵ',
  'Ⅶ' => 'ⅶ',
  'Ⅷ' => 'ⅷ',
  'Ⅸ' => 'ⅸ',
  'Ⅹ' => 'ⅹ',
  'Ⅺ' => 'ⅺ',
  'Ⅻ' => 'ⅻ',
  'Ⅼ' => 'ⅼ',
  'Ⅽ' => 'ⅽ',
  'Ⅾ' => 'ⅾ',
  'Ⅿ' => 'ⅿ',
  'Ↄ' => 'ↄ',
  'Ⓐ' => 'ⓐ',
  'Ⓑ' => 'ⓑ',
  'Ⓒ' => 'ⓒ',
  'Ⓓ' => 'ⓓ',
  'Ⓔ' => 'ⓔ',
  'Ⓕ' => 'ⓕ',
  'Ⓖ' => 'ⓖ',
  'Ⓗ' => 'ⓗ',
  'Ⓘ' => 'ⓘ',
  'Ⓙ' => 'ⓙ',
  'Ⓚ' => 'ⓚ',
  'Ⓛ' => 'ⓛ',
  'Ⓜ' => 'ⓜ',
  'Ⓝ' => 'ⓝ',
  'Ⓞ' => 'ⓞ',
  'Ⓟ' => 'ⓟ',
  'Ⓠ' => 'ⓠ',
  'Ⓡ' => 'ⓡ',
  'Ⓢ' => 'ⓢ',
  'Ⓣ' => 'ⓣ',
  'Ⓤ' => 'ⓤ',
  'Ⓥ' => 'ⓥ',
  'Ⓦ' => 'ⓦ',
  'Ⓧ' => 'ⓧ',
  'Ⓨ' => 'ⓨ',
  'Ⓩ' => 'ⓩ',
  'Ⰰ' => 'ⰰ',
  'Ⰱ' => 'ⰱ',
  'Ⰲ' => 'ⰲ',
  'Ⰳ' => 'ⰳ',
  'Ⰴ' => 'ⰴ',
  'Ⰵ' => 'ⰵ',
  'Ⰶ' => 'ⰶ',
  'Ⰷ' => 'ⰷ',
  'Ⰸ' => 'ⰸ',
  'Ⰹ' => 'ⰹ',
  'Ⰺ' => 'ⰺ',
  'Ⰻ' => 'ⰻ',
  'Ⰼ' => 'ⰼ',
  'Ⰽ' => 'ⰽ',
  'Ⰾ' => 'ⰾ',
  'Ⰿ' => 'ⰿ',
  'Ⱀ' => 'ⱀ',
  'Ⱁ' => 'ⱁ',
  'Ⱂ' => 'ⱂ',
  'Ⱃ' => 'ⱃ',
  'Ⱄ' => 'ⱄ',
  'Ⱅ' => 'ⱅ',
  'Ⱆ' => 'ⱆ',
  'Ⱇ' => 'ⱇ',
  'Ⱈ' => 'ⱈ',
  'Ⱉ' => 'ⱉ',
  'Ⱊ' => 'ⱊ',
  'Ⱋ' => 'ⱋ',
  'Ⱌ' => 'ⱌ',
  'Ⱍ' => 'ⱍ',
  'Ⱎ' => 'ⱎ',
  'Ⱏ' => 'ⱏ',
  'Ⱐ' => 'ⱐ',
  'Ⱑ' => 'ⱑ',
  'Ⱒ' => 'ⱒ',
  'Ⱓ' => 'ⱓ',
  'Ⱔ' => 'ⱔ',
  'Ⱕ' => 'ⱕ',
  'Ⱖ' => 'ⱖ',
  'Ⱗ' => 'ⱗ',
  'Ⱘ' => 'ⱘ',
  'Ⱙ' => 'ⱙ',
  'Ⱚ' => 'ⱚ',
  'Ⱛ' => 'ⱛ',
  'Ⱜ' => 'ⱜ',
  'Ⱝ' => 'ⱝ',
  'Ⱞ' => 'ⱞ',
  'Ⱡ' => 'ⱡ',
  'Ɫ' => 'ɫ',
  'Ᵽ' => 'ᵽ',
  'Ɽ' => 'ɽ',
  'Ⱨ' => 'ⱨ',
  'Ⱪ' => 'ⱪ',
  'Ⱬ' => 'ⱬ',
  'Ɑ' => 'ɑ',
  'Ɱ' => 'ɱ',
  'Ɐ' => 'ɐ',
  'Ɒ' => 'ɒ',
  'Ⱳ' => 'ⱳ',
  'Ⱶ' => 'ⱶ',
  'Ȿ' => 'ȿ',
  'Ɀ' => 'ɀ',
  'Ⲁ' => 'ⲁ',
  'Ⲃ' => 'ⲃ',
  'Ⲅ' => 'ⲅ',
  'Ⲇ' => 'ⲇ',
  'Ⲉ' => 'ⲉ',
  'Ⲋ' => 'ⲋ',
  'Ⲍ' => 'ⲍ',
  'Ⲏ' => 'ⲏ',
  'Ⲑ' => 'ⲑ',
  'Ⲓ' => 'ⲓ',
  'Ⲕ' => 'ⲕ',
  'Ⲗ' => 'ⲗ',
  'Ⲙ' => 'ⲙ',
  'Ⲛ' => 'ⲛ',
  'Ⲝ' => 'ⲝ',
  'Ⲟ' => 'ⲟ',
  'Ⲡ' => 'ⲡ',
  'Ⲣ' => 'ⲣ',
  'Ⲥ' => 'ⲥ',
  'Ⲧ' => 'ⲧ',
  'Ⲩ' => 'ⲩ',
  'Ⲫ' => 'ⲫ',
  'Ⲭ' => 'ⲭ',
  'Ⲯ' => 'ⲯ',
  'Ⲱ' => 'ⲱ',
  'Ⲳ' => 'ⲳ',
  'Ⲵ' => 'ⲵ',
  'Ⲷ' => 'ⲷ',
  'Ⲹ' => 'ⲹ',
  'Ⲻ' => 'ⲻ',
  'Ⲽ' => 'ⲽ',
  'Ⲿ' => 'ⲿ',
  'Ⳁ' => 'ⳁ',
  'Ⳃ' => 'ⳃ',
  'Ⳅ' => 'ⳅ',
  'Ⳇ' => 'ⳇ',
  'Ⳉ' => 'ⳉ',
  'Ⳋ' => 'ⳋ',
  'Ⳍ' => 'ⳍ',
  'Ⳏ' => 'ⳏ',
  'Ⳑ' => 'ⳑ',
  'Ⳓ' => 'ⳓ',
  'Ⳕ' => 'ⳕ',
  'Ⳗ' => 'ⳗ',
  'Ⳙ' => 'ⳙ',
  'Ⳛ' => 'ⳛ',
  'Ⳝ' => 'ⳝ',
  'Ⳟ' => 'ⳟ',
  'Ⳡ' => 'ⳡ',
  'Ⳣ' => 'ⳣ',
  'Ⳬ' => 'ⳬ',
  'Ⳮ' => 'ⳮ',
  'Ⳳ' => 'ⳳ',
  'Ꙁ' => 'ꙁ',
  'Ꙃ' => 'ꙃ',
  'Ꙅ' => 'ꙅ',
  'Ꙇ' => 'ꙇ',
  'Ꙉ' => 'ꙉ',
  'Ꙋ' => 'ꙋ',
  'Ꙍ' => 'ꙍ',
  'Ꙏ' => 'ꙏ',
  'Ꙑ' => 'ꙑ',
  'Ꙓ' => 'ꙓ',
  'Ꙕ' => 'ꙕ',
  'Ꙗ' => 'ꙗ',
  'Ꙙ' => 'ꙙ',
  'Ꙛ' => 'ꙛ',
  'Ꙝ' => 'ꙝ',
  'Ꙟ' => 'ꙟ',
  'Ꙡ' => 'ꙡ',
  'Ꙣ' => 'ꙣ',
  'Ꙥ' => 'ꙥ',
  'Ꙧ' => 'ꙧ',
  'Ꙩ' => 'ꙩ',
  'Ꙫ' => 'ꙫ',
  'Ꙭ' => 'ꙭ',
  'Ꚁ' => 'ꚁ',
  'Ꚃ' => 'ꚃ',
  'Ꚅ' => 'ꚅ',
  'Ꚇ' => 'ꚇ',
  'Ꚉ' => 'ꚉ',
  'Ꚋ' => 'ꚋ',
  'Ꚍ' => 'ꚍ',
  'Ꚏ' => 'ꚏ',
  'Ꚑ' => 'ꚑ',
  'Ꚓ' => 'ꚓ',
  'Ꚕ' => 'ꚕ',
  'Ꚗ' => 'ꚗ',
  'Ꚙ' => 'ꚙ',
  'Ꚛ' => 'ꚛ',
  'Ꜣ' => 'ꜣ',
  'Ꜥ' => 'ꜥ',
  'Ꜧ' => 'ꜧ',
  'Ꜩ' => 'ꜩ',
  'Ꜫ' => 'ꜫ',
  'Ꜭ' => 'ꜭ',
  'Ꜯ' => 'ꜯ',
  'Ꜳ' => 'ꜳ',
  'Ꜵ' => 'ꜵ',
  'Ꜷ' => 'ꜷ',
  'Ꜹ' => 'ꜹ',
  'Ꜻ' => 'ꜻ',
  'Ꜽ' => 'ꜽ',
  'Ꜿ' => 'ꜿ',
  'Ꝁ' => 'ꝁ',
  'Ꝃ' => 'ꝃ',
  'Ꝅ' => 'ꝅ',
  'Ꝇ' => 'ꝇ',
  'Ꝉ' => 'ꝉ',
  'Ꝋ' => 'ꝋ',
  'Ꝍ' => 'ꝍ',
  'Ꝏ' => 'ꝏ',
  'Ꝑ' => 'ꝑ',
  'Ꝓ' => 'ꝓ',
  'Ꝕ' => 'ꝕ',
  'Ꝗ' => 'ꝗ',
  'Ꝙ' => 'ꝙ',
  'Ꝛ' => 'ꝛ',
  'Ꝝ' => 'ꝝ',
  'Ꝟ' => 'ꝟ',
  'Ꝡ' => 'ꝡ',
  'Ꝣ' => 'ꝣ',
  'Ꝥ' => 'ꝥ',
  'Ꝧ' => 'ꝧ',
  'Ꝩ' => 'ꝩ',
  'Ꝫ' => 'ꝫ',
  'Ꝭ' => 'ꝭ',
  'Ꝯ' => 'ꝯ',
  'Ꝺ' => 'ꝺ',
  'Ꝼ' => 'ꝼ',
  'Ᵹ' => 'ᵹ',
  'Ꝿ' => 'ꝿ',
  'Ꞁ' => 'ꞁ',
  'Ꞃ' => 'ꞃ',
  'Ꞅ' => 'ꞅ',
  'Ꞇ' => 'ꞇ',
  'Ꞌ' => 'ꞌ',
  'Ɥ' => 'ɥ',
  'Ꞑ' => 'ꞑ',
  'Ꞓ' => 'ꞓ',
  'Ꞗ' => 'ꞗ',
  'Ꞙ' => 'ꞙ',
  'Ꞛ' => 'ꞛ',
  'Ꞝ' => 'ꞝ',
  'Ꞟ' => 'ꞟ',
  'Ꞡ' => 'ꞡ',
  'Ꞣ' => 'ꞣ',
  'Ꞥ' => 'ꞥ',
  'Ꞧ' => 'ꞧ',
  'Ꞩ' => 'ꞩ',
  'Ɦ' => 'ɦ',
  'Ɜ' => 'ɜ',
  'Ɡ' => 'ɡ',
  'Ɬ' => 'ɬ',
  'Ɪ' => 'ɪ',
  'Ʞ' => 'ʞ',
  'Ʇ' => 'ʇ',
  'Ʝ' => 'ʝ',
  'Ꭓ' => 'ꭓ',
  'Ꞵ' => 'ꞵ',
  'Ꞷ' => 'ꞷ',
  'Ꞹ' => 'ꞹ',
  'Ꞻ' => 'ꞻ',
  'Ꞽ' => 'ꞽ',
  'Ꞿ' => 'ꞿ',
  'Ꟃ' => 'ꟃ',
  'Ꞔ' => 'ꞔ',
  'Ʂ' => 'ʂ',
  'Ᶎ' => 'ᶎ',
  'Ꟈ' => 'ꟈ',
  'Ꟊ' => 'ꟊ',
  'Ꟶ' => 'ꟶ',
  'Ａ' => 'ａ',
  'Ｂ' => 'ｂ',
  'Ｃ' => 'ｃ',
  'Ｄ' => 'ｄ',
  'Ｅ' => 'ｅ',
  'Ｆ' => 'ｆ',
  'Ｇ' => 'ｇ',
  'Ｈ' => 'ｈ',
  'Ｉ' => 'ｉ',
  'Ｊ' => 'ｊ',
  'Ｋ' => 'ｋ',
  'Ｌ' => 'ｌ',
  'Ｍ' => 'ｍ',
  'Ｎ' => 'ｎ',
  'Ｏ' => 'ｏ',
  'Ｐ' => 'ｐ',
  'Ｑ' => 'ｑ',
  'Ｒ' => 'ｒ',
  'Ｓ' => 'ｓ',
  'Ｔ' => 'ｔ',
  'Ｕ' => 'ｕ',
  'Ｖ' => 'ｖ',
  'Ｗ' => 'ｗ',
  'Ｘ' => 'ｘ',
  'Ｙ' => 'ｙ',
  'Ｚ' => 'ｚ',
  '𐐀' => '𐐨',
  '𐐁' => '𐐩',
  '𐐂' => '𐐪',
  '𐐃' => '𐐫',
  '𐐄' => '𐐬',
  '𐐅' => '𐐭',
  '𐐆' => '𐐮',
  '𐐇' => '𐐯',
  '𐐈' => '𐐰',
  '𐐉' => '𐐱',
  '𐐊' => '𐐲',
  '𐐋' => '𐐳',
  '𐐌' => '𐐴',
  '𐐍' => '𐐵',
  '𐐎' => '𐐶',
  '𐐏' => '𐐷',
  '𐐐' => '𐐸',
  '𐐑' => '𐐹',
  '𐐒' => '𐐺',
  '𐐓' => '𐐻',
  '𐐔' => '𐐼',
  '𐐕' => '𐐽',
  '𐐖' => '𐐾',
  '𐐗' => '𐐿',
  '𐐘' => '𐑀',
  '𐐙' => '𐑁',
  '𐐚' => '𐑂',
  '𐐛' => '𐑃',
  '𐐜' => '𐑄',
  '𐐝' => '𐑅',
  '𐐞' => '𐑆',
  '𐐟' => '𐑇',
  '𐐠' => '𐑈',
  '𐐡' => '𐑉',
  '𐐢' => '𐑊',
  '𐐣' => '𐑋',
  '𐐤' => '𐑌',
  '𐐥' => '𐑍',
  '𐐦' => '𐑎',
  '𐐧' => '𐑏',
  '𐒰' => '𐓘',
  '𐒱' => '𐓙',
  '𐒲' => '𐓚',
  '𐒳' => '𐓛',
  '𐒴' => '𐓜',
  '𐒵' => '𐓝',
  '𐒶' => '𐓞',
  '𐒷' => '𐓟',
  '𐒸' => '𐓠',
  '𐒹' => '𐓡',
  '𐒺' => '𐓢',
  '𐒻' => '𐓣',
  '𐒼' => '𐓤',
  '𐒽' => '𐓥',
  '𐒾' => '𐓦',
  '𐒿' => '𐓧',
  '𐓀' => '𐓨',
  '𐓁' => '𐓩',
  '𐓂' => '𐓪',
  '𐓃' => '𐓫',
  '𐓄' => '𐓬',
  '𐓅' => '𐓭',
  '𐓆' => '𐓮',
  '𐓇' => '𐓯',
  '𐓈' => '𐓰',
  '𐓉' => '𐓱',
  '𐓊' => '𐓲',
  '𐓋' => '𐓳',
  '𐓌' => '𐓴',
  '𐓍' => '𐓵',
  '𐓎' => '𐓶',
  '𐓏' => '𐓷',
  '𐓐' => '𐓸',
  '𐓑' => '𐓹',
  '𐓒' => '𐓺',
  '𐓓' => '𐓻',
  '𐲀' => '𐳀',
  '𐲁' => '𐳁',
  '𐲂' => '𐳂',
  '𐲃' => '𐳃',
  '𐲄' => '𐳄',
  '𐲅' => '𐳅',
  '𐲆' => '𐳆',
  '𐲇' => '𐳇',
  '𐲈' => '𐳈',
  '𐲉' => '𐳉',
  '𐲊' => '𐳊',
  '𐲋' => '𐳋',
  '𐲌' => '𐳌',
  '𐲍' => '𐳍',
  '𐲎' => '𐳎',
  '𐲏' => '𐳏',
  '𐲐' => '𐳐',
  '𐲑' => '𐳑',
  '𐲒' => '𐳒',
  '𐲓' => '𐳓',
  '𐲔' => '𐳔',
  '𐲕' => '𐳕',
  '𐲖' => '𐳖',
  '𐲗' => '𐳗',
  '𐲘' => '𐳘',
  '𐲙' => '𐳙',
  '𐲚' => '𐳚',
  '𐲛' => '𐳛',
  '𐲜' => '𐳜',
  '𐲝' => '𐳝',
  '𐲞' => '𐳞',
  '𐲟' => '𐳟',
  '𐲠' => '𐳠',
  '𐲡' => '𐳡',
  '𐲢' => '𐳢',
  '𐲣' => '𐳣',
  '𐲤' => '𐳤',
  '𐲥' => '𐳥',
  '𐲦' => '𐳦',
  '𐲧' => '𐳧',
  '𐲨' => '𐳨',
  '𐲩' => '𐳩',
  '𐲪' => '𐳪',
  '𐲫' => '𐳫',
  '𐲬' => '𐳬',
  '𐲭' => '𐳭',
  '𐲮' => '𐳮',
  '𐲯' => '𐳯',
  '𐲰' => '𐳰',
  '𐲱' => '𐳱',
  '𐲲' => '𐳲',
  '𑢠' => '𑣀',
  '𑢡' => '𑣁',
  '𑢢' => '𑣂',
  '𑢣' => '𑣃',
  '𑢤' => '𑣄',
  '𑢥' => '𑣅',
  '𑢦' => '𑣆',
  '𑢧' => '𑣇',
  '𑢨' => '𑣈',
  '𑢩' => '𑣉',
  '𑢪' => '𑣊',
  '𑢫' => '𑣋',
  '𑢬' => '𑣌',
  '𑢭' => '𑣍',
  '𑢮' => '𑣎',
  '𑢯' => '𑣏',
  '𑢰' => '𑣐',
  '𑢱' => '𑣑',
  '𑢲' => '𑣒',
  '𑢳' => '𑣓',
  '𑢴' => '𑣔',
  '𑢵' => '𑣕',
  '𑢶' => '𑣖',
  '𑢷' => '𑣗',
  '𑢸' => '𑣘',
  '𑢹' => '𑣙',
  '𑢺' => '𑣚',
  '𑢻' => '𑣛',
  '𑢼' => '𑣜',
  '𑢽' => '𑣝',
  '𑢾' => '𑣞',
  '𑢿' => '𑣟',
  '𖹀' => '𖹠',
  '𖹁' => '𖹡',
  '𖹂' => '𖹢',
  '𖹃' => '𖹣',
  '𖹄' => '𖹤',
  '𖹅' => '𖹥',
  '𖹆' => '𖹦',
  '𖹇' => '𖹧',
  '𖹈' => '𖹨',
  '𖹉' => '𖹩',
  '𖹊' => '𖹪',
  '𖹋' => '𖹫',
  '𖹌' => '𖹬',
  '𖹍' => '𖹭',
  '𖹎' => '𖹮',
  '𖹏' => '𖹯',
  '𖹐' => '𖹰',
  '𖹑' => '𖹱',
  '𖹒' => '𖹲',
  '𖹓' => '𖹳',
  '𖹔' => '𖹴',
  '𖹕' => '𖹵',
  '𖹖' => '𖹶',
  '𖹗' => '𖹷',
  '𖹘' => '𖹸',
  '𖹙' => '𖹹',
  '𖹚' => '𖹺',
  '𖹛' => '𖹻',
  '𖹜' => '𖹼',
  '𖹝' => '𖹽',
  '𖹞' => '𖹾',
  '𖹟' => '𖹿',
  '𞤀' => '𞤢',
  '𞤁' => '𞤣',
  '𞤂' => '𞤤',
  '𞤃' => '𞤥',
  '𞤄' => '𞤦',
  '𞤅' => '𞤧',
  '𞤆' => '𞤨',
  '𞤇' => '𞤩',
  '𞤈' => '𞤪',
  '𞤉' => '𞤫',
  '𞤊' => '𞤬',
  '𞤋' => '𞤭',
  '𞤌' => '𞤮',
  '𞤍' => '𞤯',
  '𞤎' => '𞤰',
  '𞤏' => '𞤱',
  '𞤐' => '𞤲',
  '𞤑' => '𞤳',
  '𞤒' => '𞤴',
  '𞤓' => '𞤵',
  '𞤔' => '𞤶',
  '𞤕' => '𞤷',
  '𞤖' => '𞤸',
  '𞤗' => '𞤹',
  '𞤘' => '𞤺',
  '𞤙' => '𞤻',
  '𞤚' => '𞤼',
  '𞤛' => '𞤽',
  '𞤜' => '𞤾',
  '𞤝' => '𞤿',
  '𞤞' => '𞥀',
  '𞤟' => '𞥁',
  '𞤠' => '𞥂',
  '𞤡' => '𞥃',
);
<?php

// from Case_Ignorable in https://unicode.org/Public/UNIDATA/DerivedCoreProperties.txt

return '/(?<![\x{0027}\x{002E}\x{003A}\x{005E}\x{0060}\x{00A8}\x{00AD}\x{00AF}\x{00B4}\x{00B7}\x{00B8}\x{02B0}-\x{02C1}\x{02C2}-\x{02C5}\x{02C6}-\x{02D1}\x{02D2}-\x{02DF}\x{02E0}-\x{02E4}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EE}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037A}\x{0384}-\x{0385}\x{0387}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0559}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{05F4}\x{0600}-\x{0605}\x{0610}-\x{061A}\x{061C}\x{0640}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DD}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07FA}\x{07FD}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0971}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E46}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EB9}\x{0EBB}-\x{0EBC}\x{0EC6}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{10FC}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17D7}\x{17DD}\x{180B}-\x{180D}\x{180E}\x{1843}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AA7}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1C78}-\x{1C7D}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1D2C}-\x{1D6A}\x{1D78}\x{1D9B}-\x{1DBF}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200F}\x{2018}\x{2019}\x{2024}\x{2027}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{2066}-\x{206F}\x{2071}\x{207F}\x{2090}-\x{209C}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2C7C}-\x{2C7D}\x{2CEF}-\x{2CF1}\x{2D6F}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E2F}\x{3005}\x{302A}-\x{302D}\x{3031}-\x{3035}\x{303B}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{309D}-\x{309E}\x{30FC}-\x{30FE}\x{A015}\x{A4F8}-\x{A4FD}\x{A60C}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A67F}\x{A69C}-\x{A69D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A770}\x{A788}\x{A789}-\x{A78A}\x{A7F8}-\x{A7F9}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}\x{A9CF}\x{A9E5}\x{A9E6}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA70}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AADD}\x{AAEC}-\x{AAED}\x{AAF3}-\x{AAF4}\x{AAF6}\x{AB5B}\x{AB5C}-\x{AB5F}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FBB2}-\x{FBC1}\x{FE00}-\x{FE0F}\x{FE13}\x{FE20}-\x{FE2F}\x{FE52}\x{FE55}\x{FEFF}\x{FF07}\x{FF0E}\x{FF1A}\x{FF3E}\x{FF40}\x{FF70}\x{FF9E}-\x{FF9F}\x{FFE3}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{110BD}\x{110CD}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16B40}-\x{16B43}\x{16F8F}-\x{16F92}\x{16F93}-\x{16F9F}\x{16FE0}-\x{16FE1}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1F3FB}-\x{1F3FF}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}])(\pL)(\pL*+)/u';
<?php

return array (
  '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',
  'µ' => 'Μ',
  'à' => 'À',
  'á' => 'Á',
  'â' => 'Â',
  'ã' => 'Ã',
  'ä' => 'Ä',
  'å' => 'Å',
  'æ' => 'Æ',
  'ç' => 'Ç',
  'è' => 'È',
  'é' => 'É',
  'ê' => 'Ê',
  'ë' => 'Ë',
  'ì' => 'Ì',
  'í' => 'Í',
  'î' => 'Î',
  'ï' => 'Ï',
  'ð' => 'Ð',
  'ñ' => 'Ñ',
  'ò' => 'Ò',
  'ó' => 'Ó',
  'ô' => 'Ô',
  'õ' => 'Õ',
  'ö' => 'Ö',
  'ø' => 'Ø',
  'ù' => 'Ù',
  'ú' => 'Ú',
  'û' => 'Û',
  'ü' => 'Ü',
  'ý' => 'Ý',
  'þ' => 'Þ',
  'ÿ' => 'Ÿ',
  'ā' => 'Ā',
  'ă' => 'Ă',
  'ą' => 'Ą',
  'ć' => 'Ć',
  'ĉ' => 'Ĉ',
  'ċ' => 'Ċ',
  'č' => 'Č',
  'ď' => 'Ď',
  'đ' => 'Đ',
  'ē' => 'Ē',
  'ĕ' => 'Ĕ',
  'ė' => 'Ė',
  'ę' => 'Ę',
  'ě' => 'Ě',
  'ĝ' => 'Ĝ',
  'ğ' => 'Ğ',
  'ġ' => 'Ġ',
  'ģ' => 'Ģ',
  'ĥ' => 'Ĥ',
  'ħ' => 'Ħ',
  'ĩ' => 'Ĩ',
  'ī' => 'Ī',
  'ĭ' => 'Ĭ',
  'į' => 'Į',
  'ı' => 'I',
  'ĳ' => 'Ĳ',
  'ĵ' => 'Ĵ',
  'ķ' => 'Ķ',
  'ĺ' => 'Ĺ',
  'ļ' => 'Ļ',
  'ľ' => 'Ľ',
  'ŀ' => 'Ŀ',
  'ł' => 'Ł',
  'ń' => 'Ń',
  'ņ' => 'Ņ',
  'ň' => 'Ň',
  'ŋ' => 'Ŋ',
  'ō' => 'Ō',
  'ŏ' => 'Ŏ',
  'ő' => 'Ő',
  'œ' => 'Œ',
  'ŕ' => 'Ŕ',
  'ŗ' => 'Ŗ',
  'ř' => 'Ř',
  'ś' => 'Ś',
  'ŝ' => 'Ŝ',
  'ş' => 'Ş',
  'š' => 'Š',
  'ţ' => 'Ţ',
  'ť' => 'Ť',
  'ŧ' => 'Ŧ',
  'ũ' => 'Ũ',
  'ū' => 'Ū',
  'ŭ' => 'Ŭ',
  'ů' => 'Ů',
  'ű' => 'Ű',
  'ų' => 'Ų',
  'ŵ' => 'Ŵ',
  'ŷ' => 'Ŷ',
  'ź' => 'Ź',
  'ż' => 'Ż',
  'ž' => 'Ž',
  'ſ' => 'S',
  'ƀ' => 'Ƀ',
  'ƃ' => 'Ƃ',
  'ƅ' => 'Ƅ',
  'ƈ' => 'Ƈ',
  'ƌ' => 'Ƌ',
  'ƒ' => 'Ƒ',
  'ƕ' => 'Ƕ',
  'ƙ' => 'Ƙ',
  'ƚ' => 'Ƚ',
  'ƞ' => 'Ƞ',
  'ơ' => 'Ơ',
  'ƣ' => 'Ƣ',
  'ƥ' => 'Ƥ',
  'ƨ' => 'Ƨ',
  'ƭ' => 'Ƭ',
  'ư' => 'Ư',
  'ƴ' => 'Ƴ',
  'ƶ' => 'Ƶ',
  'ƹ' => 'Ƹ',
  'ƽ' => 'Ƽ',
  'ƿ' => 'Ƿ',
  'ǅ' => 'Ǆ',
  'ǆ' => 'Ǆ',
  'ǈ' => 'Ǉ',
  'ǉ' => 'Ǉ',
  'ǋ' => 'Ǌ',
  'ǌ' => 'Ǌ',
  'ǎ' => 'Ǎ',
  'ǐ' => 'Ǐ',
  'ǒ' => 'Ǒ',
  'ǔ' => 'Ǔ',
  'ǖ' => 'Ǖ',
  'ǘ' => 'Ǘ',
  'ǚ' => 'Ǚ',
  'ǜ' => 'Ǜ',
  'ǝ' => 'Ǝ',
  'ǟ' => 'Ǟ',
  'ǡ' => 'Ǡ',
  'ǣ' => 'Ǣ',
  'ǥ' => 'Ǥ',
  'ǧ' => 'Ǧ',
  'ǩ' => 'Ǩ',
  'ǫ' => 'Ǫ',
  'ǭ' => 'Ǭ',
  'ǯ' => 'Ǯ',
  'ǲ' => 'Ǳ',
  'ǳ' => 'Ǳ',
  'ǵ' => 'Ǵ',
  'ǹ' => 'Ǹ',
  'ǻ' => 'Ǻ',
  'ǽ' => 'Ǽ',
  'ǿ' => 'Ǿ',
  'ȁ' => 'Ȁ',
  'ȃ' => 'Ȃ',
  'ȅ' => 'Ȅ',
  'ȇ' => 'Ȇ',
  'ȉ' => 'Ȉ',
  'ȋ' => 'Ȋ',
  'ȍ' => 'Ȍ',
  'ȏ' => 'Ȏ',
  'ȑ' => 'Ȑ',
  'ȓ' => 'Ȓ',
  'ȕ' => 'Ȕ',
  'ȗ' => 'Ȗ',
  'ș' => 'Ș',
  'ț' => 'Ț',
  'ȝ' => 'Ȝ',
  'ȟ' => 'Ȟ',
  'ȣ' => 'Ȣ',
  'ȥ' => 'Ȥ',
  'ȧ' => 'Ȧ',
  'ȩ' => 'Ȩ',
  'ȫ' => 'Ȫ',
  'ȭ' => 'Ȭ',
  'ȯ' => 'Ȯ',
  'ȱ' => 'Ȱ',
  'ȳ' => 'Ȳ',
  'ȼ' => 'Ȼ',
  'ȿ' => 'Ȿ',
  'ɀ' => 'Ɀ',
  'ɂ' => 'Ɂ',
  'ɇ' => 'Ɇ',
  'ɉ' => 'Ɉ',
  'ɋ' => 'Ɋ',
  'ɍ' => 'Ɍ',
  'ɏ' => 'Ɏ',
  'ɐ' => 'Ɐ',
  'ɑ' => 'Ɑ',
  'ɒ' => 'Ɒ',
  'ɓ' => 'Ɓ',
  'ɔ' => 'Ɔ',
  'ɖ' => 'Ɖ',
  'ɗ' => 'Ɗ',
  'ə' => 'Ə',
  'ɛ' => 'Ɛ',
  'ɜ' => 'Ɜ',
  'ɠ' => 'Ɠ',
  'ɡ' => 'Ɡ',
  'ɣ' => 'Ɣ',
  'ɥ' => 'Ɥ',
  'ɦ' => 'Ɦ',
  'ɨ' => 'Ɨ',
  'ɩ' => 'Ɩ',
  'ɪ' => 'Ɪ',
  'ɫ' => 'Ɫ',
  'ɬ' => 'Ɬ',
  'ɯ' => 'Ɯ',
  'ɱ' => 'Ɱ',
  'ɲ' => 'Ɲ',
  'ɵ' => 'Ɵ',
  'ɽ' => 'Ɽ',
  'ʀ' => 'Ʀ',
  'ʂ' => 'Ʂ',
  'ʃ' => 'Ʃ',
  'ʇ' => 'Ʇ',
  'ʈ' => 'Ʈ',
  'ʉ' => 'Ʉ',
  'ʊ' => 'Ʊ',
  'ʋ' => 'Ʋ',
  'ʌ' => 'Ʌ',
  'ʒ' => 'Ʒ',
  'ʝ' => 'Ʝ',
  'ʞ' => 'Ʞ',
  'ͅ' => 'Ι',
  'ͱ' => 'Ͱ',
  'ͳ' => 'Ͳ',
  'ͷ' => 'Ͷ',
  'ͻ' => 'Ͻ',
  'ͼ' => 'Ͼ',
  'ͽ' => 'Ͽ',
  'ά' => 'Ά',
  'έ' => 'Έ',
  'ή' => 'Ή',
  'ί' => 'Ί',
  'α' => 'Α',
  'β' => 'Β',
  'γ' => 'Γ',
  'δ' => 'Δ',
  'ε' => 'Ε',
  'ζ' => 'Ζ',
  'η' => 'Η',
  'θ' => 'Θ',
  'ι' => 'Ι',
  'κ' => 'Κ',
  'λ' => 'Λ',
  'μ' => 'Μ',
  'ν' => 'Ν',
  'ξ' => 'Ξ',
  'ο' => 'Ο',
  'π' => 'Π',
  'ρ' => 'Ρ',
  'ς' => 'Σ',
  'σ' => 'Σ',
  'τ' => 'Τ',
  'υ' => 'Υ',
  'φ' => 'Φ',
  'χ' => 'Χ',
  'ψ' => 'Ψ',
  'ω' => 'Ω',
  'ϊ' => 'Ϊ',
  'ϋ' => 'Ϋ',
  'ό' => 'Ό',
  'ύ' => 'Ύ',
  'ώ' => 'Ώ',
  'ϐ' => 'Β',
  'ϑ' => 'Θ',
  'ϕ' => 'Φ',
  'ϖ' => 'Π',
  'ϗ' => 'Ϗ',
  'ϙ' => 'Ϙ',
  'ϛ' => 'Ϛ',
  'ϝ' => 'Ϝ',
  'ϟ' => 'Ϟ',
  'ϡ' => 'Ϡ',
  'ϣ' => 'Ϣ',
  'ϥ' => 'Ϥ',
  'ϧ' => 'Ϧ',
  'ϩ' => 'Ϩ',
  'ϫ' => 'Ϫ',
  'ϭ' => 'Ϭ',
  'ϯ' => 'Ϯ',
  'ϰ' => 'Κ',
  'ϱ' => 'Ρ',
  'ϲ' => 'Ϲ',
  'ϳ' => 'Ϳ',
  'ϵ' => 'Ε',
  'ϸ' => 'Ϸ',
  'ϻ' => 'Ϻ',
  'а' => 'А',
  'б' => 'Б',
  'в' => 'В',
  'г' => 'Г',
  'д' => 'Д',
  'е' => 'Е',
  'ж' => 'Ж',
  'з' => 'З',
  'и' => 'И',
  'й' => 'Й',
  'к' => 'К',
  'л' => 'Л',
  'м' => 'М',
  'н' => 'Н',
  'о' => 'О',
  'п' => 'П',
  'р' => 'Р',
  'с' => 'С',
  'т' => 'Т',
  'у' => 'У',
  'ф' => 'Ф',
  'х' => 'Х',
  'ц' => 'Ц',
  'ч' => 'Ч',
  'ш' => 'Ш',
  'щ' => 'Щ',
  'ъ' => 'Ъ',
  'ы' => 'Ы',
  'ь' => 'Ь',
  'э' => 'Э',
  'ю' => 'Ю',
  'я' => 'Я',
  'ѐ' => 'Ѐ',
  'ё' => 'Ё',
  'ђ' => 'Ђ',
  'ѓ' => 'Ѓ',
  'є' => 'Є',
  'ѕ' => 'Ѕ',
  'і' => 'І',
  'ї' => 'Ї',
  'ј' => 'Ј',
  'љ' => 'Љ',
  'њ' => 'Њ',
  'ћ' => 'Ћ',
  'ќ' => 'Ќ',
  'ѝ' => 'Ѝ',
  'ў' => 'Ў',
  'џ' => 'Џ',
  'ѡ' => 'Ѡ',
  'ѣ' => 'Ѣ',
  'ѥ' => 'Ѥ',
  'ѧ' => 'Ѧ',
  'ѩ' => 'Ѩ',
  'ѫ' => 'Ѫ',
  'ѭ' => 'Ѭ',
  'ѯ' => 'Ѯ',
  'ѱ' => 'Ѱ',
  'ѳ' => 'Ѳ',
  'ѵ' => 'Ѵ',
  'ѷ' => 'Ѷ',
  'ѹ' => 'Ѹ',
  'ѻ' => 'Ѻ',
  'ѽ' => 'Ѽ',
  'ѿ' => 'Ѿ',
  'ҁ' => 'Ҁ',
  'ҋ' => 'Ҋ',
  'ҍ' => 'Ҍ',
  'ҏ' => 'Ҏ',
  'ґ' => 'Ґ',
  'ғ' => 'Ғ',
  'ҕ' => 'Ҕ',
  'җ' => 'Җ',
  'ҙ' => 'Ҙ',
  'қ' => 'Қ',
  'ҝ' => 'Ҝ',
  'ҟ' => 'Ҟ',
  'ҡ' => 'Ҡ',
  'ң' => 'Ң',
  'ҥ' => 'Ҥ',
  'ҧ' => 'Ҧ',
  'ҩ' => 'Ҩ',
  'ҫ' => 'Ҫ',
  'ҭ' => 'Ҭ',
  'ү' => 'Ү',
  'ұ' => 'Ұ',
  'ҳ' => 'Ҳ',
  'ҵ' => 'Ҵ',
  'ҷ' => 'Ҷ',
  'ҹ' => 'Ҹ',
  'һ' => 'Һ',
  'ҽ' => 'Ҽ',
  'ҿ' => 'Ҿ',
  'ӂ' => 'Ӂ',
  'ӄ' => 'Ӄ',
  'ӆ' => 'Ӆ',
  'ӈ' => 'Ӈ',
  'ӊ' => 'Ӊ',
  'ӌ' => 'Ӌ',
  'ӎ' => 'Ӎ',
  'ӏ' => 'Ӏ',
  'ӑ' => 'Ӑ',
  'ӓ' => 'Ӓ',
  'ӕ' => 'Ӕ',
  'ӗ' => 'Ӗ',
  'ә' => 'Ә',
  'ӛ' => 'Ӛ',
  'ӝ' => 'Ӝ',
  'ӟ' => 'Ӟ',
  'ӡ' => 'Ӡ',
  'ӣ' => 'Ӣ',
  'ӥ' => 'Ӥ',
  'ӧ' => 'Ӧ',
  'ө' => 'Ө',
  'ӫ' => 'Ӫ',
  'ӭ' => 'Ӭ',
  'ӯ' => 'Ӯ',
  'ӱ' => 'Ӱ',
  'ӳ' => 'Ӳ',
  'ӵ' => 'Ӵ',
  'ӷ' => 'Ӷ',
  'ӹ' => 'Ӹ',
  'ӻ' => 'Ӻ',
  'ӽ' => 'Ӽ',
  'ӿ' => 'Ӿ',
  'ԁ' => 'Ԁ',
  'ԃ' => 'Ԃ',
  'ԅ' => 'Ԅ',
  'ԇ' => 'Ԇ',
  'ԉ' => 'Ԉ',
  'ԋ' => 'Ԋ',
  'ԍ' => 'Ԍ',
  'ԏ' => 'Ԏ',
  'ԑ' => 'Ԑ',
  'ԓ' => 'Ԓ',
  'ԕ' => 'Ԕ',
  'ԗ' => 'Ԗ',
  'ԙ' => 'Ԙ',
  'ԛ' => 'Ԛ',
  'ԝ' => 'Ԝ',
  'ԟ' => 'Ԟ',
  'ԡ' => 'Ԡ',
  'ԣ' => 'Ԣ',
  'ԥ' => 'Ԥ',
  'ԧ' => 'Ԧ',
  'ԩ' => 'Ԩ',
  'ԫ' => 'Ԫ',
  'ԭ' => 'Ԭ',
  'ԯ' => 'Ԯ',
  'ա' => 'Ա',
  'բ' => 'Բ',
  'գ' => 'Գ',
  'դ' => 'Դ',
  'ե' => 'Ե',
  'զ' => 'Զ',
  'է' => 'Է',
  'ը' => 'Ը',
  'թ' => 'Թ',
  'ժ' => 'Ժ',
  'ի' => 'Ի',
  'լ' => 'Լ',
  'խ' => 'Խ',
  'ծ' => 'Ծ',
  'կ' => 'Կ',
  'հ' => 'Հ',
  'ձ' => 'Ձ',
  'ղ' => 'Ղ',
  'ճ' => 'Ճ',
  'մ' => 'Մ',
  'յ' => 'Յ',
  'ն' => 'Ն',
  'շ' => 'Շ',
  'ո' => 'Ո',
  'չ' => 'Չ',
  'պ' => 'Պ',
  'ջ' => 'Ջ',
  'ռ' => 'Ռ',
  'ս' => 'Ս',
  'վ' => 'Վ',
  'տ' => 'Տ',
  'ր' => 'Ր',
  'ց' => 'Ց',
  'ւ' => 'Ւ',
  'փ' => 'Փ',
  'ք' => 'Ք',
  'օ' => 'Օ',
  'ֆ' => 'Ֆ',
  'ა' => 'Ა',
  'ბ' => 'Ბ',
  'გ' => 'Გ',
  'დ' => 'Დ',
  'ე' => 'Ე',
  'ვ' => 'Ვ',
  'ზ' => 'Ზ',
  'თ' => 'Თ',
  'ი' => 'Ი',
  'კ' => 'Კ',
  'ლ' => 'Ლ',
  'მ' => 'Მ',
  'ნ' => 'Ნ',
  'ო' => 'Ო',
  'პ' => 'Პ',
  'ჟ' => 'Ჟ',
  'რ' => 'Რ',
  'ს' => 'Ს',
  'ტ' => 'Ტ',
  'უ' => 'Უ',
  'ფ' => 'Ფ',
  'ქ' => 'Ქ',
  'ღ' => 'Ღ',
  'ყ' => 'Ყ',
  'შ' => 'Შ',
  'ჩ' => 'Ჩ',
  'ც' => 'Ც',
  'ძ' => 'Ძ',
  'წ' => 'Წ',
  'ჭ' => 'Ჭ',
  'ხ' => 'Ხ',
  'ჯ' => 'Ჯ',
  'ჰ' => 'Ჰ',
  'ჱ' => 'Ჱ',
  'ჲ' => 'Ჲ',
  'ჳ' => 'Ჳ',
  'ჴ' => 'Ჴ',
  'ჵ' => 'Ჵ',
  'ჶ' => 'Ჶ',
  'ჷ' => 'Ჷ',
  'ჸ' => 'Ჸ',
  'ჹ' => 'Ჹ',
  'ჺ' => 'Ჺ',
  'ჽ' => 'Ჽ',
  'ჾ' => 'Ჾ',
  'ჿ' => 'Ჿ',
  'ᏸ' => 'Ᏸ',
  'ᏹ' => 'Ᏹ',
  'ᏺ' => 'Ᏺ',
  'ᏻ' => 'Ᏻ',
  'ᏼ' => 'Ᏼ',
  'ᏽ' => 'Ᏽ',
  'ᲀ' => 'В',
  'ᲁ' => 'Д',
  'ᲂ' => 'О',
  'ᲃ' => 'С',
  'ᲄ' => 'Т',
  'ᲅ' => 'Т',
  'ᲆ' => 'Ъ',
  'ᲇ' => 'Ѣ',
  'ᲈ' => 'Ꙋ',
  'ᵹ' => 'Ᵹ',
  'ᵽ' => 'Ᵽ',
  'ᶎ' => 'Ᶎ',
  'ḁ' => 'Ḁ',
  'ḃ' => 'Ḃ',
  'ḅ' => 'Ḅ',
  'ḇ' => 'Ḇ',
  'ḉ' => 'Ḉ',
  'ḋ' => 'Ḋ',
  'ḍ' => 'Ḍ',
  'ḏ' => 'Ḏ',
  'ḑ' => 'Ḑ',
  'ḓ' => 'Ḓ',
  'ḕ' => 'Ḕ',
  'ḗ' => 'Ḗ',
  'ḙ' => 'Ḙ',
  'ḛ' => 'Ḛ',
  'ḝ' => 'Ḝ',
  'ḟ' => 'Ḟ',
  'ḡ' => 'Ḡ',
  'ḣ' => 'Ḣ',
  'ḥ' => 'Ḥ',
  'ḧ' => 'Ḧ',
  'ḩ' => 'Ḩ',
  'ḫ' => 'Ḫ',
  'ḭ' => 'Ḭ',
  'ḯ' => 'Ḯ',
  'ḱ' => 'Ḱ',
  'ḳ' => 'Ḳ',
  'ḵ' => 'Ḵ',
  'ḷ' => 'Ḷ',
  'ḹ' => 'Ḹ',
  'ḻ' => 'Ḻ',
  'ḽ' => 'Ḽ',
  'ḿ' => 'Ḿ',
  'ṁ' => 'Ṁ',
  'ṃ' => 'Ṃ',
  'ṅ' => 'Ṅ',
  'ṇ' => 'Ṇ',
  'ṉ' => 'Ṉ',
  'ṋ' => 'Ṋ',
  'ṍ' => 'Ṍ',
  'ṏ' => 'Ṏ',
  'ṑ' => 'Ṑ',
  'ṓ' => 'Ṓ',
  'ṕ' => 'Ṕ',
  'ṗ' => 'Ṗ',
  'ṙ' => 'Ṙ',
  'ṛ' => 'Ṛ',
  'ṝ' => 'Ṝ',
  'ṟ' => 'Ṟ',
  'ṡ' => 'Ṡ',
  'ṣ' => 'Ṣ',
  'ṥ' => 'Ṥ',
  'ṧ' => 'Ṧ',
  'ṩ' => 'Ṩ',
  'ṫ' => 'Ṫ',
  'ṭ' => 'Ṭ',
  'ṯ' => 'Ṯ',
  'ṱ' => 'Ṱ',
  'ṳ' => 'Ṳ',
  'ṵ' => 'Ṵ',
  'ṷ' => 'Ṷ',
  'ṹ' => 'Ṹ',
  'ṻ' => 'Ṻ',
  'ṽ' => 'Ṽ',
  'ṿ' => 'Ṿ',
  'ẁ' => 'Ẁ',
  'ẃ' => 'Ẃ',
  'ẅ' => 'Ẅ',
  'ẇ' => 'Ẇ',
  'ẉ' => 'Ẉ',
  'ẋ' => 'Ẋ',
  'ẍ' => 'Ẍ',
  'ẏ' => 'Ẏ',
  'ẑ' => 'Ẑ',
  'ẓ' => 'Ẓ',
  'ẕ' => 'Ẕ',
  'ẛ' => 'Ṡ',
  'ạ' => 'Ạ',
  'ả' => 'Ả',
  'ấ' => 'Ấ',
  'ầ' => 'Ầ',
  'ẩ' => 'Ẩ',
  'ẫ' => 'Ẫ',
  'ậ' => 'Ậ',
  'ắ' => 'Ắ',
  'ằ' => 'Ằ',
  'ẳ' => 'Ẳ',
  'ẵ' => 'Ẵ',
  'ặ' => 'Ặ',
  'ẹ' => 'Ẹ',
  'ẻ' => 'Ẻ',
  'ẽ' => 'Ẽ',
  'ế' => 'Ế',
  'ề' => 'Ề',
  'ể' => 'Ể',
  'ễ' => 'Ễ',
  'ệ' => 'Ệ',
  'ỉ' => 'Ỉ',
  'ị' => 'Ị',
  'ọ' => 'Ọ',
  'ỏ' => 'Ỏ',
  'ố' => 'Ố',
  'ồ' => 'Ồ',
  'ổ' => 'Ổ',
  'ỗ' => 'Ỗ',
  'ộ' => 'Ộ',
  'ớ' => 'Ớ',
  'ờ' => 'Ờ',
  'ở' => 'Ở',
  'ỡ' => 'Ỡ',
  'ợ' => 'Ợ',
  'ụ' => 'Ụ',
  'ủ' => 'Ủ',
  'ứ' => 'Ứ',
  'ừ' => 'Ừ',
  'ử' => 'Ử',
  'ữ' => 'Ữ',
  'ự' => 'Ự',
  'ỳ' => 'Ỳ',
  'ỵ' => 'Ỵ',
  'ỷ' => 'Ỷ',
  'ỹ' => 'Ỹ',
  'ỻ' => 'Ỻ',
  'ỽ' => 'Ỽ',
  'ỿ' => 'Ỿ',
  'ἀ' => 'Ἀ',
  'ἁ' => 'Ἁ',
  'ἂ' => 'Ἂ',
  'ἃ' => 'Ἃ',
  'ἄ' => 'Ἄ',
  'ἅ' => 'Ἅ',
  'ἆ' => 'Ἆ',
  'ἇ' => 'Ἇ',
  'ἐ' => 'Ἐ',
  'ἑ' => 'Ἑ',
  'ἒ' => 'Ἒ',
  'ἓ' => 'Ἓ',
  'ἔ' => 'Ἔ',
  'ἕ' => 'Ἕ',
  'ἠ' => 'Ἠ',
  'ἡ' => 'Ἡ',
  'ἢ' => 'Ἢ',
  'ἣ' => 'Ἣ',
  'ἤ' => 'Ἤ',
  'ἥ' => 'Ἥ',
  'ἦ' => 'Ἦ',
  'ἧ' => 'Ἧ',
  'ἰ' => 'Ἰ',
  'ἱ' => 'Ἱ',
  'ἲ' => 'Ἲ',
  'ἳ' => 'Ἳ',
  'ἴ' => 'Ἴ',
  'ἵ' => 'Ἵ',
  'ἶ' => 'Ἶ',
  'ἷ' => 'Ἷ',
  'ὀ' => 'Ὀ',
  'ὁ' => 'Ὁ',
  'ὂ' => 'Ὂ',
  'ὃ' => 'Ὃ',
  'ὄ' => 'Ὄ',
  'ὅ' => 'Ὅ',
  'ὑ' => 'Ὑ',
  'ὓ' => 'Ὓ',
  'ὕ' => 'Ὕ',
  'ὗ' => 'Ὗ',
  'ὠ' => 'Ὠ',
  'ὡ' => 'Ὡ',
  'ὢ' => 'Ὢ',
  'ὣ' => 'Ὣ',
  'ὤ' => 'Ὤ',
  'ὥ' => 'Ὥ',
  'ὦ' => 'Ὦ',
  'ὧ' => 'Ὧ',
  'ὰ' => 'Ὰ',
  'ά' => 'Ά',
  'ὲ' => 'Ὲ',
  'έ' => 'Έ',
  'ὴ' => 'Ὴ',
  'ή' => 'Ή',
  'ὶ' => 'Ὶ',
  'ί' => 'Ί',
  'ὸ' => 'Ὸ',
  'ό' => 'Ό',
  'ὺ' => 'Ὺ',
  'ύ' => 'Ύ',
  'ὼ' => 'Ὼ',
  'ώ' => 'Ώ',
  'ᾀ' => 'ἈΙ',
  'ᾁ' => 'ἉΙ',
  'ᾂ' => 'ἊΙ',
  'ᾃ' => 'ἋΙ',
  'ᾄ' => 'ἌΙ',
  'ᾅ' => 'ἍΙ',
  'ᾆ' => 'ἎΙ',
  'ᾇ' => 'ἏΙ',
  'ᾐ' => 'ἨΙ',
  'ᾑ' => 'ἩΙ',
  'ᾒ' => 'ἪΙ',
  'ᾓ' => 'ἫΙ',
  'ᾔ' => 'ἬΙ',
  'ᾕ' => 'ἭΙ',
  'ᾖ' => 'ἮΙ',
  'ᾗ' => 'ἯΙ',
  'ᾠ' => 'ὨΙ',
  'ᾡ' => 'ὩΙ',
  'ᾢ' => 'ὪΙ',
  'ᾣ' => 'ὫΙ',
  'ᾤ' => 'ὬΙ',
  'ᾥ' => 'ὭΙ',
  'ᾦ' => 'ὮΙ',
  'ᾧ' => 'ὯΙ',
  'ᾰ' => 'Ᾰ',
  'ᾱ' => 'Ᾱ',
  'ᾳ' => 'ΑΙ',
  'ι' => 'Ι',
  'ῃ' => 'ΗΙ',
  'ῐ' => 'Ῐ',
  'ῑ' => 'Ῑ',
  'ῠ' => 'Ῠ',
  'ῡ' => 'Ῡ',
  'ῥ' => 'Ῥ',
  'ῳ' => 'ΩΙ',
  'ⅎ' => 'Ⅎ',
  'ⅰ' => 'Ⅰ',
  'ⅱ' => 'Ⅱ',
  'ⅲ' => 'Ⅲ',
  'ⅳ' => 'Ⅳ',
  'ⅴ' => 'Ⅴ',
  'ⅵ' => 'Ⅵ',
  'ⅶ' => 'Ⅶ',
  'ⅷ' => 'Ⅷ',
  'ⅸ' => 'Ⅸ',
  'ⅹ' => 'Ⅹ',
  'ⅺ' => 'Ⅺ',
  'ⅻ' => 'Ⅻ',
  'ⅼ' => 'Ⅼ',
  'ⅽ' => 'Ⅽ',
  'ⅾ' => 'Ⅾ',
  'ⅿ' => 'Ⅿ',
  'ↄ' => 'Ↄ',
  'ⓐ' => 'Ⓐ',
  'ⓑ' => 'Ⓑ',
  'ⓒ' => 'Ⓒ',
  'ⓓ' => 'Ⓓ',
  'ⓔ' => 'Ⓔ',
  'ⓕ' => 'Ⓕ',
  'ⓖ' => 'Ⓖ',
  'ⓗ' => 'Ⓗ',
  'ⓘ' => 'Ⓘ',
  'ⓙ' => 'Ⓙ',
  'ⓚ' => 'Ⓚ',
  'ⓛ' => 'Ⓛ',
  'ⓜ' => 'Ⓜ',
  'ⓝ' => 'Ⓝ',
  'ⓞ' => 'Ⓞ',
  'ⓟ' => 'Ⓟ',
  'ⓠ' => 'Ⓠ',
  'ⓡ' => 'Ⓡ',
  'ⓢ' => 'Ⓢ',
  'ⓣ' => 'Ⓣ',
  'ⓤ' => 'Ⓤ',
  'ⓥ' => 'Ⓥ',
  'ⓦ' => 'Ⓦ',
  'ⓧ' => 'Ⓧ',
  'ⓨ' => 'Ⓨ',
  'ⓩ' => 'Ⓩ',
  'ⰰ' => 'Ⰰ',
  'ⰱ' => 'Ⰱ',
  'ⰲ' => 'Ⰲ',
  'ⰳ' => 'Ⰳ',
  'ⰴ' => 'Ⰴ',
  'ⰵ' => 'Ⰵ',
  'ⰶ' => 'Ⰶ',
  'ⰷ' => 'Ⰷ',
  'ⰸ' => 'Ⰸ',
  'ⰹ' => 'Ⰹ',
  'ⰺ' => 'Ⰺ',
  'ⰻ' => 'Ⰻ',
  'ⰼ' => 'Ⰼ',
  'ⰽ' => 'Ⰽ',
  'ⰾ' => 'Ⰾ',
  'ⰿ' => 'Ⰿ',
  'ⱀ' => 'Ⱀ',
  'ⱁ' => 'Ⱁ',
  'ⱂ' => 'Ⱂ',
  'ⱃ' => 'Ⱃ',
  'ⱄ' => 'Ⱄ',
  'ⱅ' => 'Ⱅ',
  'ⱆ' => 'Ⱆ',
  'ⱇ' => 'Ⱇ',
  'ⱈ' => 'Ⱈ',
  'ⱉ' => 'Ⱉ',
  'ⱊ' => 'Ⱊ',
  'ⱋ' => 'Ⱋ',
  'ⱌ' => 'Ⱌ',
  'ⱍ' => 'Ⱍ',
  'ⱎ' => 'Ⱎ',
  'ⱏ' => 'Ⱏ',
  'ⱐ' => 'Ⱐ',
  'ⱑ' => 'Ⱑ',
  'ⱒ' => 'Ⱒ',
  'ⱓ' => 'Ⱓ',
  'ⱔ' => 'Ⱔ',
  'ⱕ' => 'Ⱕ',
  'ⱖ' => 'Ⱖ',
  'ⱗ' => 'Ⱗ',
  'ⱘ' => 'Ⱘ',
  'ⱙ' => 'Ⱙ',
  'ⱚ' => 'Ⱚ',
  'ⱛ' => 'Ⱛ',
  'ⱜ' => 'Ⱜ',
  'ⱝ' => 'Ⱝ',
  'ⱞ' => 'Ⱞ',
  'ⱡ' => 'Ⱡ',
  'ⱥ' => 'Ⱥ',
  'ⱦ' => 'Ⱦ',
  'ⱨ' => 'Ⱨ',
  'ⱪ' => 'Ⱪ',
  'ⱬ' => 'Ⱬ',
  'ⱳ' => 'Ⱳ',
  'ⱶ' => 'Ⱶ',
  'ⲁ' => 'Ⲁ',
  'ⲃ' => 'Ⲃ',
  'ⲅ' => 'Ⲅ',
  'ⲇ' => 'Ⲇ',
  'ⲉ' => 'Ⲉ',
  'ⲋ' => 'Ⲋ',
  'ⲍ' => 'Ⲍ',
  'ⲏ' => 'Ⲏ',
  'ⲑ' => 'Ⲑ',
  'ⲓ' => 'Ⲓ',
  'ⲕ' => 'Ⲕ',
  'ⲗ' => 'Ⲗ',
  'ⲙ' => 'Ⲙ',
  'ⲛ' => 'Ⲛ',
  'ⲝ' => 'Ⲝ',
  'ⲟ' => 'Ⲟ',
  'ⲡ' => 'Ⲡ',
  'ⲣ' => 'Ⲣ',
  'ⲥ' => 'Ⲥ',
  'ⲧ' => 'Ⲧ',
  'ⲩ' => 'Ⲩ',
  'ⲫ' => 'Ⲫ',
  'ⲭ' => 'Ⲭ',
  'ⲯ' => 'Ⲯ',
  'ⲱ' => 'Ⲱ',
  'ⲳ' => 'Ⲳ',
  'ⲵ' => 'Ⲵ',
  'ⲷ' => 'Ⲷ',
  'ⲹ' => 'Ⲹ',
  'ⲻ' => 'Ⲻ',
  'ⲽ' => 'Ⲽ',
  'ⲿ' => 'Ⲿ',
  'ⳁ' => 'Ⳁ',
  'ⳃ' => 'Ⳃ',
  'ⳅ' => 'Ⳅ',
  'ⳇ' => 'Ⳇ',
  'ⳉ' => 'Ⳉ',
  'ⳋ' => 'Ⳋ',
  'ⳍ' => 'Ⳍ',
  'ⳏ' => 'Ⳏ',
  'ⳑ' => 'Ⳑ',
  'ⳓ' => 'Ⳓ',
  'ⳕ' => 'Ⳕ',
  'ⳗ' => 'Ⳗ',
  'ⳙ' => 'Ⳙ',
  'ⳛ' => 'Ⳛ',
  'ⳝ' => 'Ⳝ',
  'ⳟ' => 'Ⳟ',
  'ⳡ' => 'Ⳡ',
  'ⳣ' => 'Ⳣ',
  'ⳬ' => 'Ⳬ',
  'ⳮ' => 'Ⳮ',
  'ⳳ' => 'Ⳳ',
  'ⴀ' => 'Ⴀ',
  'ⴁ' => 'Ⴁ',
  'ⴂ' => 'Ⴂ',
  'ⴃ' => 'Ⴃ',
  'ⴄ' => 'Ⴄ',
  'ⴅ' => 'Ⴅ',
  'ⴆ' => 'Ⴆ',
  'ⴇ' => 'Ⴇ',
  'ⴈ' => 'Ⴈ',
  'ⴉ' => 'Ⴉ',
  'ⴊ' => 'Ⴊ',
  'ⴋ' => 'Ⴋ',
  'ⴌ' => 'Ⴌ',
  'ⴍ' => 'Ⴍ',
  'ⴎ' => 'Ⴎ',
  'ⴏ' => 'Ⴏ',
  'ⴐ' => 'Ⴐ',
  'ⴑ' => 'Ⴑ',
  'ⴒ' => 'Ⴒ',
  'ⴓ' => 'Ⴓ',
  'ⴔ' => 'Ⴔ',
  'ⴕ' => 'Ⴕ',
  'ⴖ' => 'Ⴖ',
  'ⴗ' => 'Ⴗ',
  'ⴘ' => 'Ⴘ',
  'ⴙ' => 'Ⴙ',
  'ⴚ' => 'Ⴚ',
  'ⴛ' => 'Ⴛ',
  'ⴜ' => 'Ⴜ',
  'ⴝ' => 'Ⴝ',
  'ⴞ' => 'Ⴞ',
  'ⴟ' => 'Ⴟ',
  'ⴠ' => 'Ⴠ',
  'ⴡ' => 'Ⴡ',
  'ⴢ' => 'Ⴢ',
  'ⴣ' => 'Ⴣ',
  'ⴤ' => 'Ⴤ',
  'ⴥ' => 'Ⴥ',
  'ⴧ' => 'Ⴧ',
  'ⴭ' => 'Ⴭ',
  'ꙁ' => 'Ꙁ',
  'ꙃ' => 'Ꙃ',
  'ꙅ' => 'Ꙅ',
  'ꙇ' => 'Ꙇ',
  'ꙉ' => 'Ꙉ',
  'ꙋ' => 'Ꙋ',
  'ꙍ' => 'Ꙍ',
  'ꙏ' => 'Ꙏ',
  'ꙑ' => 'Ꙑ',
  'ꙓ' => 'Ꙓ',
  'ꙕ' => 'Ꙕ',
  'ꙗ' => 'Ꙗ',
  'ꙙ' => 'Ꙙ',
  'ꙛ' => 'Ꙛ',
  'ꙝ' => 'Ꙝ',
  'ꙟ' => 'Ꙟ',
  'ꙡ' => 'Ꙡ',
  'ꙣ' => 'Ꙣ',
  'ꙥ' => 'Ꙥ',
  'ꙧ' => 'Ꙧ',
  'ꙩ' => 'Ꙩ',
  'ꙫ' => 'Ꙫ',
  'ꙭ' => 'Ꙭ',
  'ꚁ' => 'Ꚁ',
  'ꚃ' => 'Ꚃ',
  'ꚅ' => 'Ꚅ',
  'ꚇ' => 'Ꚇ',
  'ꚉ' => 'Ꚉ',
  'ꚋ' => 'Ꚋ',
  'ꚍ' => 'Ꚍ',
  'ꚏ' => 'Ꚏ',
  'ꚑ' => 'Ꚑ',
  'ꚓ' => 'Ꚓ',
  'ꚕ' => 'Ꚕ',
  'ꚗ' => 'Ꚗ',
  'ꚙ' => 'Ꚙ',
  'ꚛ' => 'Ꚛ',
  'ꜣ' => 'Ꜣ',
  'ꜥ' => 'Ꜥ',
  'ꜧ' => 'Ꜧ',
  'ꜩ' => 'Ꜩ',
  'ꜫ' => 'Ꜫ',
  'ꜭ' => 'Ꜭ',
  'ꜯ' => 'Ꜯ',
  'ꜳ' => 'Ꜳ',
  'ꜵ' => 'Ꜵ',
  'ꜷ' => 'Ꜷ',
  'ꜹ' => 'Ꜹ',
  'ꜻ' => 'Ꜻ',
  'ꜽ' => 'Ꜽ',
  'ꜿ' => 'Ꜿ',
  'ꝁ' => 'Ꝁ',
  'ꝃ' => 'Ꝃ',
  'ꝅ' => 'Ꝅ',
  'ꝇ' => 'Ꝇ',
  'ꝉ' => 'Ꝉ',
  'ꝋ' => 'Ꝋ',
  'ꝍ' => 'Ꝍ',
  'ꝏ' => 'Ꝏ',
  'ꝑ' => 'Ꝑ',
  'ꝓ' => 'Ꝓ',
  'ꝕ' => 'Ꝕ',
  'ꝗ' => 'Ꝗ',
  'ꝙ' => 'Ꝙ',
  'ꝛ' => 'Ꝛ',
  'ꝝ' => 'Ꝝ',
  'ꝟ' => 'Ꝟ',
  'ꝡ' => 'Ꝡ',
  'ꝣ' => 'Ꝣ',
  'ꝥ' => 'Ꝥ',
  'ꝧ' => 'Ꝧ',
  'ꝩ' => 'Ꝩ',
  'ꝫ' => 'Ꝫ',
  'ꝭ' => 'Ꝭ',
  'ꝯ' => 'Ꝯ',
  'ꝺ' => 'Ꝺ',
  'ꝼ' => 'Ꝼ',
  'ꝿ' => 'Ꝿ',
  'ꞁ' => 'Ꞁ',
  'ꞃ' => 'Ꞃ',
  'ꞅ' => 'Ꞅ',
  'ꞇ' => 'Ꞇ',
  'ꞌ' => 'Ꞌ',
  'ꞑ' => 'Ꞑ',
  'ꞓ' => 'Ꞓ',
  'ꞔ' => 'Ꞔ',
  'ꞗ' => 'Ꞗ',
  'ꞙ' => 'Ꞙ',
  'ꞛ' => 'Ꞛ',
  'ꞝ' => 'Ꞝ',
  'ꞟ' => 'Ꞟ',
  'ꞡ' => 'Ꞡ',
  'ꞣ' => 'Ꞣ',
  'ꞥ' => 'Ꞥ',
  'ꞧ' => 'Ꞧ',
  'ꞩ' => 'Ꞩ',
  'ꞵ' => 'Ꞵ',
  'ꞷ' => 'Ꞷ',
  'ꞹ' => 'Ꞹ',
  'ꞻ' => 'Ꞻ',
  'ꞽ' => 'Ꞽ',
  'ꞿ' => 'Ꞿ',
  'ꟃ' => 'Ꟃ',
  'ꟈ' => 'Ꟈ',
  'ꟊ' => 'Ꟊ',
  'ꟶ' => 'Ꟶ',
  'ꭓ' => 'Ꭓ',
  'ꭰ' => 'Ꭰ',
  'ꭱ' => 'Ꭱ',
  'ꭲ' => 'Ꭲ',
  'ꭳ' => 'Ꭳ',
  'ꭴ' => 'Ꭴ',
  'ꭵ' => 'Ꭵ',
  'ꭶ' => 'Ꭶ',
  'ꭷ' => 'Ꭷ',
  'ꭸ' => 'Ꭸ',
  'ꭹ' => 'Ꭹ',
  'ꭺ' => 'Ꭺ',
  'ꭻ' => 'Ꭻ',
  'ꭼ' => 'Ꭼ',
  'ꭽ' => 'Ꭽ',
  'ꭾ' => 'Ꭾ',
  'ꭿ' => 'Ꭿ',
  'ꮀ' => 'Ꮀ',
  'ꮁ' => 'Ꮁ',
  'ꮂ' => 'Ꮂ',
  'ꮃ' => 'Ꮃ',
  'ꮄ' => 'Ꮄ',
  'ꮅ' => 'Ꮅ',
  'ꮆ' => 'Ꮆ',
  'ꮇ' => 'Ꮇ',
  'ꮈ' => 'Ꮈ',
  'ꮉ' => 'Ꮉ',
  'ꮊ' => 'Ꮊ',
  'ꮋ' => 'Ꮋ',
  'ꮌ' => 'Ꮌ',
  'ꮍ' => 'Ꮍ',
  'ꮎ' => 'Ꮎ',
  'ꮏ' => 'Ꮏ',
  'ꮐ' => 'Ꮐ',
  'ꮑ' => 'Ꮑ',
  'ꮒ' => 'Ꮒ',
  'ꮓ' => 'Ꮓ',
  'ꮔ' => 'Ꮔ',
  'ꮕ' => 'Ꮕ',
  'ꮖ' => 'Ꮖ',
  'ꮗ' => 'Ꮗ',
  'ꮘ' => 'Ꮘ',
  'ꮙ' => 'Ꮙ',
  'ꮚ' => 'Ꮚ',
  'ꮛ' => 'Ꮛ',
  'ꮜ' => 'Ꮜ',
  'ꮝ' => 'Ꮝ',
  'ꮞ' => 'Ꮞ',
  'ꮟ' => 'Ꮟ',
  'ꮠ' => 'Ꮠ',
  'ꮡ' => 'Ꮡ',
  'ꮢ' => 'Ꮢ',
  'ꮣ' => 'Ꮣ',
  'ꮤ' => 'Ꮤ',
  'ꮥ' => 'Ꮥ',
  'ꮦ' => 'Ꮦ',
  'ꮧ' => 'Ꮧ',
  'ꮨ' => 'Ꮨ',
  'ꮩ' => 'Ꮩ',
  'ꮪ' => 'Ꮪ',
  'ꮫ' => 'Ꮫ',
  'ꮬ' => 'Ꮬ',
  'ꮭ' => 'Ꮭ',
  'ꮮ' => 'Ꮮ',
  'ꮯ' => 'Ꮯ',
  'ꮰ' => 'Ꮰ',
  'ꮱ' => 'Ꮱ',
  'ꮲ' => 'Ꮲ',
  'ꮳ' => 'Ꮳ',
  'ꮴ' => 'Ꮴ',
  'ꮵ' => 'Ꮵ',
  'ꮶ' => 'Ꮶ',
  'ꮷ' => 'Ꮷ',
  'ꮸ' => 'Ꮸ',
  'ꮹ' => 'Ꮹ',
  'ꮺ' => 'Ꮺ',
  'ꮻ' => 'Ꮻ',
  'ꮼ' => 'Ꮼ',
  'ꮽ' => 'Ꮽ',
  'ꮾ' => 'Ꮾ',
  'ꮿ' => 'Ꮿ',
  'ａ' => 'Ａ',
  'ｂ' => 'Ｂ',
  'ｃ' => 'Ｃ',
  'ｄ' => 'Ｄ',
  'ｅ' => 'Ｅ',
  'ｆ' => 'Ｆ',
  'ｇ' => 'Ｇ',
  'ｈ' => 'Ｈ',
  'ｉ' => 'Ｉ',
  'ｊ' => 'Ｊ',
  'ｋ' => 'Ｋ',
  'ｌ' => 'Ｌ',
  'ｍ' => 'Ｍ',
  'ｎ' => 'Ｎ',
  'ｏ' => 'Ｏ',
  'ｐ' => 'Ｐ',
  'ｑ' => 'Ｑ',
  'ｒ' => 'Ｒ',
  'ｓ' => 'Ｓ',
  'ｔ' => 'Ｔ',
  'ｕ' => 'Ｕ',
  'ｖ' => 'Ｖ',
  'ｗ' => 'Ｗ',
  'ｘ' => 'Ｘ',
  'ｙ' => 'Ｙ',
  'ｚ' => 'Ｚ',
  '𐐨' => '𐐀',
  '𐐩' => '𐐁',
  '𐐪' => '𐐂',
  '𐐫' => '𐐃',
  '𐐬' => '𐐄',
  '𐐭' => '𐐅',
  '𐐮' => '𐐆',
  '𐐯' => '𐐇',
  '𐐰' => '𐐈',
  '𐐱' => '𐐉',
  '𐐲' => '𐐊',
  '𐐳' => '𐐋',
  '𐐴' => '𐐌',
  '𐐵' => '𐐍',
  '𐐶' => '𐐎',
  '𐐷' => '𐐏',
  '𐐸' => '𐐐',
  '𐐹' => '𐐑',
  '𐐺' => '𐐒',
  '𐐻' => '𐐓',
  '𐐼' => '𐐔',
  '𐐽' => '𐐕',
  '𐐾' => '𐐖',
  '𐐿' => '𐐗',
  '𐑀' => '𐐘',
  '𐑁' => '𐐙',
  '𐑂' => '𐐚',
  '𐑃' => '𐐛',
  '𐑄' => '𐐜',
  '𐑅' => '𐐝',
  '𐑆' => '𐐞',
  '𐑇' => '𐐟',
  '𐑈' => '𐐠',
  '𐑉' => '𐐡',
  '𐑊' => '𐐢',
  '𐑋' => '𐐣',
  '𐑌' => '𐐤',
  '𐑍' => '𐐥',
  '𐑎' => '𐐦',
  '𐑏' => '𐐧',
  '𐓘' => '𐒰',
  '𐓙' => '𐒱',
  '𐓚' => '𐒲',
  '𐓛' => '𐒳',
  '𐓜' => '𐒴',
  '𐓝' => '𐒵',
  '𐓞' => '𐒶',
  '𐓟' => '𐒷',
  '𐓠' => '𐒸',
  '𐓡' => '𐒹',
  '𐓢' => '𐒺',
  '𐓣' => '𐒻',
  '𐓤' => '𐒼',
  '𐓥' => '𐒽',
  '𐓦' => '𐒾',
  '𐓧' => '𐒿',
  '𐓨' => '𐓀',
  '𐓩' => '𐓁',
  '𐓪' => '𐓂',
  '𐓫' => '𐓃',
  '𐓬' => '𐓄',
  '𐓭' => '𐓅',
  '𐓮' => '𐓆',
  '𐓯' => '𐓇',
  '𐓰' => '𐓈',
  '𐓱' => '𐓉',
  '𐓲' => '𐓊',
  '𐓳' => '𐓋',
  '𐓴' => '𐓌',
  '𐓵' => '𐓍',
  '𐓶' => '𐓎',
  '𐓷' => '𐓏',
  '𐓸' => '𐓐',
  '𐓹' => '𐓑',
  '𐓺' => '𐓒',
  '𐓻' => '𐓓',
  '𐳀' => '𐲀',
  '𐳁' => '𐲁',
  '𐳂' => '𐲂',
  '𐳃' => '𐲃',
  '𐳄' => '𐲄',
  '𐳅' => '𐲅',
  '𐳆' => '𐲆',
  '𐳇' => '𐲇',
  '𐳈' => '𐲈',
  '𐳉' => '𐲉',
  '𐳊' => '𐲊',
  '𐳋' => '𐲋',
  '𐳌' => '𐲌',
  '𐳍' => '𐲍',
  '𐳎' => '𐲎',
  '𐳏' => '𐲏',
  '𐳐' => '𐲐',
  '𐳑' => '𐲑',
  '𐳒' => '𐲒',
  '𐳓' => '𐲓',
  '𐳔' => '𐲔',
  '𐳕' => '𐲕',
  '𐳖' => '𐲖',
  '𐳗' => '𐲗',
  '𐳘' => '𐲘',
  '𐳙' => '𐲙',
  '𐳚' => '𐲚',
  '𐳛' => '𐲛',
  '𐳜' => '𐲜',
  '𐳝' => '𐲝',
  '𐳞' => '𐲞',
  '𐳟' => '𐲟',
  '𐳠' => '𐲠',
  '𐳡' => '𐲡',
  '𐳢' => '𐲢',
  '𐳣' => '𐲣',
  '𐳤' => '𐲤',
  '𐳥' => '𐲥',
  '𐳦' => '𐲦',
  '𐳧' => '𐲧',
  '𐳨' => '𐲨',
  '𐳩' => '𐲩',
  '𐳪' => '𐲪',
  '𐳫' => '𐲫',
  '𐳬' => '𐲬',
  '𐳭' => '𐲭',
  '𐳮' => '𐲮',
  '𐳯' => '𐲯',
  '𐳰' => '𐲰',
  '𐳱' => '𐲱',
  '𐳲' => '𐲲',
  '𑣀' => '𑢠',
  '𑣁' => '𑢡',
  '𑣂' => '𑢢',
  '𑣃' => '𑢣',
  '𑣄' => '𑢤',
  '𑣅' => '𑢥',
  '𑣆' => '𑢦',
  '𑣇' => '𑢧',
  '𑣈' => '𑢨',
  '𑣉' => '𑢩',
  '𑣊' => '𑢪',
  '𑣋' => '𑢫',
  '𑣌' => '𑢬',
  '𑣍' => '𑢭',
  '𑣎' => '𑢮',
  '𑣏' => '𑢯',
  '𑣐' => '𑢰',
  '𑣑' => '𑢱',
  '𑣒' => '𑢲',
  '𑣓' => '𑢳',
  '𑣔' => '𑢴',
  '𑣕' => '𑢵',
  '𑣖' => '𑢶',
  '𑣗' => '𑢷',
  '𑣘' => '𑢸',
  '𑣙' => '𑢹',
  '𑣚' => '𑢺',
  '𑣛' => '𑢻',
  '𑣜' => '𑢼',
  '𑣝' => '𑢽',
  '𑣞' => '𑢾',
  '𑣟' => '𑢿',
  '𖹠' => '𖹀',
  '𖹡' => '𖹁',
  '𖹢' => '𖹂',
  '𖹣' => '𖹃',
  '𖹤' => '𖹄',
  '𖹥' => '𖹅',
  '𖹦' => '𖹆',
  '𖹧' => '𖹇',
  '𖹨' => '𖹈',
  '𖹩' => '𖹉',
  '𖹪' => '𖹊',
  '𖹫' => '𖹋',
  '𖹬' => '𖹌',
  '𖹭' => '𖹍',
  '𖹮' => '𖹎',
  '𖹯' => '𖹏',
  '𖹰' => '𖹐',
  '𖹱' => '𖹑',
  '𖹲' => '𖹒',
  '𖹳' => '𖹓',
  '𖹴' => '𖹔',
  '𖹵' => '𖹕',
  '𖹶' => '𖹖',
  '𖹷' => '𖹗',
  '𖹸' => '𖹘',
  '𖹹' => '𖹙',
  '𖹺' => '𖹚',
  '𖹻' => '𖹛',
  '𖹼' => '𖹜',
  '𖹽' => '𖹝',
  '𖹾' => '𖹞',
  '𖹿' => '𖹟',
  '𞤢' => '𞤀',
  '𞤣' => '𞤁',
  '𞤤' => '𞤂',
  '𞤥' => '𞤃',
  '𞤦' => '𞤄',
  '𞤧' => '𞤅',
  '𞤨' => '𞤆',
  '𞤩' => '𞤇',
  '𞤪' => '𞤈',
  '𞤫' => '𞤉',
  '𞤬' => '𞤊',
  '𞤭' => '𞤋',
  '𞤮' => '𞤌',
  '𞤯' => '𞤍',
  '𞤰' => '𞤎',
  '𞤱' => '𞤏',
  '𞤲' => '𞤐',
  '𞤳' => '𞤑',
  '𞤴' => '𞤒',
  '𞤵' => '𞤓',
  '𞤶' => '𞤔',
  '𞤷' => '𞤕',
  '𞤸' => '𞤖',
  '𞤹' => '𞤗',
  '𞤺' => '𞤘',
  '𞤻' => '𞤙',
  '𞤼' => '𞤚',
  '𞤽' => '𞤛',
  '𞤾' => '𞤜',
  '𞤿' => '𞤝',
  '𞥀' => '𞤞',
  '𞥁' => '𞤟',
  '𞥂' => '𞤠',
  '𞥃' => '𞤡',
  'ß' => 'SS',
  'ﬀ' => 'FF',
  'ﬁ' => 'FI',
  'ﬂ' => 'FL',
  'ﬃ' => 'FFI',
  'ﬄ' => 'FFL',
  'ﬅ' => 'ST',
  'ﬆ' => 'ST',
  'և' => 'ԵՒ',
  'ﬓ' => 'ՄՆ',
  'ﬔ' => 'ՄԵ',
  'ﬕ' => 'ՄԻ',
  'ﬖ' => 'ՎՆ',
  'ﬗ' => 'ՄԽ',
  'ŉ' => 'ʼN',
  'ΐ' => 'Ϊ́',
  'ΰ' => 'Ϋ́',
  'ǰ' => 'J̌',
  'ẖ' => 'H̱',
  'ẗ' => 'T̈',
  'ẘ' => 'W̊',
  'ẙ' => 'Y̊',
  'ẚ' => 'Aʾ',
  'ὐ' => 'Υ̓',
  'ὒ' => 'Υ̓̀',
  'ὔ' => 'Υ̓́',
  'ὖ' => 'Υ̓͂',
  'ᾶ' => 'Α͂',
  'ῆ' => 'Η͂',
  'ῒ' => 'Ϊ̀',
  'ΐ' => 'Ϊ́',
  'ῖ' => 'Ι͂',
  'ῗ' => 'Ϊ͂',
  'ῢ' => 'Ϋ̀',
  'ΰ' => 'Ϋ́',
  'ῤ' => 'Ρ̓',
  'ῦ' => 'Υ͂',
  'ῧ' => 'Ϋ͂',
  'ῶ' => 'Ω͂',
  'ᾈ' => 'ἈΙ',
  'ᾉ' => 'ἉΙ',
  'ᾊ' => 'ἊΙ',
  'ᾋ' => 'ἋΙ',
  'ᾌ' => 'ἌΙ',
  'ᾍ' => 'ἍΙ',
  'ᾎ' => 'ἎΙ',
  'ᾏ' => 'ἏΙ',
  'ᾘ' => 'ἨΙ',
  'ᾙ' => 'ἩΙ',
  'ᾚ' => 'ἪΙ',
  'ᾛ' => 'ἫΙ',
  'ᾜ' => 'ἬΙ',
  'ᾝ' => 'ἭΙ',
  'ᾞ' => 'ἮΙ',
  'ᾟ' => 'ἯΙ',
  'ᾨ' => 'ὨΙ',
  'ᾩ' => 'ὩΙ',
  'ᾪ' => 'ὪΙ',
  'ᾫ' => 'ὫΙ',
  'ᾬ' => 'ὬΙ',
  'ᾭ' => 'ὭΙ',
  'ᾮ' => 'ὮΙ',
  'ᾯ' => 'ὯΙ',
  'ᾼ' => 'ΑΙ',
  'ῌ' => 'ΗΙ',
  'ῼ' => 'ΩΙ',
  'ᾲ' => 'ᾺΙ',
  'ᾴ' => 'ΆΙ',
  'ῂ' => 'ῊΙ',
  'ῄ' => 'ΉΙ',
  'ῲ' => 'ῺΙ',
  'ῴ' => 'ΏΙ',
  'ᾷ' => 'Α͂Ι',
  'ῇ' => 'Η͂Ι',
  'ῷ' => 'Ω͂Ι',
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

/**
 * Marker Interface for the Process Component.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

/**
 * InvalidArgumentException for the Process Component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

/**
 * LogicException for the Process Component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;

/**
 * Exception for failed processes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ProcessFailedException extends RuntimeException
{
    private Process $process;

    public function __construct(Process $process)
    {
        if ($process->isSuccessful()) {
            throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
        }

        $error = \sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
            $process->getCommandLine(),
            $process->getExitCode(),
            $process->getExitCodeText(),
            $process->getWorkingDirectory()
        );

        if (!$process->isOutputDisabled()) {
            $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
                $process->getOutput(),
                $process->getErrorOutput()
            );
        }

        parent::__construct($error);

        $this->process = $process;
    }

    /**
     * @return Process
     */
    public function getProcess()
    {
        return $this->process;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;

/**
 * Exception that is thrown when a process has been signaled.
 *
 * @author Sullivan Senechal <soullivaneuh@gmail.com>
 */
final class ProcessSignaledException extends RuntimeException
{
    private Process $process;

    public function __construct(Process $process)
    {
        $this->process = $process;

        parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
    }

    public function getProcess(): Process
    {
        return $this->process;
    }

    public function getSignal(): int
    {
        return $this->getProcess()->getTermSignal();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Process;

/**
 * Exception that is thrown when a process times out.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ProcessTimedOutException extends RuntimeException
{
    public const TYPE_GENERAL = 1;
    public const TYPE_IDLE = 2;

    private Process $process;
    private int $timeoutType;

    public function __construct(Process $process, int $timeoutType)
    {
        $this->process = $process;
        $this->timeoutType = $timeoutType;

        parent::__construct(\sprintf(
            'The process "%s" exceeded the timeout of %s seconds.',
            $process->getCommandLine(),
            $this->getExceededTimeout()
        ));
    }

    /**
     * @return Process
     */
    public function getProcess()
    {
        return $this->process;
    }

    /**
     * @return bool
     */
    public function isGeneralTimeout()
    {
        return self::TYPE_GENERAL === $this->timeoutType;
    }

    /**
     * @return bool
     */
    public function isIdleTimeout()
    {
        return self::TYPE_IDLE === $this->timeoutType;
    }

    public function getExceededTimeout(): ?float
    {
        return match ($this->timeoutType) {
            self::TYPE_GENERAL => $this->process->getTimeout(),
            self::TYPE_IDLE => $this->process->getIdleTimeout(),
            default => throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType)),
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

use Symfony\Component\Process\Messenger\RunProcessContext;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunProcessFailedException extends RuntimeException
{
    public function __construct(ProcessFailedException $exception, public readonly RunProcessContext $context)
    {
        parent::__construct($exception->getMessage(), $exception->getCode());
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Exception;

/**
 * RuntimeException for the Process Component.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

/**
 * Generic executable finder.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ExecutableFinder
{
    private const CMD_BUILTINS = [
        'assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date',
        'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto',
        'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause',
        'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set',
        'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol',
    ];

    private array $suffixes = [];

    /**
     * Replaces default suffixes of executable.
     *
     * @return void
     */
    public function setSuffixes(array $suffixes)
    {
        $this->suffixes = $suffixes;
    }

    /**
     * Adds new possible suffix to check for executable.
     *
     * @return void
     */
    public function addSuffix(string $suffix)
    {
        $this->suffixes[] = $suffix;
    }

    /**
     * Finds an executable by name.
     *
     * @param string      $name      The executable name (without the extension)
     * @param string|null $default   The default to return if no executable is found
     * @param array       $extraDirs Additional dirs to check into
     */
    public function find(string $name, ?string $default = null, array $extraDirs = []): ?string
    {
        // windows built-in commands that are present in cmd.exe should not be resolved using PATH as they do not exist as exes
        if ('\\' === \DIRECTORY_SEPARATOR && \in_array(strtolower($name), self::CMD_BUILTINS, true)) {
            return $name;
        }

        $dirs = array_merge(
            explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
            $extraDirs
        );

        $suffixes = [];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $pathExt = getenv('PATHEXT');
            $suffixes = $this->suffixes;
            $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']);
        }
        $suffixes = '' !== pathinfo($name, \PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']);
        foreach ($suffixes as $suffix) {
            foreach ($dirs as $dir) {
                if ('' === $dir) {
                    $dir = '.';
                }
                if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
                    return $file;
                }

                if (!@is_dir($dir) && basename($dir) === $name.$suffix && @is_executable($dir)) {
                    return $dir;
                }
            }
        }

        if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('exec') || \strlen($name) !== strcspn($name, '/'.\DIRECTORY_SEPARATOR)) {
            return $default;
        }

        $execResult = exec('command -v -- '.escapeshellarg($name));

        if (($executablePath = substr($execResult, 0, strpos($execResult, \PHP_EOL) ?: null)) && @is_executable($executablePath)) {
            return $executablePath;
        }

        return $default;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\RuntimeException;

/**
 * Provides a way to continuously write to the input of a Process until the InputStream is closed.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @implements \IteratorAggregate<int, string>
 */
class InputStream implements \IteratorAggregate
{
    private ?\Closure $onEmpty = null;
    private array $input = [];
    private bool $open = true;

    /**
     * Sets a callback that is called when the write buffer becomes empty.
     *
     * @return void
     */
    public function onEmpty(?callable $onEmpty = null)
    {
        $this->onEmpty = null !== $onEmpty ? $onEmpty(...) : null;
    }

    /**
     * Appends an input to the write buffer.
     *
     * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar,
     *                                                                stream resource or \Traversable
     *
     * @return void
     */
    public function write(mixed $input)
    {
        if (null === $input) {
            return;
        }
        if ($this->isClosed()) {
            throw new RuntimeException(\sprintf('"%s" is closed.', static::class));
        }
        $this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
    }

    /**
     * Closes the write buffer.
     *
     * @return void
     */
    public function close()
    {
        $this->open = false;
    }

    /**
     * Tells whether the write buffer is closed or not.
     *
     * @return bool
     */
    public function isClosed()
    {
        return !$this->open;
    }

    public function getIterator(): \Traversable
    {
        $this->open = true;

        while ($this->open || $this->input) {
            if (!$this->input) {
                yield '';
                continue;
            }
            $current = array_shift($this->input);

            if ($current instanceof \Iterator) {
                yield from $current;
            } else {
                yield $current;
            }
            if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
                $this->write($onEmpty($this));
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Messenger;

use Symfony\Component\Process\Process;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunProcessContext
{
    public readonly ?int $exitCode;
    public readonly ?string $output;
    public readonly ?string $errorOutput;

    public function __construct(
        public readonly RunProcessMessage $message,
        Process $process,
    ) {
        $this->exitCode = $process->getExitCode();
        $this->output = $process->isOutputDisabled() ? null : $process->getOutput();
        $this->errorOutput = $process->isOutputDisabled() ? null : $process->getErrorOutput();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Messenger;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class RunProcessMessage implements \Stringable
{
    public function __construct(
        public readonly array $command,
        public readonly ?string $cwd = null,
        public readonly ?array $env = null,
        public readonly mixed $input = null,
        public readonly ?float $timeout = 60.0,
    ) {
    }

    public function __toString(): string
    {
        return implode(' ', $this->command);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Messenger;

use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Exception\RunProcessFailedException;
use Symfony\Component\Process\Process;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class RunProcessMessageHandler
{
    public function __invoke(RunProcessMessage $message): RunProcessContext
    {
        $process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout);

        try {
            return new RunProcessContext($message, $process->mustRun());
        } catch (ProcessFailedException $e) {
            throw new RunProcessFailedException($e, new RunProcessContext($message, $e->getProcess()));
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

/**
 * An executable finder specifically designed for the PHP executable.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class PhpExecutableFinder
{
    private ExecutableFinder $executableFinder;

    public function __construct()
    {
        $this->executableFinder = new ExecutableFinder();
    }

    /**
     * Finds The PHP executable.
     */
    public function find(bool $includeArgs = true): string|false
    {
        if ($php = getenv('PHP_BINARY')) {
            if (!is_executable($php) && !$php = $this->executableFinder->find($php)) {
                return false;
            }

            if (@is_dir($php)) {
                return false;
            }

            return $php;
        }

        $args = $this->findArguments();
        $args = $includeArgs && $args ? ' '.implode(' ', $args) : '';

        // PHP_BINARY return the current sapi executable
        if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cli', 'cli-server', 'phpdbg'], true)) {
            return \PHP_BINARY.$args;
        }

        if ($php = getenv('PHP_PATH')) {
            if (!@is_executable($php) || @is_dir($php)) {
                return false;
            }

            return $php;
        }

        if ($php = getenv('PHP_PEAR_PHP_BIN')) {
            if (@is_executable($php) && !@is_dir($php)) {
                return $php;
            }
        }

        if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php')) && !@is_dir($php)) {
            return $php;
        }

        $dirs = [\PHP_BINDIR];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $dirs[] = 'C:\xampp\php\\';
        }

        return $this->executableFinder->find('php', false, $dirs);
    }

    /**
     * Finds the PHP executable arguments.
     */
    public function findArguments(): array
    {
        $arguments = [];
        if ('phpdbg' === \PHP_SAPI) {
            $arguments[] = '-qrr';
        }

        return $arguments;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\RuntimeException;

/**
 * PhpProcess runs a PHP script in an independent process.
 *
 *     $p = new PhpProcess('<?php echo "foo"; ?>');
 *     $p->run();
 *     print $p->getOutput()."\n";
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class PhpProcess extends Process
{
    /**
     * @param string      $script  The PHP script to run (as a string)
     * @param string|null $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null  $env     The environment variables or null to use the same environment as the current PHP process
     * @param int         $timeout The timeout in seconds
     * @param array|null  $php     Path to the PHP binary to use with any additional arguments
     */
    public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null)
    {
        if (null === $php) {
            $executableFinder = new PhpExecutableFinder();
            $php = $executableFinder->find(false);
            $php = false === $php ? null : array_merge([$php], $executableFinder->findArguments());
        }
        if ('phpdbg' === \PHP_SAPI) {
            $file = tempnam(sys_get_temp_dir(), 'dbg');
            file_put_contents($file, $script);
            register_shutdown_function('unlink', $file);
            $php[] = $file;
            $script = null;
        }

        parent::__construct($php, $cwd, $env, $script, $timeout);
    }

    public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
    {
        throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
    }

    /**
     * @return void
     */
    public function start(?callable $callback = null, array $env = [])
    {
        if (null === $this->getCommandLine()) {
            throw new RuntimeException('Unable to find the PHP executable.');
        }

        parent::start($callback, $env);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\RuntimeException;

/**
 * PhpSubprocess runs a PHP command as a subprocess while keeping the original php.ini settings.
 *
 * For this, it generates a temporary php.ini file taking over all the current settings and disables
 * loading additional .ini files. Basically, your command gets prefixed using "php -n -c /tmp/temp.ini".
 *
 * Given your php.ini contains "memory_limit=-1" and you have a "MemoryTest.php" with the following content:
 *
 *     <?php var_dump(ini_get('memory_limit'));
 *
 * These are the differences between the regular Process and PhpSubprocess classes:
 *
 *     $p = new Process(['php', '-d', 'memory_limit=256M', 'MemoryTest.php']);
 *     $p->run();
 *     print $p->getOutput()."\n";
 *
 * This will output "string(2) "-1", because the process is started with the default php.ini settings.
 *
 *     $p = new PhpSubprocess(['MemoryTest.php'], null, null, 60, ['php', '-d', 'memory_limit=256M']);
 *     $p->run();
 *     print $p->getOutput()."\n";
 *
 * This will output "string(4) "256M"", because the process is started with the temporarily created php.ini settings.
 *
 * @author Yanick Witschi <yanick.witschi@terminal42.ch>
 * @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson <john-stevenson@blueyonder.co.uk>
 */
class PhpSubprocess extends Process
{
    /**
     * @param array       $command The command to run and its arguments listed as separate entries. They will automatically
     *                             get prefixed with the PHP binary
     * @param string|null $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null  $env     The environment variables or null to use the same environment as the current PHP process
     * @param int         $timeout The timeout in seconds
     * @param array|null  $php     Path to the PHP binary to use with any additional arguments
     */
    public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null)
    {
        if (null === $php) {
            $executableFinder = new PhpExecutableFinder();
            $php = $executableFinder->find(false);
            $php = false === $php ? null : array_merge([$php], $executableFinder->findArguments());
        }

        if (null === $php) {
            throw new RuntimeException('Unable to find PHP binary.');
        }

        $tmpIni = $this->writeTmpIni($this->getAllIniFiles(), sys_get_temp_dir());

        $php = array_merge($php, ['-n', '-c', $tmpIni]);
        register_shutdown_function('unlink', $tmpIni);

        $command = array_merge($php, $command);

        parent::__construct($command, $cwd, $env, null, $timeout);
    }

    public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
    {
        throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
    }

    public function start(?callable $callback = null, array $env = []): void
    {
        if (null === $this->getCommandLine()) {
            throw new RuntimeException('Unable to find the PHP executable.');
        }

        parent::start($callback, $env);
    }

    private function writeTmpIni(array $iniFiles, string $tmpDir): string
    {
        if (false === $tmpfile = @tempnam($tmpDir, '')) {
            throw new RuntimeException('Unable to create temporary ini file.');
        }

        // $iniFiles has at least one item and it may be empty
        if ('' === $iniFiles[0]) {
            array_shift($iniFiles);
        }

        $content = '';

        foreach ($iniFiles as $file) {
            // Check for inaccessible ini files
            if (($data = @file_get_contents($file)) === false) {
                throw new RuntimeException('Unable to read ini: '.$file);
            }
            // Check and remove directives after HOST and PATH sections
            if (preg_match('/^\s*\[(?:PATH|HOST)\s*=/mi', $data, $matches, \PREG_OFFSET_CAPTURE)) {
                $data = substr($data, 0, $matches[0][1]);
            }

            $content .= $data."\n";
        }

        // Merge loaded settings into our ini content, if it is valid
        $config = parse_ini_string($content);
        $loaded = ini_get_all(null, false);

        if (false === $config || false === $loaded) {
            throw new RuntimeException('Unable to parse ini data.');
        }

        $content .= $this->mergeLoadedConfig($loaded, $config);

        // Work-around for https://bugs.php.net/bug.php?id=75932
        $content .= "opcache.enable_cli=0\n";

        if (false === @file_put_contents($tmpfile, $content)) {
            throw new RuntimeException('Unable to write temporary ini file.');
        }

        return $tmpfile;
    }

    private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): string
    {
        $content = '';

        foreach ($loadedConfig as $name => $value) {
            if (!\is_string($value)) {
                continue;
            }

            if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
                // Double-quote escape each value
                $content .= $name.'="'.addcslashes($value, '\\"')."\"\n";
            }
        }

        return $content;
    }

    private function getAllIniFiles(): array
    {
        $paths = [(string) php_ini_loaded_file()];

        if (false !== $scanned = php_ini_scanned_files()) {
            $paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
        }

        return $paths;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Exception\InvalidArgumentException;

/**
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
abstract class AbstractPipes implements PipesInterface
{
    public array $pipes = [];

    private string $inputBuffer = '';
    /** @var resource|string|\Iterator */
    private $input;
    private bool $blocked = true;
    private ?string $lastError = null;

    /**
     * @param resource|string|\Iterator $input
     */
    public function __construct($input)
    {
        if (\is_resource($input) || $input instanceof \Iterator) {
            $this->input = $input;
        } else {
            $this->inputBuffer = (string) $input;
        }
    }

    public function close(): void
    {
        foreach ($this->pipes as $pipe) {
            if (\is_resource($pipe)) {
                fclose($pipe);
            }
        }
        $this->pipes = [];
    }

    /**
     * Returns true if a system call has been interrupted.
     *
     * stream_select() returns false when the `select` system call is interrupted by an incoming signal.
     */
    protected function hasSystemCallBeenInterrupted(): bool
    {
        $lastError = $this->lastError;
        $this->lastError = null;

        if (null === $lastError) {
            return false;
        }

        if (false !== stripos($lastError, 'interrupted system call')) {
            return true;
        }

        // on applications with a different locale than english, the message above is not found because
        // it's translated. So we also check for the SOCKET_EINTR constant which is defined under
        // Windows and UNIX-like platforms (if available on the platform).
        return \defined('SOCKET_EINTR') && str_starts_with($lastError, 'stream_select(): Unable to select ['.\SOCKET_EINTR.']');
    }

    /**
     * Unblocks streams.
     */
    protected function unblock(): void
    {
        if (!$this->blocked) {
            return;
        }

        foreach ($this->pipes as $pipe) {
            stream_set_blocking($pipe, false);
        }
        if (\is_resource($this->input)) {
            stream_set_blocking($this->input, false);
        }

        $this->blocked = false;
    }

    /**
     * Writes input to stdin.
     *
     * @throws InvalidArgumentException When an input iterator yields a non supported value
     */
    protected function write(): ?array
    {
        if (!isset($this->pipes[0])) {
            return null;
        }
        $input = $this->input;

        if ($input instanceof \Iterator) {
            if (!$input->valid()) {
                $input = null;
            } elseif (\is_resource($input = $input->current())) {
                stream_set_blocking($input, false);
            } elseif (!isset($this->inputBuffer[0])) {
                if (!\is_string($input)) {
                    if (!\is_scalar($input)) {
                        throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input)));
                    }
                    $input = (string) $input;
                }
                $this->inputBuffer = $input;
                $this->input->next();
                $input = null;
            } else {
                $input = null;
            }
        }

        $r = $e = [];
        $w = [$this->pipes[0]];

        // let's have a look if something changed in streams
        if (false === @stream_select($r, $w, $e, 0, 0)) {
            return null;
        }

        foreach ($w as $stdin) {
            if (isset($this->inputBuffer[0])) {
                $written = fwrite($stdin, $this->inputBuffer);
                $this->inputBuffer = substr($this->inputBuffer, $written);
                if (isset($this->inputBuffer[0])) {
                    return [$this->pipes[0]];
                }
            }

            if ($input) {
                while (true) {
                    $data = fread($input, self::CHUNK_SIZE);
                    if (!isset($data[0])) {
                        break;
                    }
                    $written = fwrite($stdin, $data);
                    $data = substr($data, $written);
                    if (isset($data[0])) {
                        $this->inputBuffer = $data;

                        return [$this->pipes[0]];
                    }
                }
                if (feof($input)) {
                    if ($this->input instanceof \Iterator) {
                        $this->input->next();
                    } else {
                        $this->input = null;
                    }
                }
            }
        }

        // no input to read on resource, buffer is empty
        if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
            $this->input = null;
            fclose($this->pipes[0]);
            unset($this->pipes[0]);
        } elseif (!$w) {
            return [$this->pipes[0]];
        }

        return null;
    }

    /**
     * @internal
     */
    public function handleError(int $type, string $msg): void
    {
        $this->lastError = $msg;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Pipes;

/**
 * PipesInterface manages descriptors and pipes for the use of proc_open.
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
interface PipesInterface
{
    public const CHUNK_SIZE = 16384;

    /**
     * Returns an array of descriptors for the use of proc_open.
     */
    public function getDescriptors(): array;

    /**
     * Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
     *
     * @return string[]
     */
    public function getFiles(): array;

    /**
     * Reads data in file handles and pipes.
     *
     * @param bool $blocking Whether to use blocking calls or not
     * @param bool $close    Whether to close pipes if they've reached EOF
     *
     * @return string[] An array of read data indexed by their fd
     */
    public function readAndWrite(bool $blocking, bool $close = false): array;

    /**
     * Returns if the current state has open file handles or pipes.
     */
    public function areOpen(): bool;

    /**
     * Returns if pipes are able to read output.
     */
    public function haveReadSupport(): bool;

    /**
     * Closes file handles and pipes.
     */
    public function close(): void;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Process;

/**
 * UnixPipes implementation uses unix pipes as handles.
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
class UnixPipes extends AbstractPipes
{
    private ?bool $ttyMode;
    private bool $ptyMode;
    private bool $haveReadSupport;

    public function __construct(?bool $ttyMode, bool $ptyMode, mixed $input, bool $haveReadSupport)
    {
        $this->ttyMode = $ttyMode;
        $this->ptyMode = $ptyMode;
        $this->haveReadSupport = $haveReadSupport;

        parent::__construct($input);
    }

    public function __serialize(): array
    {
        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
    }

    public function __unserialize(array $data): void
    {
        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
    }

    public function __destruct()
    {
        $this->close();
    }

    public function getDescriptors(): array
    {
        if (!$this->haveReadSupport) {
            $nullstream = fopen('/dev/null', 'c');

            return [
                ['pipe', 'r'],
                $nullstream,
                $nullstream,
            ];
        }

        if ($this->ttyMode) {
            return [
                ['file', '/dev/tty', 'r'],
                ['file', '/dev/tty', 'w'],
                ['file', '/dev/tty', 'w'],
            ];
        }

        if ($this->ptyMode && Process::isPtySupported()) {
            return [
                ['pty'],
                ['pty'],
                ['pipe', 'w'], // stderr needs to be in a pipe to correctly split error and output, since PHP will use the same stream for both
            ];
        }

        return [
            ['pipe', 'r'],
            ['pipe', 'w'], // stdout
            ['pipe', 'w'], // stderr
        ];
    }

    public function getFiles(): array
    {
        return [];
    }

    public function readAndWrite(bool $blocking, bool $close = false): array
    {
        $this->unblock();
        $w = $this->write();

        $read = $e = [];
        $r = $this->pipes;
        unset($r[0]);

        // let's have a look if something changed in streams
        set_error_handler($this->handleError(...));
        if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
            restore_error_handler();
            // if a system call has been interrupted, forget about it, let's try again
            // otherwise, an error occurred, let's reset pipes
            if (!$this->hasSystemCallBeenInterrupted()) {
                $this->pipes = [];
            }

            return $read;
        }
        restore_error_handler();

        foreach ($r as $pipe) {
            // prior PHP 5.4 the array passed to stream_select is modified and
            // lose key association, we have to find back the key
            $read[$type = array_search($pipe, $this->pipes, true)] = '';

            do {
                $data = @fread($pipe, self::CHUNK_SIZE);
                $read[$type] .= $data;
            } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));

            if (!isset($read[$type][0])) {
                unset($read[$type]);
            }

            if ($close && feof($pipe)) {
                fclose($pipe);
                unset($this->pipes[$type]);
            }
        }

        return $read;
    }

    public function haveReadSupport(): bool
    {
        return $this->haveReadSupport;
    }

    public function areOpen(): bool
    {
        return (bool) $this->pipes;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process\Pipes;

use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;

/**
 * WindowsPipes implementation uses temporary files as handles.
 *
 * @see https://bugs.php.net/51800
 * @see https://bugs.php.net/65650
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
class WindowsPipes extends AbstractPipes
{
    private array $files = [];
    private array $fileHandles = [];
    private array $lockHandles = [];
    private array $readBytes = [
        Process::STDOUT => 0,
        Process::STDERR => 0,
    ];
    private bool $haveReadSupport;

    public function __construct(mixed $input, bool $haveReadSupport)
    {
        $this->haveReadSupport = $haveReadSupport;

        if ($this->haveReadSupport) {
            // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
            // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
            //
            // @see https://bugs.php.net/51800
            $pipes = [
                Process::STDOUT => Process::OUT,
                Process::STDERR => Process::ERR,
            ];
            $tmpDir = sys_get_temp_dir();
            $lastError = 'unknown reason';
            set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
            for ($i = 0;; ++$i) {
                foreach ($pipes as $pipe => $name) {
                    $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);

                    if (!$h = fopen($file.'.lock', 'w')) {
                        if (file_exists($file.'.lock')) {
                            continue 2;
                        }
                        restore_error_handler();
                        throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
                    }
                    if (!flock($h, \LOCK_EX | \LOCK_NB)) {
                        continue 2;
                    }
                    if (isset($this->lockHandles[$pipe])) {
                        flock($this->lockHandles[$pipe], \LOCK_UN);
                        fclose($this->lockHandles[$pipe]);
                    }
                    $this->lockHandles[$pipe] = $h;

                    if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) {
                        flock($this->lockHandles[$pipe], \LOCK_UN);
                        fclose($this->lockHandles[$pipe]);
                        unset($this->lockHandles[$pipe]);
                        continue 2;
                    }
                    $this->fileHandles[$pipe] = $h;
                    $this->files[$pipe] = $file;
                }
                break;
            }
            restore_error_handler();
        }

        parent::__construct($input);
    }

    public function __serialize(): array
    {
        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
    }

    public function __unserialize(array $data): void
    {
        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
    }

    public function __destruct()
    {
        $this->close();
    }

    public function getDescriptors(): array
    {
        if (!$this->haveReadSupport) {
            $nullstream = fopen('NUL', 'c');

            return [
                ['pipe', 'r'],
                $nullstream,
                $nullstream,
            ];
        }

        // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
        // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
        // So we redirect output within the commandline and pass the nul device to the process
        return [
            ['pipe', 'r'],
            ['file', 'NUL', 'w'],
            ['file', 'NUL', 'w'],
        ];
    }

    public function getFiles(): array
    {
        return $this->files;
    }

    public function readAndWrite(bool $blocking, bool $close = false): array
    {
        $this->unblock();
        $w = $this->write();
        $read = $r = $e = [];

        if ($blocking) {
            if ($w) {
                @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
            } elseif ($this->fileHandles) {
                usleep((int) (Process::TIMEOUT_PRECISION * 1E6));
            }
        }
        foreach ($this->fileHandles as $type => $fileHandle) {
            $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);

            if (isset($data[0])) {
                $this->readBytes[$type] += \strlen($data);
                $read[$type] = $data;
            }
            if ($close) {
                ftruncate($fileHandle, 0);
                fclose($fileHandle);
                flock($this->lockHandles[$type], \LOCK_UN);
                fclose($this->lockHandles[$type]);
                unset($this->fileHandles[$type], $this->lockHandles[$type]);
            }
        }

        return $read;
    }

    public function haveReadSupport(): bool
    {
        return $this->haveReadSupport;
    }

    public function areOpen(): bool
    {
        return $this->pipes && $this->fileHandles;
    }

    public function close(): void
    {
        parent::close();
        foreach ($this->fileHandles as $type => $handle) {
            ftruncate($handle, 0);
            fclose($handle);
            flock($this->lockHandles[$type], \LOCK_UN);
            fclose($this->lockHandles[$type]);
        }
        $this->fileHandles = $this->lockHandles = [];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\InvalidArgumentException;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Exception\ProcessSignaledException;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Pipes\UnixPipes;
use Symfony\Component\Process\Pipes\WindowsPipes;

/**
 * Process is a thin wrapper around proc_* functions to easily
 * start independent PHP processes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @implements \IteratorAggregate<string, string>
 */
class Process implements \IteratorAggregate
{
    public const ERR = 'err';
    public const OUT = 'out';

    public const STATUS_READY = 'ready';
    public const STATUS_STARTED = 'started';
    public const STATUS_TERMINATED = 'terminated';

    public const STDIN = 0;
    public const STDOUT = 1;
    public const STDERR = 2;

    // Timeout Precision in seconds.
    public const TIMEOUT_PRECISION = 0.2;

    public const ITER_NON_BLOCKING = 1; // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
    public const ITER_KEEP_OUTPUT = 2;  // By default, outputs are cleared while iterating, use this flag to keep them in memory
    public const ITER_SKIP_OUT = 4;     // Use this flag to skip STDOUT while iterating
    public const ITER_SKIP_ERR = 8;     // Use this flag to skip STDERR while iterating

    private ?\Closure $callback = null;
    private array|string $commandline;
    private ?string $cwd;
    private array $env = [];
    /** @var resource|string|\Iterator|null */
    private $input;
    private ?float $starttime = null;
    private ?float $lastOutputTime = null;
    private ?float $timeout = null;
    private ?float $idleTimeout = null;
    private ?int $exitcode = null;
    private array $fallbackStatus = [];
    private array $processInformation;
    private bool $outputDisabled = false;
    /** @var resource */
    private $stdout;
    /** @var resource */
    private $stderr;
    /** @var resource|null */
    private $process;
    private string $status = self::STATUS_READY;
    private int $incrementalOutputOffset = 0;
    private int $incrementalErrorOutputOffset = 0;
    private bool $tty = false;
    private bool $pty;
    private array $options = ['suppress_errors' => true, 'bypass_shell' => true];

    private WindowsPipes|UnixPipes $processPipes;

    private ?int $latestSignal = null;

    private static ?bool $sigchild = null;

    /**
     * Exit codes translation table.
     *
     * User-defined errors must use exit codes in the 64-113 range.
     */
    public static $exitCodes = [
        0 => 'OK',
        1 => 'General error',
        2 => 'Misuse of shell builtins',

        126 => 'Invoked command cannot execute',
        127 => 'Command not found',
        128 => 'Invalid exit argument',

        // signals
        129 => 'Hangup',
        130 => 'Interrupt',
        131 => 'Quit and dump core',
        132 => 'Illegal instruction',
        133 => 'Trace/breakpoint trap',
        134 => 'Process aborted',
        135 => 'Bus error: "access to undefined portion of memory object"',
        136 => 'Floating point exception: "erroneous arithmetic operation"',
        137 => 'Kill (terminate immediately)',
        138 => 'User-defined 1',
        139 => 'Segmentation violation',
        140 => 'User-defined 2',
        141 => 'Write to pipe with no one reading',
        142 => 'Signal raised by alarm',
        143 => 'Termination (request to terminate)',
        // 144 - not defined
        145 => 'Child process terminated, stopped (or continued*)',
        146 => 'Continue if stopped',
        147 => 'Stop executing temporarily',
        148 => 'Terminal stop signal',
        149 => 'Background process attempting to read from tty ("in")',
        150 => 'Background process attempting to write to tty ("out")',
        151 => 'Urgent data available on socket',
        152 => 'CPU time limit exceeded',
        153 => 'File size limit exceeded',
        154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
        155 => 'Profiling timer expired',
        // 156 - not defined
        157 => 'Pollable event',
        // 158 - not defined
        159 => 'Bad syscall',
    ];

    /**
     * @param array          $command The command to run and its arguments listed as separate entries
     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
     * @param int|float|null $timeout The timeout in seconds or null to disable
     *
     * @throws LogicException When proc_open is not installed
     */
    public function __construct(array $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60)
    {
        if (!\function_exists('proc_open')) {
            throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
        }

        $this->commandline = $command;
        $this->cwd = $cwd;

        // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
        // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
        // @see : https://bugs.php.net/51800
        // @see : https://bugs.php.net/50524
        if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
            $this->cwd = getcwd();
        }
        if (null !== $env) {
            $this->setEnv($env);
        }

        $this->setInput($input);
        $this->setTimeout($timeout);
        $this->pty = false;
    }

    /**
     * Creates a Process instance as a command-line to be run in a shell wrapper.
     *
     * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.)
     * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the
     * shell wrapper and not to your commands.
     *
     * In order to inject dynamic values into command-lines, we strongly recommend using placeholders.
     * This will save escaping values, which is not portable nor secure anyway:
     *
     *   $process = Process::fromShellCommandline('my_command "${:MY_VAR}"');
     *   $process->run(null, ['MY_VAR' => $theValue]);
     *
     * @param string         $command The command line to pass to the shell of the OS
     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
     * @param int|float|null $timeout The timeout in seconds or null to disable
     *
     * @throws LogicException When proc_open is not installed
     */
    public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static
    {
        $process = new static([], $cwd, $env, $input, $timeout);
        $process->commandline = $command;

        return $process;
    }

    public function __serialize(): array
    {
        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
    }

    public function __unserialize(array $data): void
    {
        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
    }

    public function __destruct()
    {
        if ($this->options['create_new_console'] ?? false) {
            $this->processPipes->close();
        } else {
            $this->stop(0);
        }
    }

    public function __clone()
    {
        $this->resetProcessData();
    }

    /**
     * Runs the process.
     *
     * The callback receives the type of output (out or err) and
     * some bytes from the output in real-time. It allows to have feedback
     * from the independent process during execution.
     *
     * The STDOUT and STDERR are also available after the process is finished
     * via the getOutput() and getErrorOutput() methods.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @return int The exit status code
     *
     * @throws RuntimeException         When process can't be launched
     * @throws RuntimeException         When process is already running
     * @throws ProcessTimedOutException When process timed out
     * @throws ProcessSignaledException When process stopped after receiving signal
     * @throws LogicException           In case a callback is provided and output has been disabled
     *
     * @final
     */
    public function run(?callable $callback = null, array $env = []): int
    {
        $this->start($callback, $env);

        return $this->wait();
    }

    /**
     * Runs the process.
     *
     * This is identical to run() except that an exception is thrown if the process
     * exits with a non-zero exit code.
     *
     * @return $this
     *
     * @throws ProcessFailedException if the process didn't terminate successfully
     *
     * @final
     */
    public function mustRun(?callable $callback = null, array $env = []): static
    {
        if (0 !== $this->run($callback, $env)) {
            throw new ProcessFailedException($this);
        }

        return $this;
    }

    /**
     * Starts the process and returns after writing the input to STDIN.
     *
     * This method blocks until all STDIN data is sent to the process then it
     * returns while the process runs in the background.
     *
     * The termination of the process can be awaited with wait().
     *
     * The callback receives the type of output (out or err) and some bytes from
     * the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @return void
     *
     * @throws RuntimeException When process can't be launched
     * @throws RuntimeException When process is already running
     * @throws LogicException   In case a callback is provided and output has been disabled
     */
    public function start(?callable $callback = null, array $env = [])
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Process is already running.');
        }

        $this->resetProcessData();
        $this->starttime = $this->lastOutputTime = microtime(true);
        $this->callback = $this->buildCallback($callback);
        $descriptors = $this->getDescriptors(null !== $callback);

        if ($this->env) {
            $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env;
        }

        $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv();

        if (\is_array($commandline = $this->commandline)) {
            $commandline = implode(' ', array_map($this->escapeArgument(...), $commandline));

            if ('\\' !== \DIRECTORY_SEPARATOR) {
                // exec is mandatory to deal with sending a signal to the process
                $commandline = 'exec '.$commandline;
            }
        } else {
            $commandline = $this->replacePlaceholders($commandline, $env);
        }

        if ('\\' === \DIRECTORY_SEPARATOR) {
            $commandline = $this->prepareWindowsCommandLine($commandline, $env);
        } elseif ($this->isSigchildEnabled()) {
            // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
            $descriptors[3] = ['pipe', 'w'];

            // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
            $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
            $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code';
        }

        $envPairs = [];
        foreach ($env as $k => $v) {
            if (false !== $v && false === \in_array($k, ['argc', 'argv', 'ARGC', 'ARGV'], true)) {
                $envPairs[] = $k.'='.$v;
            }
        }

        if (!is_dir($this->cwd)) {
            throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd));
        }

        $process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);

        if (!$process) {
            throw new RuntimeException('Unable to launch a new process.');
        }
        $this->process = $process;
        $this->status = self::STATUS_STARTED;

        if (isset($descriptors[3])) {
            $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
        }

        if ($this->tty) {
            return;
        }

        $this->updateStatus(false);
        $this->checkTimeout();
    }

    /**
     * Restarts the process.
     *
     * Be warned that the process is cloned before being started.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @throws RuntimeException When process can't be launched
     * @throws RuntimeException When process is already running
     *
     * @see start()
     *
     * @final
     */
    public function restart(?callable $callback = null, array $env = []): static
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Process is already running.');
        }

        $process = clone $this;
        $process->start($callback, $env);

        return $process;
    }

    /**
     * Waits for the process to terminate.
     *
     * The callback receives the type of output (out or err) and some bytes
     * from the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @param callable|null $callback A valid PHP callback
     *
     * @return int The exitcode of the process
     *
     * @throws ProcessTimedOutException When process timed out
     * @throws ProcessSignaledException When process stopped after receiving signal
     * @throws LogicException           When process is not yet started
     */
    public function wait(?callable $callback = null): int
    {
        $this->requireProcessIsStarted(__FUNCTION__);

        $this->updateStatus(false);

        if (null !== $callback) {
            if (!$this->processPipes->haveReadSupport()) {
                $this->stop(0);
                throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
            }
            $this->callback = $this->buildCallback($callback);
        }

        do {
            $this->checkTimeout();
            $running = $this->isRunning() && ('\\' === \DIRECTORY_SEPARATOR || $this->processPipes->areOpen());
            $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
        } while ($running);

        while ($this->isRunning()) {
            $this->checkTimeout();
            usleep(1000);
        }

        if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
            throw new ProcessSignaledException($this);
        }

        return $this->exitcode;
    }

    /**
     * Waits until the callback returns true.
     *
     * The callback receives the type of output (out or err) and some bytes
     * from the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @throws RuntimeException         When process timed out
     * @throws LogicException           When process is not yet started
     * @throws ProcessTimedOutException In case the timeout was reached
     */
    public function waitUntil(callable $callback): bool
    {
        $this->requireProcessIsStarted(__FUNCTION__);
        $this->updateStatus(false);

        if (!$this->processPipes->haveReadSupport()) {
            $this->stop(0);
            throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
        }
        $callback = $this->buildCallback($callback);

        $ready = false;
        while (true) {
            $this->checkTimeout();
            $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
            $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);

            foreach ($output as $type => $data) {
                if (3 !== $type) {
                    $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
                } elseif (!isset($this->fallbackStatus['signaled'])) {
                    $this->fallbackStatus['exitcode'] = (int) $data;
                }
            }
            if ($ready) {
                return true;
            }
            if (!$running) {
                return false;
            }

            usleep(1000);
        }
    }

    /**
     * Returns the Pid (process identifier), if applicable.
     *
     * @return int|null The process id if running, null otherwise
     */
    public function getPid(): ?int
    {
        return $this->isRunning() ? $this->processInformation['pid'] : null;
    }

    /**
     * Sends a POSIX signal to the process.
     *
     * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
     *
     * @return $this
     *
     * @throws LogicException   In case the process is not running
     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
     * @throws RuntimeException In case of failure
     */
    public function signal(int $signal): static
    {
        $this->doSignal($signal, true);

        return $this;
    }

    /**
     * Disables fetching output and error output from the underlying process.
     *
     * @return $this
     *
     * @throws RuntimeException In case the process is already running
     * @throws LogicException   if an idle timeout is set
     */
    public function disableOutput(): static
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Disabling output while the process is running is not possible.');
        }
        if (null !== $this->idleTimeout) {
            throw new LogicException('Output cannot be disabled while an idle timeout is set.');
        }

        $this->outputDisabled = true;

        return $this;
    }

    /**
     * Enables fetching output and error output from the underlying process.
     *
     * @return $this
     *
     * @throws RuntimeException In case the process is already running
     */
    public function enableOutput(): static
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Enabling output while the process is running is not possible.');
        }

        $this->outputDisabled = false;

        return $this;
    }

    /**
     * Returns true in case the output is disabled, false otherwise.
     */
    public function isOutputDisabled(): bool
    {
        return $this->outputDisabled;
    }

    /**
     * Returns the current output of the process (STDOUT).
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getOutput(): string
    {
        $this->readPipesForOutput(__FUNCTION__);

        if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
            return '';
        }

        return $ret;
    }

    /**
     * Returns the output incrementally.
     *
     * In comparison with the getOutput method which always return the whole
     * output, this one returns the new output since the last call.
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getIncrementalOutput(): string
    {
        $this->readPipesForOutput(__FUNCTION__);

        $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
        $this->incrementalOutputOffset = ftell($this->stdout);

        if (false === $latest) {
            return '';
        }

        return $latest;
    }

    /**
     * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
     *
     * @param int $flags A bit field of Process::ITER_* flags
     *
     * @return \Generator<string, string>
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getIterator(int $flags = 0): \Generator
    {
        $this->readPipesForOutput(__FUNCTION__, false);

        $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
        $blocking = !(self::ITER_NON_BLOCKING & $flags);
        $yieldOut = !(self::ITER_SKIP_OUT & $flags);
        $yieldErr = !(self::ITER_SKIP_ERR & $flags);

        while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
            if ($yieldOut) {
                $out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);

                if (isset($out[0])) {
                    if ($clearOutput) {
                        $this->clearOutput();
                    } else {
                        $this->incrementalOutputOffset = ftell($this->stdout);
                    }

                    yield self::OUT => $out;
                }
            }

            if ($yieldErr) {
                $err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);

                if (isset($err[0])) {
                    if ($clearOutput) {
                        $this->clearErrorOutput();
                    } else {
                        $this->incrementalErrorOutputOffset = ftell($this->stderr);
                    }

                    yield self::ERR => $err;
                }
            }

            if (!$blocking && !isset($out[0]) && !isset($err[0])) {
                yield self::OUT => '';
            }

            $this->checkTimeout();
            $this->readPipesForOutput(__FUNCTION__, $blocking);
        }
    }

    /**
     * Clears the process output.
     *
     * @return $this
     */
    public function clearOutput(): static
    {
        ftruncate($this->stdout, 0);
        fseek($this->stdout, 0);
        $this->incrementalOutputOffset = 0;

        return $this;
    }

    /**
     * Returns the current error output of the process (STDERR).
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getErrorOutput(): string
    {
        $this->readPipesForOutput(__FUNCTION__);

        if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
            return '';
        }

        return $ret;
    }

    /**
     * Returns the errorOutput incrementally.
     *
     * In comparison with the getErrorOutput method which always return the
     * whole error output, this one returns the new error output since the last
     * call.
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getIncrementalErrorOutput(): string
    {
        $this->readPipesForOutput(__FUNCTION__);

        $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
        $this->incrementalErrorOutputOffset = ftell($this->stderr);

        if (false === $latest) {
            return '';
        }

        return $latest;
    }

    /**
     * Clears the process output.
     *
     * @return $this
     */
    public function clearErrorOutput(): static
    {
        ftruncate($this->stderr, 0);
        fseek($this->stderr, 0);
        $this->incrementalErrorOutputOffset = 0;

        return $this;
    }

    /**
     * Returns the exit code returned by the process.
     *
     * @return int|null The exit status code, null if the Process is not terminated
     */
    public function getExitCode(): ?int
    {
        $this->updateStatus(false);

        return $this->exitcode;
    }

    /**
     * Returns a string representation for the exit code returned by the process.
     *
     * This method relies on the Unix exit code status standardization
     * and might not be relevant for other operating systems.
     *
     * @return string|null A string representation for the exit status code, null if the Process is not terminated
     *
     * @see http://tldp.org/LDP/abs/html/exitcodes.html
     * @see http://en.wikipedia.org/wiki/Unix_signal
     */
    public function getExitCodeText(): ?string
    {
        if (null === $exitcode = $this->getExitCode()) {
            return null;
        }

        return self::$exitCodes[$exitcode] ?? 'Unknown error';
    }

    /**
     * Checks if the process ended successfully.
     */
    public function isSuccessful(): bool
    {
        return 0 === $this->getExitCode();
    }

    /**
     * Returns true if the child process has been terminated by an uncaught signal.
     *
     * It always returns false on Windows.
     *
     * @throws LogicException In case the process is not terminated
     */
    public function hasBeenSignaled(): bool
    {
        $this->requireProcessIsTerminated(__FUNCTION__);

        return $this->processInformation['signaled'];
    }

    /**
     * Returns the number of the signal that caused the child process to terminate its execution.
     *
     * It is only meaningful if hasBeenSignaled() returns true.
     *
     * @throws RuntimeException In case --enable-sigchild is activated
     * @throws LogicException   In case the process is not terminated
     */
    public function getTermSignal(): int
    {
        $this->requireProcessIsTerminated(__FUNCTION__);

        if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
            throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.');
        }

        return $this->processInformation['termsig'];
    }

    /**
     * Returns true if the child process has been stopped by a signal.
     *
     * It always returns false on Windows.
     *
     * @throws LogicException In case the process is not terminated
     */
    public function hasBeenStopped(): bool
    {
        $this->requireProcessIsTerminated(__FUNCTION__);

        return $this->processInformation['stopped'];
    }

    /**
     * Returns the number of the signal that caused the child process to stop its execution.
     *
     * It is only meaningful if hasBeenStopped() returns true.
     *
     * @throws LogicException In case the process is not terminated
     */
    public function getStopSignal(): int
    {
        $this->requireProcessIsTerminated(__FUNCTION__);

        return $this->processInformation['stopsig'];
    }

    /**
     * Checks if the process is currently running.
     */
    public function isRunning(): bool
    {
        if (self::STATUS_STARTED !== $this->status) {
            return false;
        }

        $this->updateStatus(false);

        return $this->processInformation['running'];
    }

    /**
     * Checks if the process has been started with no regard to the current state.
     */
    public function isStarted(): bool
    {
        return self::STATUS_READY != $this->status;
    }

    /**
     * Checks if the process is terminated.
     */
    public function isTerminated(): bool
    {
        $this->updateStatus(false);

        return self::STATUS_TERMINATED == $this->status;
    }

    /**
     * Gets the process status.
     *
     * The status is one of: ready, started, terminated.
     */
    public function getStatus(): string
    {
        $this->updateStatus(false);

        return $this->status;
    }

    /**
     * Stops the process.
     *
     * @param int|float $timeout The timeout in seconds
     * @param int|null  $signal  A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
     *
     * @return int|null The exit-code of the process or null if it's not running
     */
    public function stop(float $timeout = 10, ?int $signal = null): ?int
    {
        $timeoutMicro = microtime(true) + $timeout;
        if ($this->isRunning()) {
            // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
            $this->doSignal(15, false);
            do {
                usleep(1000);
            } while ($this->isRunning() && microtime(true) < $timeoutMicro);

            if ($this->isRunning()) {
                // Avoid exception here: process is supposed to be running, but it might have stopped just
                // after this line. In any case, let's silently discard the error, we cannot do anything.
                $this->doSignal($signal ?: 9, false);
            }
        }

        if ($this->isRunning()) {
            if (isset($this->fallbackStatus['pid'])) {
                unset($this->fallbackStatus['pid']);

                return $this->stop(0, $signal);
            }
            $this->close();
        }

        return $this->exitcode;
    }

    /**
     * Adds a line to the STDOUT stream.
     *
     * @internal
     */
    public function addOutput(string $line): void
    {
        $this->lastOutputTime = microtime(true);

        fseek($this->stdout, 0, \SEEK_END);
        fwrite($this->stdout, $line);
        fseek($this->stdout, $this->incrementalOutputOffset);
    }

    /**
     * Adds a line to the STDERR stream.
     *
     * @internal
     */
    public function addErrorOutput(string $line): void
    {
        $this->lastOutputTime = microtime(true);

        fseek($this->stderr, 0, \SEEK_END);
        fwrite($this->stderr, $line);
        fseek($this->stderr, $this->incrementalErrorOutputOffset);
    }

    /**
     * Gets the last output time in seconds.
     */
    public function getLastOutputTime(): ?float
    {
        return $this->lastOutputTime;
    }

    /**
     * Gets the command line to be executed.
     */
    public function getCommandLine(): string
    {
        return \is_array($this->commandline) ? implode(' ', array_map($this->escapeArgument(...), $this->commandline)) : $this->commandline;
    }

    /**
     * Gets the process timeout in seconds (max. runtime).
     */
    public function getTimeout(): ?float
    {
        return $this->timeout;
    }

    /**
     * Gets the process idle timeout in seconds (max. time since last output).
     */
    public function getIdleTimeout(): ?float
    {
        return $this->idleTimeout;
    }

    /**
     * Sets the process timeout (max. runtime) in seconds.
     *
     * To disable the timeout, set this value to null.
     *
     * @return $this
     *
     * @throws InvalidArgumentException if the timeout is negative
     */
    public function setTimeout(?float $timeout): static
    {
        $this->timeout = $this->validateTimeout($timeout);

        return $this;
    }

    /**
     * Sets the process idle timeout (max. time since last output) in seconds.
     *
     * To disable the timeout, set this value to null.
     *
     * @return $this
     *
     * @throws LogicException           if the output is disabled
     * @throws InvalidArgumentException if the timeout is negative
     */
    public function setIdleTimeout(?float $timeout): static
    {
        if (null !== $timeout && $this->outputDisabled) {
            throw new LogicException('Idle timeout cannot be set while the output is disabled.');
        }

        $this->idleTimeout = $this->validateTimeout($timeout);

        return $this;
    }

    /**
     * Enables or disables the TTY mode.
     *
     * @return $this
     *
     * @throws RuntimeException In case the TTY mode is not supported
     */
    public function setTty(bool $tty): static
    {
        if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
            throw new RuntimeException('TTY mode is not supported on Windows platform.');
        }

        if ($tty && !self::isTtySupported()) {
            throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
        }

        $this->tty = $tty;

        return $this;
    }

    /**
     * Checks if the TTY mode is enabled.
     */
    public function isTty(): bool
    {
        return $this->tty;
    }

    /**
     * Sets PTY mode.
     *
     * @return $this
     */
    public function setPty(bool $bool): static
    {
        $this->pty = $bool;

        return $this;
    }

    /**
     * Returns PTY state.
     */
    public function isPty(): bool
    {
        return $this->pty;
    }

    /**
     * Gets the working directory.
     */
    public function getWorkingDirectory(): ?string
    {
        if (null === $this->cwd) {
            // getcwd() will return false if any one of the parent directories does not have
            // the readable or search mode set, even if the current directory does
            return getcwd() ?: null;
        }

        return $this->cwd;
    }

    /**
     * Sets the current working directory.
     *
     * @return $this
     */
    public function setWorkingDirectory(string $cwd): static
    {
        $this->cwd = $cwd;

        return $this;
    }

    /**
     * Gets the environment variables.
     */
    public function getEnv(): array
    {
        return $this->env;
    }

    /**
     * Sets the environment variables.
     *
     * @param array<string|\Stringable> $env The new environment variables
     *
     * @return $this
     */
    public function setEnv(array $env): static
    {
        $this->env = $env;

        return $this;
    }

    /**
     * Gets the Process input.
     *
     * @return resource|string|\Iterator|null
     */
    public function getInput()
    {
        return $this->input;
    }

    /**
     * Sets the input.
     *
     * This content will be passed to the underlying process standard input.
     *
     * @param string|resource|\Traversable|self|null $input The content
     *
     * @return $this
     *
     * @throws LogicException In case the process is running
     */
    public function setInput(mixed $input): static
    {
        if ($this->isRunning()) {
            throw new LogicException('Input cannot be set while the process is running.');
        }

        $this->input = ProcessUtils::validateInput(__METHOD__, $input);

        return $this;
    }

    /**
     * Performs a check between the timeout definition and the time the process started.
     *
     * In case you run a background process (with the start method), you should
     * trigger this method regularly to ensure the process timeout
     *
     * @return void
     *
     * @throws ProcessTimedOutException In case the timeout was reached
     */
    public function checkTimeout()
    {
        if (self::STATUS_STARTED !== $this->status) {
            return;
        }

        if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
            $this->stop(0);

            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
        }

        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
            $this->stop(0);

            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
        }
    }

    /**
     * @throws LogicException in case process is not started
     */
    public function getStartTime(): float
    {
        if (!$this->isStarted()) {
            throw new LogicException('Start time is only available after process start.');
        }

        return $this->starttime;
    }

    /**
     * Defines options to pass to the underlying proc_open().
     *
     * @see https://php.net/proc_open for the options supported by PHP.
     *
     * Enabling the "create_new_console" option allows a subprocess to continue
     * to run after the main process exited, on both Windows and *nix
     *
     * @return void
     */
    public function setOptions(array $options)
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Setting options while the process is running is not possible.');
        }

        $defaultOptions = $this->options;
        $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];

        foreach ($options as $key => $value) {
            if (!\in_array($key, $existingOptions)) {
                $this->options = $defaultOptions;
                throw new LogicException(\sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions)));
            }
            $this->options[$key] = $value;
        }
    }

    /**
     * Returns whether TTY is supported on the current operating system.
     */
    public static function isTtySupported(): bool
    {
        static $isTtySupported;

        return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT) && @is_writable('/dev/tty'));
    }

    /**
     * Returns whether PTY is supported on the current operating system.
     */
    public static function isPtySupported(): bool
    {
        static $result;

        if (null !== $result) {
            return $result;
        }

        if ('\\' === \DIRECTORY_SEPARATOR) {
            return $result = false;
        }

        return $result = (bool) @proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
    }

    /**
     * Creates the descriptors needed by the proc_open.
     */
    private function getDescriptors(bool $hasCallback): array
    {
        if ($this->input instanceof \Iterator) {
            $this->input->rewind();
        }
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $hasCallback);
        } else {
            $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $hasCallback);
        }

        return $this->processPipes->getDescriptors();
    }

    /**
     * Builds up the callback used by wait().
     *
     * The callbacks adds all occurred output to the specific buffer and calls
     * the user callback (if present) with the received output.
     *
     * @param callable|null $callback The user defined PHP callback
     */
    protected function buildCallback(?callable $callback = null): \Closure
    {
        if ($this->outputDisabled) {
            return fn ($type, $data): bool => null !== $callback && $callback($type, $data);
        }

        $out = self::OUT;

        return function ($type, $data) use ($callback, $out): bool {
            if ($out == $type) {
                $this->addOutput($data);
            } else {
                $this->addErrorOutput($data);
            }

            return null !== $callback && $callback($type, $data);
        };
    }

    /**
     * Updates the status of the process, reads pipes.
     *
     * @param bool $blocking Whether to use a blocking read call
     *
     * @return void
     */
    protected function updateStatus(bool $blocking)
    {
        if (self::STATUS_STARTED !== $this->status) {
            return;
        }

        if ($this->processInformation['running'] ?? true) {
            $this->processInformation = proc_get_status($this->process);
        }
        $running = $this->processInformation['running'];

        $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);

        if ($this->fallbackStatus && $this->isSigchildEnabled()) {
            $this->processInformation = $this->fallbackStatus + $this->processInformation;
        }

        if (!$running) {
            $this->close();
        }
    }

    /**
     * Returns whether PHP has been compiled with the '--enable-sigchild' option or not.
     */
    protected function isSigchildEnabled(): bool
    {
        if (null !== self::$sigchild) {
            return self::$sigchild;
        }

        if (!\function_exists('phpinfo')) {
            return self::$sigchild = false;
        }

        ob_start();
        phpinfo(\INFO_GENERAL);

        return self::$sigchild = str_contains(ob_get_clean(), '--enable-sigchild');
    }

    /**
     * Reads pipes for the freshest output.
     *
     * @param string $caller   The name of the method that needs fresh outputs
     * @param bool   $blocking Whether to use blocking calls or not
     *
     * @throws LogicException in case output has been disabled or process is not started
     */
    private function readPipesForOutput(string $caller, bool $blocking = false): void
    {
        if ($this->outputDisabled) {
            throw new LogicException('Output has been disabled.');
        }

        $this->requireProcessIsStarted($caller);

        $this->updateStatus($blocking);
    }

    /**
     * Validates and returns the filtered timeout.
     *
     * @throws InvalidArgumentException if the given timeout is a negative number
     */
    private function validateTimeout(?float $timeout): ?float
    {
        $timeout = (float) $timeout;

        if (0.0 === $timeout) {
            $timeout = null;
        } elseif ($timeout < 0) {
            throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
        }

        return $timeout;
    }

    /**
     * Reads pipes, executes callback.
     *
     * @param bool $blocking Whether to use blocking calls or not
     * @param bool $close    Whether to close file handles or not
     */
    private function readPipes(bool $blocking, bool $close): void
    {
        $result = $this->processPipes->readAndWrite($blocking, $close);

        $callback = $this->callback;
        foreach ($result as $type => $data) {
            if (3 !== $type) {
                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
            } elseif (!isset($this->fallbackStatus['signaled'])) {
                $this->fallbackStatus['exitcode'] = (int) $data;
            }
        }
    }

    /**
     * Closes process resource, closes file handles, sets the exitcode.
     *
     * @return int The exitcode
     */
    private function close(): int
    {
        $this->processPipes->close();
        if ($this->process) {
            proc_close($this->process);
            $this->process = null;
        }
        $this->exitcode = $this->processInformation['exitcode'];
        $this->status = self::STATUS_TERMINATED;

        if (-1 === $this->exitcode) {
            if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
                // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
                $this->exitcode = 128 + $this->processInformation['termsig'];
            } elseif ($this->isSigchildEnabled()) {
                $this->processInformation['signaled'] = true;
                $this->processInformation['termsig'] = -1;
            }
        }

        // Free memory from self-reference callback created by buildCallback
        // Doing so in other contexts like __destruct or by garbage collector is ineffective
        // Now pipes are closed, so the callback is no longer necessary
        $this->callback = null;

        return $this->exitcode;
    }

    /**
     * Resets data related to the latest run of the process.
     */
    private function resetProcessData(): void
    {
        $this->starttime = null;
        $this->callback = null;
        $this->exitcode = null;
        $this->fallbackStatus = [];
        $this->processInformation = [];
        $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
        $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
        $this->process = null;
        $this->latestSignal = null;
        $this->status = self::STATUS_READY;
        $this->incrementalOutputOffset = 0;
        $this->incrementalErrorOutputOffset = 0;
    }

    /**
     * Sends a POSIX signal to the process.
     *
     * @param int  $signal         A valid POSIX signal (see https://php.net/pcntl.constants)
     * @param bool $throwException Whether to throw exception in case signal failed
     *
     * @throws LogicException   In case the process is not running
     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
     * @throws RuntimeException In case of failure
     */
    private function doSignal(int $signal, bool $throwException): bool
    {
        if (null === $pid = $this->getPid()) {
            if ($throwException) {
                throw new LogicException('Cannot send signal on a non running process.');
            }

            return false;
        }

        if ('\\' === \DIRECTORY_SEPARATOR) {
            exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
            if ($exitCode && $this->isRunning()) {
                if ($throwException) {
                    throw new RuntimeException(\sprintf('Unable to kill the process (%s).', implode(' ', $output)));
                }

                return false;
            }
        } else {
            if (!$this->isSigchildEnabled()) {
                $ok = @proc_terminate($this->process, $signal);
            } elseif (\function_exists('posix_kill')) {
                $ok = @posix_kill($pid, $signal);
            } elseif ($ok = proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
                $ok = false === fgets($pipes[2]);
            }
            if (!$ok) {
                if ($throwException) {
                    throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal));
                }

                return false;
            }
        }

        $this->latestSignal = $signal;
        $this->fallbackStatus['signaled'] = true;
        $this->fallbackStatus['exitcode'] = -1;
        $this->fallbackStatus['termsig'] = $this->latestSignal;

        return true;
    }

    private function prepareWindowsCommandLine(string $cmd, array &$env): string
    {
        $uid = uniqid('', true);
        $cmd = preg_replace_callback(
            '/"(?:(
                [^"%!^]*+
                (?:
                    (?: !LF! | "(?:\^[%!^])?+" )
                    [^"%!^]*+
                )++
            ) | [^"]*+ )"/x',
            function ($m) use (&$env, $uid) {
                static $varCount = 0;
                static $varCache = [];
                if (!isset($m[1])) {
                    return $m[0];
                }
                if (isset($varCache[$m[0]])) {
                    return $varCache[$m[0]];
                }
                if (str_contains($value = $m[1], "\0")) {
                    $value = str_replace("\0", '?', $value);
                }
                if (false === strpbrk($value, "\"%!\n")) {
                    return '"'.$value.'"';
                }

                $value = str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
                $value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
                $var = $uid.++$varCount;

                $env[$var] = $value;

                return $varCache[$m[0]] = '!'.$var.'!';
            },
            $cmd
        );

        static $comSpec;

        if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) {
            // Escape according to CommandLineToArgvW rules
            $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec).'"';
        }

        $cmd = ($comSpec ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
        foreach ($this->processPipes->getFiles() as $offset => $filename) {
            $cmd .= ' '.$offset.'>"'.$filename.'"';
        }

        return $cmd;
    }

    /**
     * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
     *
     * @throws LogicException if the process has not run
     */
    private function requireProcessIsStarted(string $functionName): void
    {
        if (!$this->isStarted()) {
            throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName));
        }
    }

    /**
     * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated".
     *
     * @throws LogicException if the process is not yet terminated
     */
    private function requireProcessIsTerminated(string $functionName): void
    {
        if (!$this->isTerminated()) {
            throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName));
        }
    }

    /**
     * Escapes a string to be used as a shell argument.
     */
    private function escapeArgument(?string $argument): string
    {
        if ('' === $argument || null === $argument) {
            return '""';
        }
        if ('\\' !== \DIRECTORY_SEPARATOR) {
            return "'".str_replace("'", "'\\''", $argument)."'";
        }
        if (str_contains($argument, "\0")) {
            $argument = str_replace("\0", '?', $argument);
        }
        if (!preg_match('/[()%!^"<>&|\s]/', $argument)) {
            return $argument;
        }
        $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument);

        return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
    }

    private function replacePlaceholders(string $commandline, array $env): string
    {
        return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) {
            if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
                throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline);
            }

            return $this->escapeArgument($env[$matches[1]]);
        }, $commandline);
    }

    private function getDefaultEnv(): array
    {
        $env = getenv();
        $env = ('\\' === \DIRECTORY_SEPARATOR ? array_intersect_ukey($env, $_SERVER, 'strcasecmp') : array_intersect_key($env, $_SERVER)) ?: $env;

        return $_ENV + ('\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($env, $_ENV, 'strcasecmp') : $env);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\InvalidArgumentException;

/**
 * ProcessUtils is a bunch of utility methods.
 *
 * This class contains static methods only and is not meant to be instantiated.
 *
 * @author Martin Hasoň <martin.hason@gmail.com>
 */
class ProcessUtils
{
    /**
     * This class should not be instantiated.
     */
    private function __construct()
    {
    }

    /**
     * Validates and normalizes a Process input.
     *
     * @param string $caller The name of method call that validates the input
     * @param mixed  $input  The input to validate
     *
     * @throws InvalidArgumentException In case the input is not valid
     */
    public static function validateInput(string $caller, mixed $input): mixed
    {
        if (null !== $input) {
            if (\is_resource($input)) {
                return $input;
            }
            if (\is_scalar($input)) {
                return (string) $input;
            }
            if ($input instanceof Process) {
                return $input->getIterator($input::ITER_SKIP_ERR);
            }
            if ($input instanceof \Iterator) {
                return $input;
            }
            if ($input instanceof \Traversable) {
                return new \IteratorIterator($input);
            }

            throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
        }

        return $input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service\Attribute;

/**
 * A required dependency.
 *
 * This attribute indicates that a property holds a required dependency. The annotated property or method should be
 * considered during the instantiation process of the containing class.
 *
 * @author Alexander M. Turek <me@derrabus.de>
 */
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
final class Required
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service\Attribute;

use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
 * For use as the return value for {@see ServiceSubscriberInterface}.
 *
 * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi'))
 *
 * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type
 * as a subscribed service.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
#[\Attribute(\Attribute::TARGET_METHOD)]
final class SubscribedService
{
    /** @var object[] */
    public array $attributes;

    /**
     * @param string|null       $key        The key to use for the service
     * @param class-string|null $type       The service class
     * @param bool              $nullable   Whether the service is optional
     * @param object|object[]   $attributes One or more dependency injection attributes to use
     */
    public function __construct(
        public ?string $key = null,
        public ?string $type = null,
        public bool $nullable = false,
        array|object $attributes = [],
    ) {
        $this->attributes = \is_array($attributes) ? $attributes : [$attributes];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

/**
 * Provides a way to reset an object to its initial state.
 *
 * When calling the "reset()" method on an object, it should be put back to its
 * initial state. This usually means clearing any internal buffers and forwarding
 * the call to internal dependencies. All properties of the object should be put
 * back to the same state it had when it was first ready to use.
 *
 * This method could be called, for example, to recycle objects that are used as
 * services, so that they can be used to handle several requests in the same
 * process loop (note that we advise making your services stateless instead of
 * implementing this interface when possible.)
 */
interface ResetInterface
{
    /**
     * @return void
     */
    public function reset();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

/**
 * A ServiceProviderInterface that is also countable and iterable.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 *
 * @template-covariant T of mixed
 *
 * @extends ServiceProviderInterface<T>
 * @extends \IteratorAggregate<string, T>
 */
interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

// Help opcache.preload discover always-needed symbols
class_exists(ContainerExceptionInterface::class);
class_exists(NotFoundExceptionInterface::class);

/**
 * A trait to help implement ServiceProviderInterface.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 */
trait ServiceLocatorTrait
{
    private array $loading = [];
    private array $providedTypes;

    /**
     * @param array<string, callable> $factories
     */
    public function __construct(
        private array $factories,
    ) {
    }

    public function has(string $id): bool
    {
        return isset($this->factories[$id]);
    }

    public function get(string $id): mixed
    {
        if (!isset($this->factories[$id])) {
            throw $this->createNotFoundException($id);
        }

        if (isset($this->loading[$id])) {
            $ids = array_values($this->loading);
            $ids = \array_slice($this->loading, array_search($id, $ids));
            $ids[] = $id;

            throw $this->createCircularReferenceException($id, $ids);
        }

        $this->loading[$id] = $id;
        try {
            return $this->factories[$id]($this);
        } finally {
            unset($this->loading[$id]);
        }
    }

    public function getProvidedServices(): array
    {
        if (!isset($this->providedTypes)) {
            $this->providedTypes = [];

            foreach ($this->factories as $name => $factory) {
                if (!\is_callable($factory)) {
                    $this->providedTypes[$name] = '?';
                } else {
                    $type = (new \ReflectionFunction($factory))->getReturnType();

                    $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
                }
            }
        }

        return $this->providedTypes;
    }

    private function createNotFoundException(string $id): NotFoundExceptionInterface
    {
        if (!$alternatives = array_keys($this->factories)) {
            $message = 'is empty...';
        } else {
            $last = array_pop($alternatives);
            if ($alternatives) {
                $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
            } else {
                $message = \sprintf('only knows about the "%s" service.', $last);
            }
        }

        if ($this->loading) {
            $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
        } else {
            $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message);
        }

        return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
        };
    }

    private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
    {
        return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\Contracts\Service\Attribute\SubscribedService;

/**
 * Implementation of ServiceSubscriberInterface that determines subscribed services
 * from methods that have the #[SubscribedService] attribute.
 *
 * Service ids are available as "ClassName::methodName" so that the implementation
 * of subscriber methods can be just `return $this->container->get(__METHOD__);`.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
trait ServiceMethodsSubscriberTrait
{
    protected ContainerInterface $container;

    public static function getSubscribedServices(): array
    {
        $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];

        foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
            if (self::class !== $method->getDeclaringClass()->name) {
                continue;
            }

            if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
                continue;
            }

            if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
                throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
            }

            if (!$returnType = $method->getReturnType()) {
                throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
            }

            /* @var SubscribedService $attribute */
            $attribute = $attribute->newInstance();
            $attribute->key ??= self::class.'::'.$method->name;
            $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
            $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull();

            if ($attribute->attributes) {
                $services[] = $attribute;
            } else {
                $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;
            }
        }

        return $services;
    }

    #[Required]
    public function setContainer(ContainerInterface $container): ?ContainerInterface
    {
        $ret = null;
        if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
            $ret = parent::setContainer($container);
        }

        $this->container = $container;

        return $ret;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

use Psr\Container\ContainerInterface;

/**
 * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Mateusz Sip <mateusz.sip@gmail.com>
 *
 * @template-covariant T of mixed
 */
interface ServiceProviderInterface extends ContainerInterface
{
    /**
     * @return T
     */
    public function get(string $id): mixed;

    public function has(string $id): bool;

    /**
     * Returns an associative array of service types keyed by the identifiers provided by the current container.
     *
     * Examples:
     *
     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface
     *  * ['foo' => '?'] means the container provides service name "foo" of unspecified type
     *  * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null
     *
     * @return array<string, string> The provided service types, keyed by service names
     */
    public function getProvidedServices(): array;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

use Symfony\Contracts\Service\Attribute\SubscribedService;

/**
 * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method.
 *
 * The getSubscribedServices method returns an array of service types required by such instances,
 * optionally keyed by the service names used internally. Service types that start with an interrogation
 * mark "?" are optional, while the other ones are mandatory service dependencies.
 *
 * The injected service locators SHOULD NOT allow access to any other services not specified by the method.
 *
 * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally.
 * This interface does not dictate any injection method for these service locators, although constructor
 * injection is recommended.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
interface ServiceSubscriberInterface
{
    /**
     * Returns an array of service types (or {@see SubscribedService} objects) required
     * by such instances, optionally keyed by the service names used internally.
     *
     * For mandatory dependencies:
     *
     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name
     *    internally to fetch a service which must implement Psr\Log\LoggerInterface.
     *  * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name
     *    internally to fetch an iterable of Psr\Log\LoggerInterface instances.
     *  * ['Psr\Log\LoggerInterface'] is a shortcut for
     *  * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface']
     *
     * otherwise:
     *
     *  * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency
     *  * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency
     *  * ['?Psr\Log\LoggerInterface'] is a shortcut for
     *  * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface']
     *
     * additionally, an array of {@see SubscribedService}'s can be returned:
     *
     *  * [new SubscribedService('logger', Psr\Log\LoggerInterface::class)]
     *  * [new SubscribedService(type: Psr\Log\LoggerInterface::class, nullable: true)]
     *  * [new SubscribedService('http_client', HttpClientInterface::class, attributes: new Target('githubApi'))]
     *
     * @return string[]|SubscribedService[] The required service types, optionally keyed by service names
     */
    public static function getSubscribedServices(): array;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service;

use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\Contracts\Service\Attribute\SubscribedService;

trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class);

/**
 * Implementation of ServiceSubscriberInterface that determines subscribed services
 * from methods that have the #[SubscribedService] attribute.
 *
 * Service ids are available as "ClassName::methodName" so that the implementation
 * of subscriber methods can be just `return $this->container->get(__METHOD__);`.
 *
 * @property ContainerInterface $container
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 *
 * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead
 */
trait ServiceSubscriberTrait
{
    public static function getSubscribedServices(): array
    {
        $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];

        foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
            if (self::class !== $method->getDeclaringClass()->name) {
                continue;
            }

            if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
                continue;
            }

            if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
                throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
            }

            if (!$returnType = $method->getReturnType()) {
                throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
            }

            /* @var SubscribedService $attribute */
            $attribute = $attribute->newInstance();
            $attribute->key ??= self::class.'::'.$method->name;
            $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
            $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull();

            if ($attribute->attributes) {
                $services[] = $attribute;
            } else {
                $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;
            }
        }

        return $services;
    }

    #[Required]
    public function setContainer(ContainerInterface $container): ?ContainerInterface
    {
        $ret = null;
        if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
            $ret = parent::setContainer($container);
        }

        $this->container = $container;

        return $ret;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service\Test;

class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class);

if (false) {
    /**
     * @deprecated since PHPUnit 9.6
     */
    class ServiceLocatorTest
    {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Contracts\Service\Test;

use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Contracts\Service\ServiceLocatorTrait;

abstract class ServiceLocatorTestCase extends TestCase
{
    /**
     * @param array<string, callable> $factories
     */
    protected function getServiceLocator(array $factories): ContainerInterface
    {
        return new class($factories) implements ContainerInterface {
            use ServiceLocatorTrait;
        };
    }

    public function testHas()
    {
        $locator = $this->getServiceLocator([
            'foo' => fn () => 'bar',
            'bar' => fn () => 'baz',
            fn () => 'dummy',
        ]);

        $this->assertTrue($locator->has('foo'));
        $this->assertTrue($locator->has('bar'));
        $this->assertFalse($locator->has('dummy'));
    }

    public function testGet()
    {
        $locator = $this->getServiceLocator([
            'foo' => fn () => 'bar',
            'bar' => fn () => 'baz',
        ]);

        $this->assertSame('bar', $locator->get('foo'));
        $this->assertSame('baz', $locator->get('bar'));
    }

    public function testGetDoesNotMemoize()
    {
        $i = 0;
        $locator = $this->getServiceLocator([
            'foo' => function () use (&$i) {
                ++$i;

                return 'bar';
            },
        ]);

        $this->assertSame('bar', $locator->get('foo'));
        $this->assertSame('bar', $locator->get('foo'));
        $this->assertSame(2, $i);
    }

    public function testThrowsOnUndefinedInternalService()
    {
        $locator = $this->getServiceLocator([
            'foo' => function () use (&$locator) { return $locator->get('bar'); },
        ]);

        $this->expectException(NotFoundExceptionInterface::class);
        $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.');

        $locator->get('foo');
    }

    public function testThrowsOnCircularReference()
    {
        $locator = $this->getServiceLocator([
            'foo' => function () use (&$locator) { return $locator->get('bar'); },
            'bar' => function () use (&$locator) { return $locator->get('baz'); },
            'baz' => function () use (&$locator) { return $locator->get('bar'); },
        ]);

        $this->expectException(ContainerExceptionInterface::class);
        $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".');

        $locator->get('foo');
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <p@tchwork.com>
 * @author Hugo Hamon <hugohamon@neuf.fr>
 *
 * @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 $string = '';
    protected ?bool $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 ??= 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
     */
    public function after(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static
    {
        $str = clone $this;
        $i = \PHP_INT_MAX;

        if (\is_string($needle)) {
            $needle = [$needle];
        }

        foreach ($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
     */
    public function afterLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static
    {
        $str = clone $this;
        $i = null;

        if (\is_string($needle)) {
            $needle = [$needle];
        }

        foreach ($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);
    }

    abstract public function append(string ...$suffix): static;

    /**
     * @param string|string[] $needle
     */
    public function before(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static
    {
        $str = clone $this;
        $i = \PHP_INT_MAX;

        if (\is_string($needle)) {
            $needle = [$needle];
        }

        foreach ($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
     */
    public function beforeLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static
    {
        $str = clone $this;
        $i = null;

        if (\is_string($needle)) {
            $needle = [$needle];
        }

        foreach ($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));
    }

    abstract public function camel(): static;

    /**
     * @return static[]
     */
    abstract public function chunk(int $length = 1): array;

    public function collapseWhitespace(): static
    {
        $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(string|iterable $needle): bool
    {
        return null !== $this->indexOf($needle);
    }

    /**
     * @param string|string[] $suffix
     */
    public function endsWith(string|iterable $suffix): bool
    {
        if (\is_string($suffix)) {
            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;
    }

    public function ensureEnd(string $suffix): static
    {
        if (!$this->endsWith($suffix)) {
            return $this->append($suffix);
        }

        $suffix = preg_quote($suffix);
        $regex = '{('.$suffix.')(?:'.$suffix.')++$}D';

        return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1');
    }

    public function ensureStart(string $prefix): static
    {
        $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|iterable $string): bool
    {
        if (\is_string($string)) {
            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;
    }

    abstract public function folded(): static;

    public function ignoreCase(): static
    {
        $str = clone $this;
        $str->ignoreCase = true;

        return $str;
    }

    /**
     * @param string|string[] $needle
     */
    public function indexOf(string|iterable $needle, int $offset = 0): ?int
    {
        if (\is_string($needle)) {
            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(string|iterable $needle, int $offset = 0): ?int
    {
        if (\is_string($needle)) {
            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;
    }

    abstract public function join(array $strings, ?string $lastGlue = null): static;

    public function jsonSerialize(): string
    {
        return $this->string;
    }

    abstract public function length(): int;

    abstract public function lower(): static;

    /**
     * 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;

    abstract public function padBoth(int $length, string $padStr = ' '): static;

    abstract public function padEnd(int $length, string $padStr = ' '): static;

    abstract public function padStart(int $length, string $padStr = ' '): static;

    abstract public function prepend(string ...$prefix): static;

    public function repeat(int $multiplier): static
    {
        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;
    }

    abstract public function replace(string $from, string $to): static;

    abstract public function replaceMatches(string $fromRegexp, string|callable $to): static;

    abstract public function reverse(): static;

    abstract public function slice(int $start = 0, ?int $length = null): static;

    abstract public function snake(): static;

    public function kebab(): static
    {
        return $this->snake()->replace('_', '-');
    }

    public function pascal(): static
    {
        return $this->camel()->title();
    }

    abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static;

    /**
     * @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 fn ($t, $m) => throw new InvalidArgumentException($m));

        try {
            if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) {
                throw new RuntimeException('Splitting failed with error: '.preg_last_error_msg());
            }
        } 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(string|iterable $prefix): bool
    {
        if (\is_string($prefix)) {
            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;
    }

    abstract public function title(bool $allWords = false): static;

    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;
        }

        try {
            $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8');
        } catch (\ValueError $e) {
            if (!\function_exists('iconv')) {
                throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
            }

            $b->string = iconv('UTF-8', $toEncoding, $this->string);
        }

        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);
    }

    abstract public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static;

    abstract public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static;

    /**
     * @param string|string[] $prefix
     */
    public function trimPrefix($prefix): static
    {
        if (\is_array($prefix) || $prefix instanceof \Traversable) { // don't use is_iterable(), it's slow
            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;
    }

    abstract public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static;

    /**
     * @param string|string[] $suffix
     */
    public function trimSuffix($suffix): static
    {
        if (\is_array($suffix) || $suffix instanceof \Traversable) { // don't use is_iterable(), it's slow
            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;
    }

    public function truncate(int $length, string $ellipsis = '', bool|TruncateMode $cut = TruncateMode::Char): static
    {
        $stringLength = $this->length();

        if ($stringLength <= $length) {
            return clone $this;
        }

        $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0;

        if ($length < $ellipsisLength) {
            $ellipsisLength = 0;
        }

        $desiredLength = $length;
        if (TruncateMode::WordAfter === $cut || !$cut) {
            if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
                return clone $this;
            }

            $length += $ellipsisLength;
        } elseif (TruncateMode::WordBefore === $cut && null !== $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
            $length += $ellipsisLength;
        }

        $str = $this->slice(0, $length - $ellipsisLength);

        if (TruncateMode::WordBefore === $cut) {
            if (0 === $ellipsisLength && $desiredLength === $this->indexOf([' ', "\r", "\n", "\t"], $length)) {
                return $str;
            }

            $str = $str->beforeLast([' ', "\r", "\n", "\t"]);
        }

        return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
    }

    abstract public function upper(): static;

    /**
     * Returns the printable length on a terminal.
     */
    abstract public function width(bool $ignoreAnsiDecoration = true): int;

    public function wordwrap(int $width = 75, string $break = "\n", bool $cut = false): static
    {
        $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;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <p@tchwork.com>
 *
 * @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", 'ß', 'ŉ', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ﬀ', 'ﬁ', 'ﬂ', 'ﬃ', 'ﬄ', 'ﬅ', 'ﬆ', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ'];
    private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ'];

    // 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 = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ŉ', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'Ǆ', 'ǅ', 'ǆ', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '｟', '｠', '｡', '､', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆'];
    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 array $transliterators = [];
    private static array $tableZero;
    private static array $tableWide;

    public static function fromCodePoints(int ...$codes): static
    {
        $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] ??= \Transliterator::create($rule)) {
                        if ('any-latin/bgn' === $rule) {
                            $rule = 'any-latin';
                            $transliterator = 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 {
                $previousLocale = setlocale(\LC_CTYPE, 0);
                try {
                    setlocale(\LC_CTYPE, 'C');
                    $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);
                } finally {
                    setlocale(\LC_CTYPE, $previousLocale);
                }
            }
        }

        $str->string .= $s;

        return $str;
    }

    public function camel(): static
    {
        $str = clone $this;
        $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?!\p{Lu})/u', static function ($m) {
            static $i = 0;

            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): static
    {
        $str = clone $this;

        if (!$compat || !\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, $str->string), 'UTF-8');
        } else {
            $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF);
        }

        return $str;
    }

    public function join(array $strings, ?string $lastGlue = null): static
    {
        $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(): static
    {
        $str = clone $this;
        $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8');

        return $str;
    }

    /**
     * @param string $locale In the format language_region (e.g. tr_TR)
     */
    public function localeLower(string $locale): static
    {
        if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Lower')) {
            $str = clone $this;
            $str->string = $transliterator->transliterate($str->string);

            return $str;
        }

        return $this->lower();
    }

    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 fn ($t, $m) => throw new InvalidArgumentException($m));

        try {
            if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
                throw new RuntimeException('Matching failed with error: '.preg_last_error_msg());
            }
        } finally {
            restore_error_handler();
        }

        return $matches;
    }

    public function normalize(int $form = self::NFC): static
    {
        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 = ' '): static
    {
        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 = ' '): static
    {
        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 = ' '): static
    {
        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, string|callable $to): static
    {
        if ($this->ignoreCase) {
            $fromRegexp .= 'i';
        }

        if (\is_array($to) || $to instanceof \Closure) {
            $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 fn ($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 && str_ends_with($k, '_ERROR')) {
                        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(): static
    {
        $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(): static
    {
        $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): static
    {
        $str = clone $this;

        $limit = $allWords ? -1 : 1;

        $str->string = preg_replace_callback('/\b./u', static fn (array $m): string => mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'), $str->string, $limit);

        return $str;
    }

    /**
     * @param string $locale In the format language_region (e.g. tr_TR)
     */
    public function localeTitle(string $locale): static
    {
        if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Title')) {
            $str = clone $this;
            $str->string = $transliterator->transliterate($str->string);

            return $str;
        }

        return $this->title();
    }

    public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static
    {
        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}"): static
    {
        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): static
    {
        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}"): static
    {
        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): static
    {
        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(): static
    {
        $str = clone $this;
        $str->string = mb_strtoupper($str->string, 'UTF-8');

        return $str;
    }

    /**
     * @param string $locale In the format language_region (e.g. tr_TR)
     */
    public function localeUpper(string $locale): static
    {
        if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Upper')) {
            $str = clone $this;
            $str->string = $transliterator->transliterate($str->string);

            return $str;
        }

        return $this->upper();
    }

    public function width(bool $ignoreAnsiDecoration = true): int
    {
        $width = 0;
        $s = str_replace(["\x00", "\x05", "\x07"], '', $this->string);

        if (str_contains($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;
    }

    private function pad(int $len, self $pad, int $type): static
    {
        $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;
            }

            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;
                    }
                }
            }

            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;
    }

    private function getLocaleTransliterator(string $locale, string $id): ?\Transliterator
    {
        $rule = $locale.'-'.$id;
        if (\array_key_exists($rule, self::$transliterators)) {
            return self::$transliterators[$rule];
        }

        if (null !== $transliterator = self::$transliterators[$rule] = \Transliterator::create($rule)) {
            return $transliterator;
        }

        // Try to find a parent locale (nl_BE -> nl)
        if (false === $i = strpos($locale, '_')) {
            return null;
        }

        $parentRule = substr_replace($locale, '-'.$id, $i);

        // Parent locale was already cached, return and store as current locale
        if (\array_key_exists($parentRule, self::$transliterators)) {
            return self::$transliterators[$rule] = self::$transliterators[$parentRule];
        }

        // Create transliterator based on parent locale and cache the result on both initial and parent locale values
        $transliterator = \Transliterator::create($parentRule);

        return self::$transliterators[$rule] = self::$transliterators[$parentRule] = $transliterator;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String;

use Random\Randomizer;
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 <p@tchwork.com>
 * @author Hugo Hamon <hugohamon@neuf.fr>
 *
 * @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 ??= 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.');
        }

        if (\PHP_VERSION_ID >= 80300) {
            return new static((new Randomizer())->getBytesFromString($alphabet, $length));
        }

        $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): static
    {
        $str = clone $this;
        $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);

        return $str;
    }

    public function camel(): static
    {
        $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(string|iterable|AbstractString $suffix): bool
    {
        if ($suffix instanceof AbstractString) {
            $suffix = $suffix->string;
        } elseif (!\is_string($suffix)) {
            return parent::endsWith($suffix);
        }

        return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase);
    }

    public function equalsTo(string|iterable|AbstractString $string): bool
    {
        if ($string instanceof AbstractString) {
            $string = $string->string;
        } elseif (!\is_string($string)) {
            return parent::equalsTo($string);
        }

        if ('' !== $string && $this->ignoreCase) {
            return 0 === strcasecmp($string, $this->string);
        }

        return $string === $this->string;
    }

    public function folded(): static
    {
        $str = clone $this;
        $str->string = strtolower($str->string);

        return $str;
    }

    public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOf($needle, $offset);
        }

        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(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOfLast($needle, $offset);
        }

        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): static
    {
        $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(): static
    {
        $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 fn ($t, $m) => throw new InvalidArgumentException($m));

        try {
            if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
                throw new RuntimeException('Matching failed with error: '.preg_last_error_msg());
            }
        } finally {
            restore_error_handler();
        }

        return $matches;
    }

    public function padBoth(int $length, string $padStr = ' '): static
    {
        $str = clone $this;
        $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH);

        return $str;
    }

    public function padEnd(int $length, string $padStr = ' '): static
    {
        $str = clone $this;
        $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT);

        return $str;
    }

    public function padStart(int $length, string $padStr = ' '): static
    {
        $str = clone $this;
        $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT);

        return $str;
    }

    public function prepend(string ...$prefix): static
    {
        $str = clone $this;
        $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string;

        return $str;
    }

    public function replace(string $from, string $to): static
    {
        $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, string|callable $to): static
    {
        if ($this->ignoreCase) {
            $fromRegexp .= 'i';
        }

        $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace';

        set_error_handler(static fn ($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 && str_ends_with($k, '_ERROR')) {
                        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(): static
    {
        $str = clone $this;
        $str->string = strrev($str->string);

        return $str;
    }

    public function slice(int $start = 0, ?int $length = null): static
    {
        $str = clone $this;
        $str->string = substr($this->string, $start, $length ?? \PHP_INT_MAX);

        return $str;
    }

    public function snake(): static
    {
        $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): static
    {
        $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 ??= \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(string|iterable|AbstractString $prefix): bool
    {
        if ($prefix instanceof AbstractString) {
            $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): static
    {
        $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 fn ($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"): static
    {
        $str = clone $this;
        $str->string = trim($str->string, $chars);

        return $str;
    }

    public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): static
    {
        $str = clone $this;
        $str->string = rtrim($str->string, $chars);

        return $str;
    }

    public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): static
    {
        $str = clone $this;
        $str->string = ltrim($str->string, $chars);

        return $str;
    }

    public function upper(): static
    {
        $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);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <p@tchwork.com>
 * @author Hugo Hamon <hugohamon@neuf.fr>
 *
 * @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): static
    {
        $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(string|iterable|AbstractString $suffix): bool
    {
        if ($suffix instanceof AbstractString) {
            $suffix = $suffix->string;
        } elseif (!\is_string($suffix)) {
            return parent::endsWith($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|iterable|AbstractString $string): bool
    {
        if ($string instanceof AbstractString) {
            $string = $string->string;
        } elseif (!\is_string($string)) {
            return parent::equalsTo($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(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOf($needle, $offset);
        }

        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(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOfLast($needle, $offset);
        }

        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): static
    {
        $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): static
    {
        $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): static
    {
        $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): static
    {
        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 ??= \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(string|iterable|AbstractString $prefix): bool
    {
        if ($prefix instanceof AbstractString) {
            $prefix = $prefix->string;
        } elseif (!\is_string($prefix)) {
            return parent::startsWith($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));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Exception;

interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Exception;

class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 vowel
        // Fourth entry: Whether the suffix may succeed a consonant
        // Fifth entry: singular suffix, normal

        // insignias (insigne), insignia (insigne)
        ['saingisni', 9, true, true, 'insigne'],
        ['aingisni', 8, true, true, 'insigne'],

        // passersby (passerby)
        ['ybsressap', 9, true, true, 'passerby'],

        // nodes (node)
        ['sedon', 5, true, true, 'node'],

        // bacteria (bacterium)
        ['airetcab', 8, true, true, 'bacterium'],

        // issues (issue)
        ['seussi', 6, true, true, 'issue'],

        // corpora (corpus)
        ['aroproc', 7, true, true, 'corpus'],

        // criteria (criterion)
        ['airetirc', 8, true, true, 'criterion'],

        // curricula (curriculum)
        ['alucirruc', 9, true, true, 'curriculum'],

        // quora (quorum)
        ['arouq', 5, true, true, 'quorum'],

        // genera (genus)
        ['areneg', 6, true, true, 'genus'],

        // media (medium)
        ['aidem', 5, true, true, 'medium'],

        // memoranda (memorandum)
        ['adnaromem', 9, true, true, 'memorandum'],

        // phenomena (phenomenon)
        ['anemonehp', 9, true, true, 'phenomenon'],

        // strata (stratum)
        ['atarts', 6, true, true, 'stratum'],

        // 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'],

        // article (articles), ancle (ancles)
        ['sel', 3, true, true, 'le'],

        // 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'],

        // outages (outage) - specific fix to avoid 'outag'
        ['segatuo', 7, true, true, 'outage'],

        // 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 vowel
        // Fourth entry: Whether the suffix may succeed a consonant
        // Fifth entry: plural suffix, normal

        // passerby (passersby)
        ['ybressap', 8, true, true, 'passersby'],

        // insigne (insignia, insignias)
        ['engisni', 7, true, true, ['insignia', 'insignias']],

        // nodes (node)
        ['edon', 4, true, true, 'nodes'],

        // axes (axis)
        ['sixa', 4, false, false, 'axes'],

        // 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'],

        // albums (album)
        ['mubla', 5, true, true, 'albums'],

        // quorums (quorum)
        ['murouq', 6, true, true, ['quora', 'quorums']],

        // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum)
        ['mu', 2, true, true, 'a'],

        // men (man), women (woman)
        ['nam', 3, true, true, 'men'],

        // people (person)
        ['nosrep', 6, true, true, ['persons', 'people']],

        // criteria (criterion)
        ['noiretirc', 9, true, true, 'criteria'],

        // phenomena (phenomenon)
        ['nonemonehp', 10, true, true, 'phenomena'],

        // echoes (echo)
        ['ohce', 4, true, true, 'echoes'],

        // heroes (hero)
        ['oreh', 4, true, true, 'heroes'],

        // atlases (atlas)
        ['salta', 5, true, true, 'atlases'],

        // aliases (alias)
        ['saila', 5, true, true, 'aliases'],

        // 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'],

        // hippocampi (hippocampus)
        ['supmacoppih', 11, false, false, 'hippocampi'],

        // campuses (campus)
        ['sup', 3, true, true, 'puses'],

        // status (status)
        ['sutats', 6, true, true, ['status', 'statuses']],

        // conspectuses (conspectus), prospectuses (prospectus)
        ['sutcep', 6, true, true, 'pectuses'],

        // nexuses (nexus)
        ['suxen', 5, false, false, 'nexuses'],

        // 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']],

        // fax (faxes, faxxes)
        ['xaf', 3, true, true, ['faxes', 'faxxes']],

        // boxes (box)
        ['xo', 2, false, true, 'oxes'],

        // indexes (index), matrixes (matrix), appendices (appendix)
        ['x', 1, true, false, ['ces', 'xes']],

        // 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',

        // equipment
        'tnempiuqe',

        // feedback
        'kcabdeef',

        // fish
        'hsif',

        // health
        'htlaeh',

        // history
        'yrotsih',

        // info
        'ofni',

        // information
        'noitamrofni',

        // money
        'yenom',

        // moose
        'esoom',

        // series
        'seires',

        // sheep
        'peehs',

        // species
        'seiceps',

        // traffic
        'ciffart',

        // aircraft
        'tfarcria',

        // hardware
        'erawdrah',
    ];

    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) {
                        $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]);

                        if (!$map[2] && $nextIsVowel) {
                            // suffix may not succeed a vowel but next char is one
                            break;
                        }

                        if (!$map[3] && !$nextIsVowel) {
                            // 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];
    }

    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) {
                        $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]);

                        if (!$map[2] && $nextIsVowel) {
                            // suffix may not succeed a vowel but next char is one
                            break;
                        }

                        if (!$map[3] && !$nextIsVowel) {
                            // 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'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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';

    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];
    }

    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);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Inflector;

final class SpanishInflector implements InflectorInterface
{
    /**
     * A list of all rules for pluralise.
     *
     * @see https://www.spanishdict.com/guide/spanish-plural-noun-forms
     * @see https://www.rae.es/gram%C3%A1tica/morfolog%C3%ADa/la-formaci%C3%B3n-del-plural-plurales-en-s-y-plurales-en-es-reglas-generales
     */
    // First entry: regex
    // Second entry: replacement
    private const PLURALIZE_REGEXP = [
        // Specials sí, no
        ['/(sí|no)$/i', '\1es'],

        // Words ending with vowel must use -s (RAE 3.2a, 3.2c)
        ['/(a|e|i|o|u|á|é|í|ó|ú)$/i', '\1s'],

        // Word ending in s or x and the previous letter is accented (RAE 3.2n)
        ['/ás$/i', 'ases'],
        ['/és$/i', 'eses'],
        ['/ís$/i', 'ises'],
        ['/ós$/i', 'oses'],
        ['/ús$/i', 'uses'],

        // Words ending in -ión must changed to -iones
        ['/ión$/i', '\1iones'],

        // Words ending in some consonants must use -es (RAE 3.2k)
        ['/(l|r|n|d|j|s|x|ch|y)$/i', '\1es'],

        // Word ending in z, must changed to ces
        ['/(z)$/i', 'ces'],
    ];

    /**
     * A list of all rules for singularize.
     */
    private const SINGULARIZE_REGEXP = [
        // Specials sí, no
        ['/(sí|no)es$/i', '\1'],

        // Words ending in -ión must changed to -iones
        ['/iones$/i', '\1ión'],

        // Word ending in z, must changed to ces
        ['/ces$/i', 'z'],

        // Word ending in s or x and the previous letter is accented (RAE 3.2n)
        ['/(\w)ases$/i', '\1ás'],
        ['/eses$/i', 'és'],
        ['/ises$/i', 'ís'],
        ['/(\w{2,})oses$/i', '\1ós'],
        ['/(\w)uses$/i', '\1ús'],

        // Words ending in some consonants and -es, must be the consonants
        ['/(l|r|n|d|j|s|x|ch|y)e?s$/i', '\1'],

        // Words ended with vowel and s, must be vowel
        ['/(a|e|i|o|u|á|é|ó|í|ú)s$/i', '\1'],
    ];

    private const UNINFLECTED_RULES = [
        // Words ending with pies (RAE 3.2n)
        '/.*(piés)$/i',
    ];

    private const UNINFLECTED = '/^(lunes|martes|miércoles|jueves|viernes|análisis|torax|yo|pies)$/i';

    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];
    }

    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
    {
        foreach (self::UNINFLECTED_RULES as $rule) {
            if (1 === preg_match($rule, $word)) {
                return true;
            }
        }

        return 1 === preg_match(self::UNINFLECTED, $word);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String;

/**
 * A string whose value is computed lazily by a callback.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class LazyString implements \Stringable, \JsonSerializable
{
    private \Closure|string $value;

    /**
     * @param callable|array $callback A callable or a [Closure, method] lazy-callable
     */
    public static function fromCallable(callable|array $callback, mixed ...$arguments): static
    {
        if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) 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__, '['.implode(', ', array_map('get_debug_type', $callback)).']'));
        }

        $lazyString = new static();
        $lazyString->value = static function () use (&$callback, &$arguments): string {
            static $value;

            if (null !== $arguments) {
                if (!\is_callable($callback)) {
                    $callback[0] = $callback[0]();
                    $callback[1] ??= '__invoke';
                }
                $value = $callback(...$arguments);
                $callback = !\is_scalar($value) && !$value instanceof \Stringable ? self::getPrettyName($callback) : 'callable';
                $arguments = null;
            }

            return $value ?? '';
        };

        return $lazyString;
    }

    public static function fromStringable(string|int|float|bool|\Stringable $value): static
    {
        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(mixed $value): bool
    {
        return \is_string($value) || $value instanceof \Stringable || \is_scalar($value);
    }

    /**
     * Casts scalars and stringable objects to strings.
     *
     * @throws \TypeError When the provided value is not stringable
     */
    final public static function resolve(\Stringable|string|int|float|bool $value): string
    {
        return $value;
    }

    public function __toString(): string
    {
        if (\is_string($this->value)) {
            return $this->value;
        }

        try {
            return $this->value = ($this->value)();
        } catch (\Throwable $e) {
            if (\TypeError::class === $e::class && __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));
            }

            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 ($r->isAnonymous() || !$class = $r->getClosureCalledClass()) {
                return $r->name;
            }

            $class = $class->name;
            $method = $r->name;
        } else {
            $class = get_debug_type($callback);
            $method = '__invoke';
        }

        return $class.'::'.$method;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * This file has been auto-generated by the Symfony String Component for internal use.
 *
 * Unicode version: 16.0.0
 * Date: 2024-09-11T08:21:22+00:00
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

return [
    [
        4352,
        4447,
    ],
    [
        8986,
        8987,
    ],
    [
        9001,
        9001,
    ],
    [
        9002,
        9002,
    ],
    [
        9193,
        9196,
    ],
    [
        9200,
        9200,
    ],
    [
        9203,
        9203,
    ],
    [
        9725,
        9726,
    ],
    [
        9748,
        9749,
    ],
    [
        9776,
        9783,
    ],
    [
        9800,
        9811,
    ],
    [
        9855,
        9855,
    ],
    [
        9866,
        9871,
    ],
    [
        9875,
        9875,
    ],
    [
        9889,
        9889,
    ],
    [
        9898,
        9899,
    ],
    [
        9917,
        9918,
    ],
    [
        9924,
        9925,
    ],
    [
        9934,
        9934,
    ],
    [
        9940,
        9940,
    ],
    [
        9962,
        9962,
    ],
    [
        9970,
        9971,
    ],
    [
        9973,
        9973,
    ],
    [
        9978,
        9978,
    ],
    [
        9981,
        9981,
    ],
    [
        9989,
        9989,
    ],
    [
        9994,
        9995,
    ],
    [
        10024,
        10024,
    ],
    [
        10060,
        10060,
    ],
    [
        10062,
        10062,
    ],
    [
        10067,
        10069,
    ],
    [
        10071,
        10071,
    ],
    [
        10133,
        10135,
    ],
    [
        10160,
        10160,
    ],
    [
        10175,
        10175,
    ],
    [
        11035,
        11036,
    ],
    [
        11088,
        11088,
    ],
    [
        11093,
        11093,
    ],
    [
        11904,
        11929,
    ],
    [
        11931,
        12019,
    ],
    [
        12032,
        12245,
    ],
    [
        12272,
        12287,
    ],
    [
        12288,
        12288,
    ],
    [
        12289,
        12291,
    ],
    [
        12292,
        12292,
    ],
    [
        12293,
        12293,
    ],
    [
        12294,
        12294,
    ],
    [
        12295,
        12295,
    ],
    [
        12296,
        12296,
    ],
    [
        12297,
        12297,
    ],
    [
        12298,
        12298,
    ],
    [
        12299,
        12299,
    ],
    [
        12300,
        12300,
    ],
    [
        12301,
        12301,
    ],
    [
        12302,
        12302,
    ],
    [
        12303,
        12303,
    ],
    [
        12304,
        12304,
    ],
    [
        12305,
        12305,
    ],
    [
        12306,
        12307,
    ],
    [
        12308,
        12308,
    ],
    [
        12309,
        12309,
    ],
    [
        12310,
        12310,
    ],
    [
        12311,
        12311,
    ],
    [
        12312,
        12312,
    ],
    [
        12313,
        12313,
    ],
    [
        12314,
        12314,
    ],
    [
        12315,
        12315,
    ],
    [
        12316,
        12316,
    ],
    [
        12317,
        12317,
    ],
    [
        12318,
        12319,
    ],
    [
        12320,
        12320,
    ],
    [
        12321,
        12329,
    ],
    [
        12330,
        12333,
    ],
    [
        12334,
        12335,
    ],
    [
        12336,
        12336,
    ],
    [
        12337,
        12341,
    ],
    [
        12342,
        12343,
    ],
    [
        12344,
        12346,
    ],
    [
        12347,
        12347,
    ],
    [
        12348,
        12348,
    ],
    [
        12349,
        12349,
    ],
    [
        12350,
        12350,
    ],
    [
        12353,
        12438,
    ],
    [
        12441,
        12442,
    ],
    [
        12443,
        12444,
    ],
    [
        12445,
        12446,
    ],
    [
        12447,
        12447,
    ],
    [
        12448,
        12448,
    ],
    [
        12449,
        12538,
    ],
    [
        12539,
        12539,
    ],
    [
        12540,
        12542,
    ],
    [
        12543,
        12543,
    ],
    [
        12549,
        12591,
    ],
    [
        12593,
        12686,
    ],
    [
        12688,
        12689,
    ],
    [
        12690,
        12693,
    ],
    [
        12694,
        12703,
    ],
    [
        12704,
        12735,
    ],
    [
        12736,
        12773,
    ],
    [
        12783,
        12783,
    ],
    [
        12784,
        12799,
    ],
    [
        12800,
        12830,
    ],
    [
        12832,
        12841,
    ],
    [
        12842,
        12871,
    ],
    [
        12880,
        12880,
    ],
    [
        12881,
        12895,
    ],
    [
        12896,
        12927,
    ],
    [
        12928,
        12937,
    ],
    [
        12938,
        12976,
    ],
    [
        12977,
        12991,
    ],
    [
        12992,
        13055,
    ],
    [
        13056,
        13311,
    ],
    [
        13312,
        19903,
    ],
    [
        19904,
        19967,
    ],
    [
        19968,
        40959,
    ],
    [
        40960,
        40980,
    ],
    [
        40981,
        40981,
    ],
    [
        40982,
        42124,
    ],
    [
        42128,
        42182,
    ],
    [
        43360,
        43388,
    ],
    [
        44032,
        55203,
    ],
    [
        63744,
        64109,
    ],
    [
        64110,
        64111,
    ],
    [
        64112,
        64217,
    ],
    [
        64218,
        64255,
    ],
    [
        65040,
        65046,
    ],
    [
        65047,
        65047,
    ],
    [
        65048,
        65048,
    ],
    [
        65049,
        65049,
    ],
    [
        65072,
        65072,
    ],
    [
        65073,
        65074,
    ],
    [
        65075,
        65076,
    ],
    [
        65077,
        65077,
    ],
    [
        65078,
        65078,
    ],
    [
        65079,
        65079,
    ],
    [
        65080,
        65080,
    ],
    [
        65081,
        65081,
    ],
    [
        65082,
        65082,
    ],
    [
        65083,
        65083,
    ],
    [
        65084,
        65084,
    ],
    [
        65085,
        65085,
    ],
    [
        65086,
        65086,
    ],
    [
        65087,
        65087,
    ],
    [
        65088,
        65088,
    ],
    [
        65089,
        65089,
    ],
    [
        65090,
        65090,
    ],
    [
        65091,
        65091,
    ],
    [
        65092,
        65092,
    ],
    [
        65093,
        65094,
    ],
    [
        65095,
        65095,
    ],
    [
        65096,
        65096,
    ],
    [
        65097,
        65100,
    ],
    [
        65101,
        65103,
    ],
    [
        65104,
        65106,
    ],
    [
        65108,
        65111,
    ],
    [
        65112,
        65112,
    ],
    [
        65113,
        65113,
    ],
    [
        65114,
        65114,
    ],
    [
        65115,
        65115,
    ],
    [
        65116,
        65116,
    ],
    [
        65117,
        65117,
    ],
    [
        65118,
        65118,
    ],
    [
        65119,
        65121,
    ],
    [
        65122,
        65122,
    ],
    [
        65123,
        65123,
    ],
    [
        65124,
        65126,
    ],
    [
        65128,
        65128,
    ],
    [
        65129,
        65129,
    ],
    [
        65130,
        65131,
    ],
    [
        65281,
        65283,
    ],
    [
        65284,
        65284,
    ],
    [
        65285,
        65287,
    ],
    [
        65288,
        65288,
    ],
    [
        65289,
        65289,
    ],
    [
        65290,
        65290,
    ],
    [
        65291,
        65291,
    ],
    [
        65292,
        65292,
    ],
    [
        65293,
        65293,
    ],
    [
        65294,
        65295,
    ],
    [
        65296,
        65305,
    ],
    [
        65306,
        65307,
    ],
    [
        65308,
        65310,
    ],
    [
        65311,
        65312,
    ],
    [
        65313,
        65338,
    ],
    [
        65339,
        65339,
    ],
    [
        65340,
        65340,
    ],
    [
        65341,
        65341,
    ],
    [
        65342,
        65342,
    ],
    [
        65343,
        65343,
    ],
    [
        65344,
        65344,
    ],
    [
        65345,
        65370,
    ],
    [
        65371,
        65371,
    ],
    [
        65372,
        65372,
    ],
    [
        65373,
        65373,
    ],
    [
        65374,
        65374,
    ],
    [
        65375,
        65375,
    ],
    [
        65376,
        65376,
    ],
    [
        65504,
        65505,
    ],
    [
        65506,
        65506,
    ],
    [
        65507,
        65507,
    ],
    [
        65508,
        65508,
    ],
    [
        65509,
        65510,
    ],
    [
        94176,
        94177,
    ],
    [
        94178,
        94178,
    ],
    [
        94179,
        94179,
    ],
    [
        94180,
        94180,
    ],
    [
        94192,
        94193,
    ],
    [
        94208,
        100343,
    ],
    [
        100352,
        101119,
    ],
    [
        101120,
        101589,
    ],
    [
        101631,
        101631,
    ],
    [
        101632,
        101640,
    ],
    [
        110576,
        110579,
    ],
    [
        110581,
        110587,
    ],
    [
        110589,
        110590,
    ],
    [
        110592,
        110847,
    ],
    [
        110848,
        110882,
    ],
    [
        110898,
        110898,
    ],
    [
        110928,
        110930,
    ],
    [
        110933,
        110933,
    ],
    [
        110948,
        110951,
    ],
    [
        110960,
        111355,
    ],
    [
        119552,
        119638,
    ],
    [
        119648,
        119670,
    ],
    [
        126980,
        126980,
    ],
    [
        127183,
        127183,
    ],
    [
        127374,
        127374,
    ],
    [
        127377,
        127386,
    ],
    [
        127488,
        127490,
    ],
    [
        127504,
        127547,
    ],
    [
        127552,
        127560,
    ],
    [
        127568,
        127569,
    ],
    [
        127584,
        127589,
    ],
    [
        127744,
        127776,
    ],
    [
        127789,
        127797,
    ],
    [
        127799,
        127868,
    ],
    [
        127870,
        127891,
    ],
    [
        127904,
        127946,
    ],
    [
        127951,
        127955,
    ],
    [
        127968,
        127984,
    ],
    [
        127988,
        127988,
    ],
    [
        127992,
        127994,
    ],
    [
        127995,
        127999,
    ],
    [
        128000,
        128062,
    ],
    [
        128064,
        128064,
    ],
    [
        128066,
        128252,
    ],
    [
        128255,
        128317,
    ],
    [
        128331,
        128334,
    ],
    [
        128336,
        128359,
    ],
    [
        128378,
        128378,
    ],
    [
        128405,
        128406,
    ],
    [
        128420,
        128420,
    ],
    [
        128507,
        128511,
    ],
    [
        128512,
        128591,
    ],
    [
        128640,
        128709,
    ],
    [
        128716,
        128716,
    ],
    [
        128720,
        128722,
    ],
    [
        128725,
        128727,
    ],
    [
        128732,
        128735,
    ],
    [
        128747,
        128748,
    ],
    [
        128756,
        128764,
    ],
    [
        128992,
        129003,
    ],
    [
        129008,
        129008,
    ],
    [
        129292,
        129338,
    ],
    [
        129340,
        129349,
    ],
    [
        129351,
        129535,
    ],
    [
        129648,
        129660,
    ],
    [
        129664,
        129673,
    ],
    [
        129679,
        129734,
    ],
    [
        129742,
        129756,
    ],
    [
        129759,
        129769,
    ],
    [
        129776,
        129784,
    ],
    [
        131072,
        173791,
    ],
    [
        173792,
        173823,
    ],
    [
        173824,
        177977,
    ],
    [
        177978,
        177983,
    ],
    [
        177984,
        178205,
    ],
    [
        178206,
        178207,
    ],
    [
        178208,
        183969,
    ],
    [
        183970,
        183983,
    ],
    [
        183984,
        191456,
    ],
    [
        191457,
        191471,
    ],
    [
        191472,
        192093,
    ],
    [
        192094,
        194559,
    ],
    [
        194560,
        195101,
    ],
    [
        195102,
        195103,
    ],
    [
        195104,
        196605,
    ],
    [
        196608,
        201546,
    ],
    [
        201547,
        201551,
    ],
    [
        201552,
        205743,
    ],
    [
        205744,
        262141,
    ],
];
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * This file has been auto-generated by the Symfony String Component for internal use.
 *
 * Unicode version: 16.0.0
 * Date: 2024-09-11T08:21:22+00:00
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

return [
    [
        768,
        879,
    ],
    [
        1155,
        1159,
    ],
    [
        1160,
        1161,
    ],
    [
        1425,
        1469,
    ],
    [
        1471,
        1471,
    ],
    [
        1473,
        1474,
    ],
    [
        1476,
        1477,
    ],
    [
        1479,
        1479,
    ],
    [
        1552,
        1562,
    ],
    [
        1611,
        1631,
    ],
    [
        1648,
        1648,
    ],
    [
        1750,
        1756,
    ],
    [
        1759,
        1764,
    ],
    [
        1767,
        1768,
    ],
    [
        1770,
        1773,
    ],
    [
        1809,
        1809,
    ],
    [
        1840,
        1866,
    ],
    [
        1958,
        1968,
    ],
    [
        2027,
        2035,
    ],
    [
        2045,
        2045,
    ],
    [
        2070,
        2073,
    ],
    [
        2075,
        2083,
    ],
    [
        2085,
        2087,
    ],
    [
        2089,
        2093,
    ],
    [
        2137,
        2139,
    ],
    [
        2199,
        2207,
    ],
    [
        2250,
        2273,
    ],
    [
        2275,
        2306,
    ],
    [
        2362,
        2362,
    ],
    [
        2364,
        2364,
    ],
    [
        2369,
        2376,
    ],
    [
        2381,
        2381,
    ],
    [
        2385,
        2391,
    ],
    [
        2402,
        2403,
    ],
    [
        2433,
        2433,
    ],
    [
        2492,
        2492,
    ],
    [
        2497,
        2500,
    ],
    [
        2509,
        2509,
    ],
    [
        2530,
        2531,
    ],
    [
        2558,
        2558,
    ],
    [
        2561,
        2562,
    ],
    [
        2620,
        2620,
    ],
    [
        2625,
        2626,
    ],
    [
        2631,
        2632,
    ],
    [
        2635,
        2637,
    ],
    [
        2641,
        2641,
    ],
    [
        2672,
        2673,
    ],
    [
        2677,
        2677,
    ],
    [
        2689,
        2690,
    ],
    [
        2748,
        2748,
    ],
    [
        2753,
        2757,
    ],
    [
        2759,
        2760,
    ],
    [
        2765,
        2765,
    ],
    [
        2786,
        2787,
    ],
    [
        2810,
        2815,
    ],
    [
        2817,
        2817,
    ],
    [
        2876,
        2876,
    ],
    [
        2879,
        2879,
    ],
    [
        2881,
        2884,
    ],
    [
        2893,
        2893,
    ],
    [
        2901,
        2902,
    ],
    [
        2914,
        2915,
    ],
    [
        2946,
        2946,
    ],
    [
        3008,
        3008,
    ],
    [
        3021,
        3021,
    ],
    [
        3072,
        3072,
    ],
    [
        3076,
        3076,
    ],
    [
        3132,
        3132,
    ],
    [
        3134,
        3136,
    ],
    [
        3142,
        3144,
    ],
    [
        3146,
        3149,
    ],
    [
        3157,
        3158,
    ],
    [
        3170,
        3171,
    ],
    [
        3201,
        3201,
    ],
    [
        3260,
        3260,
    ],
    [
        3263,
        3263,
    ],
    [
        3270,
        3270,
    ],
    [
        3276,
        3277,
    ],
    [
        3298,
        3299,
    ],
    [
        3328,
        3329,
    ],
    [
        3387,
        3388,
    ],
    [
        3393,
        3396,
    ],
    [
        3405,
        3405,
    ],
    [
        3426,
        3427,
    ],
    [
        3457,
        3457,
    ],
    [
        3530,
        3530,
    ],
    [
        3538,
        3540,
    ],
    [
        3542,
        3542,
    ],
    [
        3633,
        3633,
    ],
    [
        3636,
        3642,
    ],
    [
        3655,
        3662,
    ],
    [
        3761,
        3761,
    ],
    [
        3764,
        3772,
    ],
    [
        3784,
        3790,
    ],
    [
        3864,
        3865,
    ],
    [
        3893,
        3893,
    ],
    [
        3895,
        3895,
    ],
    [
        3897,
        3897,
    ],
    [
        3953,
        3966,
    ],
    [
        3968,
        3972,
    ],
    [
        3974,
        3975,
    ],
    [
        3981,
        3991,
    ],
    [
        3993,
        4028,
    ],
    [
        4038,
        4038,
    ],
    [
        4141,
        4144,
    ],
    [
        4146,
        4151,
    ],
    [
        4153,
        4154,
    ],
    [
        4157,
        4158,
    ],
    [
        4184,
        4185,
    ],
    [
        4190,
        4192,
    ],
    [
        4209,
        4212,
    ],
    [
        4226,
        4226,
    ],
    [
        4229,
        4230,
    ],
    [
        4237,
        4237,
    ],
    [
        4253,
        4253,
    ],
    [
        4957,
        4959,
    ],
    [
        5906,
        5908,
    ],
    [
        5938,
        5939,
    ],
    [
        5970,
        5971,
    ],
    [
        6002,
        6003,
    ],
    [
        6068,
        6069,
    ],
    [
        6071,
        6077,
    ],
    [
        6086,
        6086,
    ],
    [
        6089,
        6099,
    ],
    [
        6109,
        6109,
    ],
    [
        6155,
        6157,
    ],
    [
        6159,
        6159,
    ],
    [
        6277,
        6278,
    ],
    [
        6313,
        6313,
    ],
    [
        6432,
        6434,
    ],
    [
        6439,
        6440,
    ],
    [
        6450,
        6450,
    ],
    [
        6457,
        6459,
    ],
    [
        6679,
        6680,
    ],
    [
        6683,
        6683,
    ],
    [
        6742,
        6742,
    ],
    [
        6744,
        6750,
    ],
    [
        6752,
        6752,
    ],
    [
        6754,
        6754,
    ],
    [
        6757,
        6764,
    ],
    [
        6771,
        6780,
    ],
    [
        6783,
        6783,
    ],
    [
        6832,
        6845,
    ],
    [
        6846,
        6846,
    ],
    [
        6847,
        6862,
    ],
    [
        6912,
        6915,
    ],
    [
        6964,
        6964,
    ],
    [
        6966,
        6970,
    ],
    [
        6972,
        6972,
    ],
    [
        6978,
        6978,
    ],
    [
        7019,
        7027,
    ],
    [
        7040,
        7041,
    ],
    [
        7074,
        7077,
    ],
    [
        7080,
        7081,
    ],
    [
        7083,
        7085,
    ],
    [
        7142,
        7142,
    ],
    [
        7144,
        7145,
    ],
    [
        7149,
        7149,
    ],
    [
        7151,
        7153,
    ],
    [
        7212,
        7219,
    ],
    [
        7222,
        7223,
    ],
    [
        7376,
        7378,
    ],
    [
        7380,
        7392,
    ],
    [
        7394,
        7400,
    ],
    [
        7405,
        7405,
    ],
    [
        7412,
        7412,
    ],
    [
        7416,
        7417,
    ],
    [
        7616,
        7679,
    ],
    [
        8400,
        8412,
    ],
    [
        8413,
        8416,
    ],
    [
        8417,
        8417,
    ],
    [
        8418,
        8420,
    ],
    [
        8421,
        8432,
    ],
    [
        11503,
        11505,
    ],
    [
        11647,
        11647,
    ],
    [
        11744,
        11775,
    ],
    [
        12330,
        12333,
    ],
    [
        12441,
        12442,
    ],
    [
        42607,
        42607,
    ],
    [
        42608,
        42610,
    ],
    [
        42612,
        42621,
    ],
    [
        42654,
        42655,
    ],
    [
        42736,
        42737,
    ],
    [
        43010,
        43010,
    ],
    [
        43014,
        43014,
    ],
    [
        43019,
        43019,
    ],
    [
        43045,
        43046,
    ],
    [
        43052,
        43052,
    ],
    [
        43204,
        43205,
    ],
    [
        43232,
        43249,
    ],
    [
        43263,
        43263,
    ],
    [
        43302,
        43309,
    ],
    [
        43335,
        43345,
    ],
    [
        43392,
        43394,
    ],
    [
        43443,
        43443,
    ],
    [
        43446,
        43449,
    ],
    [
        43452,
        43453,
    ],
    [
        43493,
        43493,
    ],
    [
        43561,
        43566,
    ],
    [
        43569,
        43570,
    ],
    [
        43573,
        43574,
    ],
    [
        43587,
        43587,
    ],
    [
        43596,
        43596,
    ],
    [
        43644,
        43644,
    ],
    [
        43696,
        43696,
    ],
    [
        43698,
        43700,
    ],
    [
        43703,
        43704,
    ],
    [
        43710,
        43711,
    ],
    [
        43713,
        43713,
    ],
    [
        43756,
        43757,
    ],
    [
        43766,
        43766,
    ],
    [
        44005,
        44005,
    ],
    [
        44008,
        44008,
    ],
    [
        44013,
        44013,
    ],
    [
        64286,
        64286,
    ],
    [
        65024,
        65039,
    ],
    [
        65056,
        65071,
    ],
    [
        66045,
        66045,
    ],
    [
        66272,
        66272,
    ],
    [
        66422,
        66426,
    ],
    [
        68097,
        68099,
    ],
    [
        68101,
        68102,
    ],
    [
        68108,
        68111,
    ],
    [
        68152,
        68154,
    ],
    [
        68159,
        68159,
    ],
    [
        68325,
        68326,
    ],
    [
        68900,
        68903,
    ],
    [
        68969,
        68973,
    ],
    [
        69291,
        69292,
    ],
    [
        69372,
        69375,
    ],
    [
        69446,
        69456,
    ],
    [
        69506,
        69509,
    ],
    [
        69633,
        69633,
    ],
    [
        69688,
        69702,
    ],
    [
        69744,
        69744,
    ],
    [
        69747,
        69748,
    ],
    [
        69759,
        69761,
    ],
    [
        69811,
        69814,
    ],
    [
        69817,
        69818,
    ],
    [
        69826,
        69826,
    ],
    [
        69888,
        69890,
    ],
    [
        69927,
        69931,
    ],
    [
        69933,
        69940,
    ],
    [
        70003,
        70003,
    ],
    [
        70016,
        70017,
    ],
    [
        70070,
        70078,
    ],
    [
        70089,
        70092,
    ],
    [
        70095,
        70095,
    ],
    [
        70191,
        70193,
    ],
    [
        70196,
        70196,
    ],
    [
        70198,
        70199,
    ],
    [
        70206,
        70206,
    ],
    [
        70209,
        70209,
    ],
    [
        70367,
        70367,
    ],
    [
        70371,
        70378,
    ],
    [
        70400,
        70401,
    ],
    [
        70459,
        70460,
    ],
    [
        70464,
        70464,
    ],
    [
        70502,
        70508,
    ],
    [
        70512,
        70516,
    ],
    [
        70587,
        70592,
    ],
    [
        70606,
        70606,
    ],
    [
        70608,
        70608,
    ],
    [
        70610,
        70610,
    ],
    [
        70625,
        70626,
    ],
    [
        70712,
        70719,
    ],
    [
        70722,
        70724,
    ],
    [
        70726,
        70726,
    ],
    [
        70750,
        70750,
    ],
    [
        70835,
        70840,
    ],
    [
        70842,
        70842,
    ],
    [
        70847,
        70848,
    ],
    [
        70850,
        70851,
    ],
    [
        71090,
        71093,
    ],
    [
        71100,
        71101,
    ],
    [
        71103,
        71104,
    ],
    [
        71132,
        71133,
    ],
    [
        71219,
        71226,
    ],
    [
        71229,
        71229,
    ],
    [
        71231,
        71232,
    ],
    [
        71339,
        71339,
    ],
    [
        71341,
        71341,
    ],
    [
        71344,
        71349,
    ],
    [
        71351,
        71351,
    ],
    [
        71453,
        71453,
    ],
    [
        71455,
        71455,
    ],
    [
        71458,
        71461,
    ],
    [
        71463,
        71467,
    ],
    [
        71727,
        71735,
    ],
    [
        71737,
        71738,
    ],
    [
        71995,
        71996,
    ],
    [
        71998,
        71998,
    ],
    [
        72003,
        72003,
    ],
    [
        72148,
        72151,
    ],
    [
        72154,
        72155,
    ],
    [
        72160,
        72160,
    ],
    [
        72193,
        72202,
    ],
    [
        72243,
        72248,
    ],
    [
        72251,
        72254,
    ],
    [
        72263,
        72263,
    ],
    [
        72273,
        72278,
    ],
    [
        72281,
        72283,
    ],
    [
        72330,
        72342,
    ],
    [
        72344,
        72345,
    ],
    [
        72752,
        72758,
    ],
    [
        72760,
        72765,
    ],
    [
        72767,
        72767,
    ],
    [
        72850,
        72871,
    ],
    [
        72874,
        72880,
    ],
    [
        72882,
        72883,
    ],
    [
        72885,
        72886,
    ],
    [
        73009,
        73014,
    ],
    [
        73018,
        73018,
    ],
    [
        73020,
        73021,
    ],
    [
        73023,
        73029,
    ],
    [
        73031,
        73031,
    ],
    [
        73104,
        73105,
    ],
    [
        73109,
        73109,
    ],
    [
        73111,
        73111,
    ],
    [
        73459,
        73460,
    ],
    [
        73472,
        73473,
    ],
    [
        73526,
        73530,
    ],
    [
        73536,
        73536,
    ],
    [
        73538,
        73538,
    ],
    [
        73562,
        73562,
    ],
    [
        78912,
        78912,
    ],
    [
        78919,
        78933,
    ],
    [
        90398,
        90409,
    ],
    [
        90413,
        90415,
    ],
    [
        92912,
        92916,
    ],
    [
        92976,
        92982,
    ],
    [
        94031,
        94031,
    ],
    [
        94095,
        94098,
    ],
    [
        94180,
        94180,
    ],
    [
        113821,
        113822,
    ],
    [
        118528,
        118573,
    ],
    [
        118576,
        118598,
    ],
    [
        119143,
        119145,
    ],
    [
        119163,
        119170,
    ],
    [
        119173,
        119179,
    ],
    [
        119210,
        119213,
    ],
    [
        119362,
        119364,
    ],
    [
        121344,
        121398,
    ],
    [
        121403,
        121452,
    ],
    [
        121461,
        121461,
    ],
    [
        121476,
        121476,
    ],
    [
        121499,
        121503,
    ],
    [
        121505,
        121519,
    ],
    [
        122880,
        122886,
    ],
    [
        122888,
        122904,
    ],
    [
        122907,
        122913,
    ],
    [
        122915,
        122916,
    ],
    [
        122918,
        122922,
    ],
    [
        123023,
        123023,
    ],
    [
        123184,
        123190,
    ],
    [
        123566,
        123566,
    ],
    [
        123628,
        123631,
    ],
    [
        124140,
        124143,
    ],
    [
        124398,
        124399,
    ],
    [
        125136,
        125142,
    ],
    [
        125252,
        125258,
    ],
    [
        917760,
        917999,
    ],
];
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 ??= '';

        return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Slugger;

use Symfony\Component\Emoji\EmojiTransliterator;
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 <galopintitouan@gmail.com>
 */
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 \Closure|array $symbolsMap = [
        'en' => ['@' => 'at', '&' => 'and'],
    ];
    private bool|string $emoji = false;

    /**
     * Cache of transliterators per locale.
     *
     * @var \Transliterator[]
     */
    private array $transliterators = [];

    public function __construct(
        private ?string $defaultLocale = null,
        array|\Closure|null $symbolsMap = null,
    ) {
        $this->symbolsMap = $symbolsMap ?? $this->symbolsMap;
    }

    public function setLocale(string $locale): void
    {
        $this->defaultLocale = $locale;
    }

    public function getLocale(): string
    {
        return $this->defaultLocale;
    }

    /**
     * @param bool|string $emoji true will use the same locale,
     *                           false will disable emoji,
     *                           and a string to use a specific locale
     */
    public function withEmoji(bool|string $emoji = true): static
    {
        if (false !== $emoji && !class_exists(EmojiTransliterator::class)) {
            throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/emoji" package is not installed. Try running "composer require symfony/emoji".', __METHOD__));
        }

        $new = clone $this;
        $new->emoji = $emoji;

        return $new;
    }

    public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString
    {
        $locale ??= $this->defaultLocale;

        $transliterator = [];
        if ($locale && ('de' === $locale || str_starts_with($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 ($emojiTransliterator = $this->createEmojiTransliterator($locale)) {
            $transliterator[] = $emojiTransliterator;
        }

        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 fn ($s) => $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 function createEmojiTransliterator(?string $locale): ?EmojiTransliterator
    {
        if (\is_string($this->emoji)) {
            $locale = $this->emoji;
        } elseif (!$this->emoji) {
            return null;
        }

        while (null !== $locale) {
            try {
                return EmojiTransliterator::create("emoji-$locale");
            } catch (\IntlException) {
                $locale = self::getParentLocale($locale);
            }
        }

        return 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));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String\Slugger;

use Symfony\Component\String\AbstractUnicodeString;

/**
 * Creates a URL-friendly slug from a given string.
 *
 * @author Titouan Galopin <galopintitouan@gmail.com>
 */
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;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\String;

enum TruncateMode
{
    /**
     * Will cut exactly at given length.
     *
     * Length: 14
     * Source: Lorem ipsum dolor sit amet
     * Output: Lorem ipsum do
     */
    case Char;

    /**
     * Returns the string up to the last complete word containing the specified length.
     *
     * Length: 14
     * Source: Lorem ipsum dolor sit amet
     * Output: Lorem ipsum
     */
    case WordBefore;

    /**
     * Returns the string up to the complete word after or at the given length.
     *
     * Length: 14
     * Source: Lorem ipsum dolor sit amet
     * Output: Lorem ipsum dolor
     */
    case WordAfter;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\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 <p@tchwork.com>
 * @author Hugo Hamon <hugohamon@neuf.fr>
 *
 * @throws ExceptionInterface
 */
class UnicodeString extends AbstractUnicodeString
{
    public function __construct(string $string = '')
    {
        if ('' === $string || normalizer_is_normalized($this->string = $string)) {
            return;
        }

        if (false === $string = normalizer_normalize($string)) {
            throw new InvalidArgumentException('Invalid UTF-8 string.');
        }

        $this->string = $string;
    }

    public function append(string ...$suffix): static
    {
        $str = clone $this;
        $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix));

        if (normalizer_is_normalized($str->string)) {
            return $str;
        }

        if (false === $string = normalizer_normalize($str->string)) {
            throw new InvalidArgumentException('Invalid UTF-8 string.');
        }

        $str->string = $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(string|iterable|AbstractString $suffix): bool
    {
        if ($suffix instanceof AbstractString) {
            $suffix = $suffix->string;
        } elseif (!\is_string($suffix)) {
            return parent::endsWith($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|iterable|AbstractString $string): bool
    {
        if ($string instanceof AbstractString) {
            $string = $string->string;
        } elseif (!\is_string($string)) {
            return parent::equalsTo($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(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOf($needle, $offset);
        }

        $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) {
            return null;
        }

        return false === $i ? null : $i;
    }

    public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int
    {
        if ($needle instanceof AbstractString) {
            $needle = $needle->string;
        } elseif (!\is_string($needle)) {
            return parent::indexOfLast($needle, $offset);
        }

        $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): static
    {
        $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);
    }

    public function normalize(int $form = self::NFC): static
    {
        $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): static
    {
        $str = clone $this;
        $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;

        if (normalizer_is_normalized($str->string)) {
            return $str;
        }

        if (false === $string = normalizer_normalize($str->string)) {
            throw new InvalidArgumentException('Invalid UTF-8 string.');
        }

        $str->string = $string;

        return $str;
    }

    public function replace(string $from, string $to): static
    {
        $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;

            if (normalizer_is_normalized($str->string)) {
                return $str;
            }

            if (false === $string = normalizer_normalize($str->string)) {
                throw new InvalidArgumentException('Invalid UTF-8 string.');
            }

            $str->string = $string;
        }

        return $str;
    }

    public function replaceMatches(string $fromRegexp, string|callable $to): static
    {
        $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): static
    {
        $str = clone $this;

        $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647);

        return $str;
    }

    public function splice(string $replacement, int $start = 0, ?int $length = null): static
    {
        $str = clone $this;

        $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0;
        $length = $length ? \strlen(grapheme_substr($this->string, $start, $length)) : $length;
        $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647);

        if (normalizer_is_normalized($str->string)) {
            return $str;
        }

        if (false === $string = normalizer_normalize($str->string)) {
            throw new InvalidArgumentException('Invalid UTF-8 string.');
        }

        $str->string = $string;

        return $str;
    }

    public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
    {
        if (1 > $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(string|iterable|AbstractString $prefix): bool
    {
        if ($prefix instanceof AbstractString) {
            $prefix = $prefix->string;
        } elseif (!\is_string($prefix)) {
            return parent::startsWith($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(): void
    {
        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;
    }
}
<?php

/** @noinspection ReturnTypeCanBeDeclaredInspection */

declare(strict_types=1);

namespace voku\helper;

use const ENT_DISALLOWED;
use const ENT_HTML5;
use const ENT_QUOTES;
use const ENT_SUBSTITUTE;
use const HTML_ENTITIES;

/**
 * AntiXSS - ported from "CodeIgniter"
 *
 * ## 🇷🇺 Русским гражданам
 * В Украине сейчас идет война. Силами РФ наносятся удары по гражданской инфраструктуре в [Харькове][1], [Киеве][2], [Чернигове][3], [Сумах][4], [Ирпене][5] и десятках других городов. Гибнут люди - и гражданское население, и военные, в том числе российские призывники, которых бросили воевать. Чтобы лишить собственный народ доступа к информации, правительство РФ запретило называть войну войной, закрыло независимые СМИ и принимает сейчас ряд диктаторских законов. Эти законы призваны заткнуть рот всем, кто против войны. За обычный призыв к миру сейчас можно получить несколько лет тюрьмы.
 * Не молчите! Молчание - знак вашего согласия с политикой российского правительства.
 *  **Вы можете сделать выбор НЕ МОЛЧАТЬ.**
 * ---
 * ## 🇺🇸 To people of Russia
 * There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilian infrastructure in [Kharkiv][1], [Kyiv][2], [Chernihiv][3], [Sumy][4], [Irpin][5] and dozens of other cities. People are dying – both civilians and military servicemen, including Russian conscripts who were thrown into the fighting. In order to deprive its own people of access to information, the government of the Russian Federation has forbidden calling a war a war, shut down independent media and is passing a number of dictatorial laws. These laws are meant to silence all those who are against war. You can be jailed for multiple years for simply calling for peace.
 * Do not be silent! Silence is a sign that you accept the Russian government's policy.
 * **You can choose NOT TO BE SILENT.**
 * ---
 * - [1] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/P7K2MSZDGFMIJPDD7CI2GIROJI.jpg "Kharkiv under attack"
 * - [2] https://gdb.voanews.com/01bd0000-0aff-0242-fad0-08d9fc92c5b3_cx0_cy5_cw0_w1023_r1_s.jpg "Kyiv under attack"
 * - [3] https://ichef.bbci.co.uk/news/976/cpsprodpb/163DD/production/_123510119_hi074310744.jpg "Chernihiv under attack"
 * - [4] https://www.youtube.com/watch?v=8K-bkqKKf2A "Sumy under attack"
 * - [5] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/K4MTMLEHTRKGFK3GSKAT4GR3NE.jpg "Irpin under attack"
 *
 * @copyright   Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
 * @copyright   Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
 * @copyright   Copyright (c) 2015 - 2020, Lars Moelleken (https://moelleken.org/)
 * @license     http://opensource.org/licenses/MIT	MIT License
 */
final class AntiXSS
{
    const VOKU_ANTI_XSS_GT = 'voku::anti-xss::gt';

    const VOKU_ANTI_XSS_LT = 'voku::anti-xss::lt';

    const VOKU_ANTI_XSS_STYLE = 'voku::anti-xss::STYLE';

    /**
     * List of never allowed regex replacements.
     *
     * @var string[]
     */
    private $_never_allowed_regex = [];

    /**
     * List of html tags that will not close automatically.
     *
     * @var string[]
     */
    private $_do_not_close_html_tags = [];

    /**
     * List of never allowed call statements.
     *
     * @var string[]
     */
    private $_never_allowed_js_callback_regex = [
        '\(?window\)?\.',
        '\(?history\)?\.',
        '\(?location\)?\.',
        '\(?document\)?\.',
        '\(?cookie\)?\.',
        '\(?ScriptElement\)?\.',
        'd\s*a\s*t\s*a\s*:',
    ];
    
    /**
     * List of simple never allowed call statements.
     *
     * @var string[]
     */
    private $_never_allowed_call_strings = [
        // default javascript
        'javascript',
        // Java: jar-protocol is an XSS hazard
        'jar',
        // Mac (will not run the script, but open it in AppleScript Editor)
        'applescript',
        // IE: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#VBscript_in_an_image
        'vbscript',
        'vbs',
        // IE, surprise!
        'wscript',
        // IE
        'jscript',
        // https://html5sec.org/#behavior
        'behavior',
        // old Netscape
        'mocha',
        // old Netscape
        'livescript',
        // default view source
        'view-source',
    ];

    /**
     * @var string[]
     */
    private $_never_allowed_str_afterwards = [
        '&lt;script&gt;',
        '&lt;/script&gt;',
    ];

    /**
     * List of never allowed strings, afterwards.
     *
     * @var string[]
     */
    private $_never_allowed_on_events_afterwards = [
        'onAbort',
        'onActivate',
        'onAttribute',
        'onAfterPrint',
        'onAfterScriptExecute',
        'onAfterUpdate',
        'onAnimationCancel',
        'onAnimationEnd',
        'onAnimationIteration',
        'onAnimationStart',
        'onAriaRequest',
        'onAutoComplete',
        'onAutoCompleteError',
        'onAuxClick',
        'onBeforeActivate',
        'onBeforeCopy',
        'onBeforeCut',
        'onBeforeInput',
        'onBeforePrint',
        'onBeforeDeactivate',
        'onBeforeEditFocus',
        'onBeforePaste',
        'onBeforePrint',
        'onBeforeScriptExecute',
        'onBeforeToggle',
        'onBeforeUnload',
        'onBeforeUpdate',
        'onBegin',
        'onBlur',
        'onBounce',
        'onCancel',
        'onCanPlay',
        'onCanPlayThrough',
        'onCellChange',
        'onChange',
        'onClick',
        'onClose',
        'onCommand',
        'onCompassNeedsCalibration',
        'onContextMenu',
        'onControlSelect',
        'onCopy',
        'onCueChange',
        'onCut',
        'onDataAvailable',
        'onDataSetChanged',
        'onDataSetComplete',
        'onDblClick',
        'onDeactivate',
        'onDeviceLight',
        'onDeviceMotion',
        'onDeviceOrientation',
        'onDeviceProximity',
        'onDrag',
        'onDragDrop',
        'onDragEnd',
        'onDragExit',
        'onDragEnter',
        'onDragLeave',
        'onDragOver',
        'onDragStart',
        'onDrop',
        'onDurationChange',
        'onEmptied',
        'onEnd',
        'onEnded',
        'onError',
        'onErrorUpdate',
        'onExit',
        'onFilterChange',
        'onFinish',
        'onFocus',
        'onFocusIn',
        'onFocusOut',
        'onFormChange',
        'onFormInput',
        'onFullScreenChange',
        'onFullScreenError',
        'onGotPointerCapture',
        'onHashChange',
        'onHelp',
        'onInput',
        'onInvalid',
        'onKeyDown',
        'onKeyPress',
        'onKeyUp',
        'onLanguageChange',
        'onLayoutComplete',
        'onLoad',
        'onLoadEnd',
        'onLoadedData',
        'onLoadedMetaData',
        'onLoadStart',
        'onLoseCapture',
        'onLostPointerCapture',
        'onMediaComplete',
        'onMediaError',
        'onMessage',
        'onMouseDown',
        'onMouseEnter',
        'onMouseLeave',
        'onMouseMove',
        'onMouseOut',
        'onMouseOver',
        'onMouseUp',
        'onMouseWheel',
        'onMove',
        'onMoveEnd',
        'onMoveStart',
        'onMozFullScreenChange',
        'onMozFullScreenError',
        'onMozPointerLockChange',
        'onMozPointerLockError',
        'onMsContentZoom',
        'onMsFullScreenChange',
        'onMsFullScreenError',
        'onMsGestureChange',
        'onMsGestureDoubleTap',
        'onMsGestureEnd',
        'onMsGestureHold',
        'onMsGestureStart',
        'onMsGestureTap',
        'onMsGotPointerCapture',
        'onMsInertiaStart',
        'onMsLostPointerCapture',
        'onMsManipulationStateChanged',
        'onMsPointerCancel',
        'onMsPointerDown',
        'onMsPointerEnter',
        'onMsPointerLeave',
        'onMsPointerMove',
        'onMsPointerOut',
        'onMsPointerOver',
        'onMsPointerUp',
        'onMsSiteModeJumpListItemRemoved',
        'onMsThumbnailClick',
        'onOffline',
        'onOnline',
        'onOutOfSync',
        'onPage',
        'onPageHide',
        'onPageShow',
        'onPaste',
        'onPause',
        'onPlay',
        'onPlaying',
        'onPointerCancel',
        'onPointerDown',
        'onPointerEnter',
        'onPointerLeave',
        'onPointerLockChange',
        'onPointerLockError',
        'onPointerMove',
        'onPointerOut',
        'onPointerOver',
        'onPointerRawUpdate',
        'onPointerUp',
        'onPopState',
        'onProgress',
        'onPropertyChange',
        'onqt_error',
        'onRateChange',
        'onReadyStateChange',
        'onReceived',
        'onRepeat',
        'onReset',
        'onResize',
        'onResizeEnd',
        'onResizeStart',
        'onResume',
        'onReverse',
        'onRowDelete',
        'onRowEnter',
        'onRowExit',
        'onRowInserted',
        'onRowsDelete',
        'onRowsEnter',
        'onRowsExit',
        'onRowsInserted',
        'onScroll',
        'onSearch',
        'onSeek',
        'onSeeked',
        'onSeeking',
        'onSelect',
        'onSelectionChange',
        'onSelectStart',
        'onStalled',
        'onStorage',
        'onStorageCommit',
        'onStart',
        'onStop',
        'onShow',
        'onSyncRestored',
        'onSubmit',
        'onSuspend',
        'onSynchRestored',
        'onTimeError',
        'onTimeUpdate',
        'onTimer',
        'onTrackChange',
        'onTransitionEnd',
        'onTransitionRun',
        'onTransitionStart',
        'onToggle',
        'onTouchCancel',
        'onTouchEnd',
        'onTouchLeave',
        'onTouchMove',
        'onTouchStart',
        'onTransitionCancel',
        'onTransitionEnd',
        'onUnload',
        'onUnhandledRejection',
        'onURLFlip',
        'onUserProximity',
        'onVolumeChange',
        'onWaiting',
        'onWebKitAnimationEnd',
        'onWebKitAnimationIteration',
        'onWebKitAnimationStart',
        'onWebKitFullScreenChange',
        'onWebKitFullScreenError',
        'onWebKitTransitionEnd',
        'onWheel',
    ];

    /**
     * https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Event_Handlers
     *
     * @var string[]
     */
    private $_evil_attributes_regex = [
        'style',
        'xmlns:xdp',
        'formaction',
        'form',
        'xlink:href',
        'seekSegmentTime',
        'FSCommand',
    ];

    /**
     * @var string[]
     */
    private $_evil_html_tags = [
        'applet',
        'audio',
        'basefont',
        'base',
        'behavior',
        'bgsound',
        'blink',
        'body',
        'embed',
        'eval',
        'expression',
        'form',
        'frameset',
        'frame',
        'head',
        'html',
        'ilayer',
        'iframe',
        'input',
        'button',
        'select',
        'isindex',
        'layer',
        'link',
        'meta',
        'keygen',
        'object',
        'plaintext',
        'style',
        'script',
        'textarea',
        'title',
        'math',
        'noscript',
        'event-source',
        'vmlframe',
        'video',
        'source',
        'svg',
        'xml',
    ];

    /**
     * @var string
     */
    private $_spacing_regex = '(?:\s|"|\'|\+|&#x0[9A-F];|%0[9a-f])*?';

    /**
     * The replacement-string for not allowed strings.
     *
     * @var string
     */
    private $_replacement = '';

    /**
     * List of never allowed strings.
     *
     * @var string[]
     */
    private $_never_allowed_str = [];

    /**
     * If your DB (MySQL) encoding is "utf8" and not "utf8mb4", then
     * you can't save 4-Bytes chars from UTF-8 and someone can create stored XSS-attacks.
     *
     * @var bool
     */
    private $_stripe_4byte_chars = false;

    /**
     * @var bool|null
     */
    private $_xss_found;

    /**
     * @var string
     */
    private $_cache_evil_attributes_regex_string = '';

    /**
     * @var string
     */
    private $_cache_never_allowed_regex_string = '';

    /**
     * @var string
     */
    private $_cache__evil_html_tags_str = '';

    /**
     * __construct()
     */
    public function __construct()
    {
        $this->_initNeverAllowedStr();
        $this->_initNeverAllowedRegex();
    }

    /**
     * Compact any exploded words.
     *
     * <p>
     * <br />
     * INFO: This corrects words like:  j a v a s c r i p t
     * <br />
     * These words are compacted back to their correct state.
     * </p>
     *
     * @param string $str
     *
     * @return string
     */
    private function _compact_exploded_javascript($str)
    {
        static $WORDS_CACHE;
        $WORDS_CACHE['chunk'] = [];
        $WORDS_CACHE['split'] = [];

        $words = [
            'javascript',
            '<script',
            '</script>',
            'base64',
            'document',
            'eval',
        ];

        // check if we need to perform the regex-stuff
        if (\strlen($str) <= 30) {
            $useStrPos = true;
        } else {
            $useStrPos = false;
        }

        foreach ($words as $word) {
            if (!isset($WORDS_CACHE['chunk'][$word])) {
                $WORDS_CACHE['chunk'][$word] = \substr(
                    \chunk_split($word, 1, $this->_spacing_regex),
                    0,
                    -\strlen($this->_spacing_regex)
                );

                $WORDS_CACHE['split'][$word] = \str_split($word);
            }

            if ($useStrPos) {
                foreach ($WORDS_CACHE['split'][$word] as $charTmp) {
                    if (\stripos($str, $charTmp) === false) {
                        continue 2;
                    }
                }
            }

            // We only want to do this when it is followed by a non-word character.
            // And if there are no char at the start of the string.
            //
            // That way valid stuff like "dealer to!" does not become "dealerto".

            $str = (string) \preg_replace_callback(
                '#(?<before>[^\p{L}]|^)(?<word>' . \str_replace(
                    ['#', '.'],
                    ['\#', '\.'],
                    $WORDS_CACHE['chunk'][$word]
                ) . ')(?<after>[^\p{L}@.!?\' ]|$)#ius',
                function ($matches) {
                    return $this->_compact_exploded_words_callback($matches);
                },
                $str
            );
        }

        return $str;
    }

    /**
     * Compact exploded words.
     *
     * <p>
     * <br />
     * INFO: Callback method for xss_clean() to remove whitespace from things like 'j a v a s c r i p t'.
     * </p>
     *
     * @param string[] $matches
     *
     * @return  string
     */
    private function _compact_exploded_words_callback($matches)
    {
        return $matches['before'] . \preg_replace(
            '/' . $this->_spacing_regex . '/ius',
            '',
            $matches['word']
        ) . $matches['after'];
    }

    /**
     * HTML-Entity decode callback.
     *
     * @param string[] $match
     *
     * @return string
     */
    private function _decode_entity($match)
    {
        // init
        $str = $match[0];

        // protect GET variables without XSS in URLs
        $needProtection = true;
        if (\strpos($str, '=') !== false) {
            $strCopy = $str;
            $matchesTmp = [];
            while (\preg_match("/[?|&]?[\p{L}\d_\-\[\]]+\s*=\s*([\"'])(?<attr>[^\1]*?)\\1/u", $strCopy, $matches)) {
                $matchesTmp[] = $matches;
                $strCopy = \str_replace($matches[0], '', $strCopy);

                if (\substr_count($strCopy, '"') <= 1 && \substr_count($strCopy, '\'') <= 1) {
                    break;
                }
            }

            if ($strCopy !== $str) {
                $needProtection = false;
                foreach ($matchesTmp as $matches) {
                    if (isset($matches['attr'])) {
                        $tmpAntiXss = clone $this;

                        $urlPartClean = $tmpAntiXss->xss_clean((string) $matches['attr']);

                        if ($tmpAntiXss->isXssFound() === true) {
                            $this->_xss_found = true;

                            $urlPartClean = \str_replace(['&lt;', '&gt;'], [self::VOKU_ANTI_XSS_LT, self::VOKU_ANTI_XSS_GT], $urlPartClean);
                            $urlPartClean = UTF8::rawurldecode($urlPartClean);
                            $urlPartClean = \str_replace([self::VOKU_ANTI_XSS_LT, self::VOKU_ANTI_XSS_GT], ['&lt;', '&gt;'], $urlPartClean);

                            $str = \str_ireplace($matches['attr'], $urlPartClean, $str);
                        }
                    }
                }
            }
        }

        if ($needProtection) {
            $str = \str_replace(['&lt;', '&gt;'], [self::VOKU_ANTI_XSS_LT, self::VOKU_ANTI_XSS_GT], $str);
            $str = $this->_entity_decode(UTF8::rawurldecode($str));
            $str = \str_replace([self::VOKU_ANTI_XSS_LT, self::VOKU_ANTI_XSS_GT], ['&lt;', '&gt;'], $str);
        }

        return $str;
    }

    /**
     * Decode the html-tags but keep links without XSS.
     *
     * @param string $str
     *
     * @return string
     */
    private function _decode_string($str)
    {
        // init
        $regExForHtmlTags = '/<\p{L}+(?:[^>"\']|(["\']).*\1)*>/usU';

        if (
            \strpos($str, '<') !== false
            &&
            \preg_match($regExForHtmlTags, $str, $matches)
        ) {
            $str = (string) \preg_replace_callback(
                $regExForHtmlTags,
                function ($matches) {
                    return $this->_decode_entity($matches);
                },
                $str
            );
        } else {
            $str = UTF8::rawurldecode($str);
        }

        return $str;
    }

    /**
     * @param string $str
     *
     * @return string
     */
    private function _do($str)
    {
        $str = (string) $str;
        $strInt = (int) $str;
        $strFloat = (float) $str;
        if (
            !$str
            ||
            (string) $strInt === $str
            ||
            (string) $strFloat === $str
        ) {
            // no xss found
            if ($this->_xss_found !== true) {
                $this->_xss_found = false;
            }

            return $str;
        }

        // remove the BOM from UTF-8 / UTF-16 / UTF-32 strings
        $str = UTF8::remove_bom($str);

        // replace the diamond question mark (�) and invalid-UTF8 chars
        $str = UTF8::replace_diamond_question_mark($str, '');

        // replace invisible characters with one single space
        $str = UTF8::remove_invisible_characters($str, true, '', false);

        // decode UTF-7 characters
        $str = $this->_repack_utf7($str);

        // decode the string
        $str = $this->_decode_string($str);

        // remove all >= 4-Byte chars if needed
        if ($this->_stripe_4byte_chars) {
            $str = (string) \preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $str);
        }

        // backup the string (for later comparison)
        $str_backup = $str;
        
        // process
        do {
            // backup the string (for the loop)
            $str_backup_loop = $str;

            // correct words before the browser will do it
            $str = $this->_compact_exploded_javascript($str);
    
            // remove disallowed javascript calls in links, images etc.
            $str = $this->_remove_disallowed_javascript($str);
    
            // remove strings that are never allowed
            $str = $this->_do_never_allowed($str);
    
            // remove evil attributes such as style, onclick and xmlns
            $str = $this->_remove_evil_attributes($str);
    
            // sanitize naughty JavaScript elements
            $str = $this->_sanitize_naughty_javascript($str);
    
            // sanitize naughty HTML elements
            $str = $this->_sanitize_naughty_html($str);
    
            // final clean up
            //
            // -> This adds a bit of extra precaution in case something got through the above filters.
            $str = $this->_do_never_allowed_afterwards($str);
        } while ($str_backup_loop !== $str);

        // check for xss
        if ($this->_xss_found !== true) {
            $this->_xss_found = !($str_backup === $str);
        }
        
        return $str;
    }

    /**
     * Remove never allowed strings.
     *
     * @param string $str
     *
     * @return string
     */
    private function _do_never_allowed($str)
    {
        static $NEVER_ALLOWED_CACHE = [];

        $NEVER_ALLOWED_CACHE['keys'] = null;

        if ($NEVER_ALLOWED_CACHE['keys'] === null) {
            $NEVER_ALLOWED_CACHE['keys'] = \array_keys($this->_never_allowed_str);
        }

        $str = \str_ireplace(
            $NEVER_ALLOWED_CACHE['keys'],
            $this->_never_allowed_str,
            $str
        );

        // ---

        $replaceNeverAllowedCall = [];
        foreach ($this->_never_allowed_call_strings as $call) {
            if (\stripos($str, $call) !== false) {
                $replaceNeverAllowedCall[] = $call;
            }
        }
        if (\count($replaceNeverAllowedCall) > 0) {
            $str = (string) \preg_replace(
                '#([^\p{L}]|^)(?:' . \implode('|', $replaceNeverAllowedCall) . ')\s*:(?:.*?([/\\\;()\'">]|$))#ius',
                '$1' . $this->_replacement . '$2',
                $str
            );
        }

        // ---

        $regex_combined = [];
        foreach ($this->_never_allowed_regex as $regex => $replacement) {
            if ($replacement === $this->_replacement) {
                $regex_combined[] = $regex;

                continue;
            }

            $str = (string) \preg_replace(
                '#' . $regex . '#iUus',
                $replacement,
                $str
            );
        }

        if (!$this->_cache_never_allowed_regex_string || $regex_combined !== []) {
            $this->_cache_never_allowed_regex_string = \implode('|', $regex_combined);
        }

        if ($this->_cache_never_allowed_regex_string) {
            $str = (string) \preg_replace(
                '#' . $this->_cache_never_allowed_regex_string . '#ius',
                $this->_replacement,
                $str
            );
        }

        return $str;
    }

    /**
     * @return array
     *
     * @phpstan-return array<string, list<string>>
     */
    private function _get_never_allowed_on_events_afterwards_chunks()
    {
        // init
        $array = [];

        foreach ($this->_never_allowed_on_events_afterwards as $event) {
            $array[$event[0] . $event[1] . $event[2]][] = $event;
        }

        return $array;
    }

    /**
     * Remove never allowed string, afterwards.
     *
     * <p>
     * <br />
     * INFO: clean-up also some string, if there is no html-tag
     * </p>
     *
     * @param string $str
     *
     * @return  string
     */
    private function _do_never_allowed_afterwards($str)
    {
        if (\stripos($str, 'on') !== false) {
            foreach ($this->_get_never_allowed_on_events_afterwards_chunks() as $eventNameBeginning => $events) {
                if (\stripos($str, $eventNameBeginning) === false) {
                    continue;
                }

                foreach ($events as $event) {
                    if (\stripos($str, $event) === false) {
                        continue;
                    }

                    $regex = '(?<before>[^\p{L}@.!?>]|^)(?:' . \implode('|', $events) . ')(?<after>\(.*?\)|.*?>|(?:\s|\[.*?\])*?=(?:\s|\[.*?\])*?|(?:\s|\[.*?\])*?&equals;(?:\s|\[.*?\])*?|[^\p{L}]*?=[^\p{L}]*?|[^\p{L}]*?&equals;[^\p{L}]*?|$|\s*?>*?$)';

                    do {
                        $count = $temp_count = 0;

                        $str = (string) \preg_replace(
                            '#' . $regex . '#ius',
                            '$1' . $this->_replacement . '$2',
                            $str,
                            -1,
                            $temp_count
                        );
                        $count += $temp_count;
                    } while ($count);

                    break;
                }
            }
        }

        return (string) \str_ireplace(
            $this->_never_allowed_str_afterwards,
            $this->_replacement,
            $str
        );
    }

    /**
     * Entity-decoding.
     *
     * @param string $str
     *
     * @return string
     */
    private function _entity_decode($str)
    {
        static $HTML_ENTITIES_CACHE;

        $flags = ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED | ENT_SUBSTITUTE;

        // decode-again, for e.g. HHVM or miss configured applications ...
        if (
            \strpos($str, '&') !== false
            &&
            \preg_match_all('/(?<html_entity>&[A-Za-z]{2,};{0})/', $str, $matches)
        ) {
            if ($HTML_ENTITIES_CACHE === null) {
                // links:
                // - http://dev.w3.org/html5/html-author/charref
                // - http://www.w3schools.com/charsets/ref_html_entities_n.asp
                $entitiesSecurity = [
                    '&#x00000;'          => '',
                    '&#0;'               => '',
                    '&#x00001;'          => '',
                    '&#1;'               => '',
                    '&nvgt;'             => '',
                    '&#61253;'           => '',
                    '&#x0EF45;'          => '',
                    '&shy;'              => '',
                    '&#x000AD;'          => '',
                    '&#173;'             => '',
                    '&colon;'            => ':',
                    '&#x0003A;'          => ':',
                    '&#58;'              => ':',
                    '&lpar;'             => '(',
                    '&#x00028;'          => '(',
                    '&#40;'              => '(',
                    '&rpar;'             => ')',
                    '&#x00029;'          => ')',
                    '&#41;'              => ')',
                    '&quest;'            => '?',
                    '&#x0003F;'          => '?',
                    '&#63;'              => '?',
                    '&sol;'              => '/',
                    '&#x0002F;'          => '/',
                    '&#47;'              => '/',
                    '&apos;'             => '\'',
                    '&#x00027;'          => '\'',
                    '&#039;'             => '\'',
                    '&#39;'              => '\'',
                    '&#x27;'             => '\'',
                    '&bsol;'             => '\'',
                    '&#x0005C;'          => '\\',
                    '&#92;'              => '\\',
                    '&comma;'            => ',',
                    '&#x0002C;'          => ',',
                    '&#44;'              => ',',
                    '&period;'           => '.',
                    '&#x0002E;'          => '.',
                    '&quot;'             => '"',
                    '&QUOT;'             => '"',
                    '&#x00022;'          => '"',
                    '&#34;'              => '"',
                    '&grave;'            => '`',
                    '&DiacriticalGrave;' => '`',
                    '&#x00060;'          => '`',
                    '&#96;'              => '`',
                    '&#46;'              => '.',
                    '&equals;'           => '=',
                    '&#x0003D;'          => '=',
                    '&#61;'              => '=',
                    '&newline;'          => "\n",
                    '&#x0000A;'          => "\n",
                    '&#10;'              => "\n",
                    '&tab;'              => "\t",
                    '&#x00009;'          => "\t",
                    '&#9;'               => "\t",
                ];

                $HTML_ENTITIES_CACHE = \array_merge(
                    $entitiesSecurity,
                    \array_flip(\get_html_translation_table(HTML_ENTITIES, $flags)),
                    \array_flip(self::_get_data('entities_fallback'))
                );
            }

            $search = [];
            $replace = [];
            foreach ($matches['html_entity'] as $match) {
                $match .= ';';
                if (isset($HTML_ENTITIES_CACHE[$match])) {
                    $search[$match] = $match;
                    $replace[$match] = $HTML_ENTITIES_CACHE[$match];
                }
            }

            if (\count($replace) > 0) {
                $str = \str_ireplace($search, $replace, $str);
            }
        }

        return $str;
    }

    /**
     * Filters tag attributes for consistency and safety.
     *
     * @param string $str
     *
     * @return string
     */
    private function _filter_attributes($str)
    {
        if ($str === '') {
            return '';
        }

        if (\strpos($str, '=') !== false) {
            $matchesTmp = [];
            while (\preg_match('#\s*[\p{L}\d_\-\[\]]+\s*=\s*(["\'])(?:[^\1]*?)\\1#u', $str, $matches)) {
                $matchesTmp[] = $matches[0];
                $str = \str_replace($matches[0], '', $str);

                if (\substr_count($str, '"') <= 1 && \substr_count($str, '\'') <= 1) {
                    break;
                }
            }
            $out = \implode('', $matchesTmp);
        } else {
            $out = $str;
        }

        return $out;
    }

    /**
     * get data from "/data/*.php"
     *
     * @param string $file
     *
     * @return string[]
     *
     * @phpstan-return array<string, string>
     */
    private static function _get_data($file)
    {
        /** @noinspection PhpIncludeInspection */
        return include __DIR__ . '/data/' . $file . '.php';
    }

    /**
     * initialize "$this->_never_allowed_str"
     *
     * @return void
     */
    private function _initNeverAllowedStr()
    {
        $this->_never_allowed_str = [
            'document.cookie'   => $this->_replacement,
            '(document).cookie' => $this->_replacement,
            'document.write'    => $this->_replacement,
            '(document).write'  => $this->_replacement,
            '.parentNode'       => $this->_replacement,
            '.innerHTML'        => $this->_replacement,
            '.appendChild'      => $this->_replacement,
            '-moz-binding'      => $this->_replacement,
            '<?'                => '&lt;?',
            '?>'                => '?&gt;',
            '<![CDATA['         => '&lt;![CDATA[',
            '<!ENTITY'          => '&lt;!ENTITY',
            '<!DOCTYPE'         => '&lt;!DOCTYPE',
            '<!ATTLIST'         => '&lt;!ATTLIST',
        ];
    }

    /**
     * initialize "$this->_never_allowed_regex"
     *
     * @return void
     */
    private function _initNeverAllowedRegex()
    {
        $this->_never_allowed_regex = [
            // default javascript
            '(\(?:?document\)?|\(?:?window\)?(?:\.document)?)\.(?:location|on\w*)' => $this->_replacement,
            // data-attribute + base64
            "([\"'])?data\s*:\s*(?!image\s*\/\s*(?!svg.*?))[^\1]*?base64[^\1]*?,[^\1]*?\1?" => $this->_replacement,
            // old IE, old Netscape
            'expression\s*(?:\(|&\#40;)' => $this->_replacement,
            // src="js"
            'src\=(?<wrapper>[\'|"]).*\.js(?:\g{wrapper})' => $this->_replacement,
            // comments
            '<!--(.*)-->' => '&lt;!--$1--&gt;',
            '<!--'        => '&lt;!--',
        ];
    }

    /**
     * Callback method for xss_clean() to sanitize links.
     *
     * <p>
     * <br />
     * INFO: This limits the PCRE backtracks, making it more performance friendly
     * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
     * PHP 5.2+ on link-heavy strings.
     * </p>
     *
     * @param string[] $match
     *
     * @return string
     */
    private function _js_link_removal_callback($match)
    {
        return $this->_js_removal_callback($match, 'href');
    }

    /**
     * Callback method for xss_clean() to sanitize tags.
     *
     * <p>
     * <br />
     * INFO: This limits the PCRE backtracks, making it more performance friendly
     * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
     * PHP 5.2+ on image tag heavy strings.
     * </p>
     *
     * @param string[]  $match
     * @param string $search
     *
     * @return string
     */
    private function _js_removal_callback($match, $search)
    {
        if (!$match[0]) {
            return '';
        }

        $replacer = $this->_filter_attributes($match[1]);

        // filter for "$search"-attributes
        if (\stripos($match[1], $search . '=') !== false) {
            $pattern = '#' . $search . '=(?<wrapper>[\'|"])(?<link>.*)(?:\g{wrapper})#isU';
            $matchInner = [];
            $foundSomethingBad = false;
            if (\preg_match($pattern, $match[1], $matchInner)) {
                $needProtection = true;
                $matchInner['link'] = \str_replace(' ', '%20', $matchInner['link']);

                if (
                    \strpos($matchInner[0], 'script') === false
                    &&
                    \strpos(\str_replace(['http://', 'https://'], '', $matchInner[0]), ':') === false
                    &&
                    (
                        \filter_var($matchInner['link'], \FILTER_VALIDATE_URL) !== false
                        ||
                        \filter_var('https://localhost.localdomain/' . $matchInner['link'], \FILTER_VALIDATE_URL) !== false
                    )
                ) {
                    $needProtection = false;
                }

                if ($needProtection) {
                    $tmpAntiXss = clone $this;

                    $tmpAntiXss->xss_clean((string) $matchInner[0]);

                    if ($tmpAntiXss->isXssFound() === true) {
                        $foundSomethingBad = true;
                        $this->_xss_found = true;

                        $replacer = (string) \preg_replace(
                            $pattern,
                            $search . '="' . $this->_replacement . '"',
                            $replacer
                        );
                    }
                }
            }

            if (!$foundSomethingBad) {
                // filter for javascript
                $patternTmp = '';
                foreach ($this->_never_allowed_call_strings as $callTmp) {
                    if (\stripos($match[0], $callTmp) !== false) {
                        $patternTmp .= $callTmp . ':|';
                    }
                }
                $pattern = '#' . $search . '=.*(?:' . $patternTmp . \implode('|', $this->_never_allowed_js_callback_regex) . ')#ius';
                $matchInner = [];
                if (\preg_match($pattern, $match[1], $matchInner)) {
                    $replacer = (string) \preg_replace(
                        $pattern,
                        $search . '="' . $this->_replacement . '"',
                        $replacer
                    );
                }
            }
        }
        
        if (
            \substr($match[0], -3) === ' />'
            &&
            \substr($match[1], -2) === ' /'
            &&
            \substr($replacer, -2) !== ' /'
        ) {
            $replacer .= ' /';
        } elseif (
            \substr($match[0], -2) === '/>'
            &&
            \substr($match[1], -1) === '/'
            &&
            \substr($replacer, -1) !== '/'
        ) {
            $replacer .= '/';
        }
        
        
        return \str_ireplace($match[1], $replacer, (string) $match[0]);
    }

    /**
     * Callback method for xss_clean() to sanitize image tags.
     *
     * <p>
     * <br />
     * INFO: This limits the PCRE backtracks, making it more performance friendly
     * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
     * PHP 5.2+ on image tag heavy strings.
     * </p>
     *
     * @param string[] $match
     *
     * @return string
     */
    private function _js_src_removal_callback(array $match)
    {
        return $this->_js_removal_callback($match, 'src');
    }

    /**
     * Remove disallowed Javascript in links or img tags
     *
     * <p>
     * <br />
     * We used to do some version comparisons and use of stripos(),
     * but it is dog slow compared to these simplified non-capturing
     * preg_match(), especially if the pattern exists in the string
     * </p>
     *
     * <p>
     * <br />
     * Note: It was reported that not only space characters, but all in
     * the following pattern can be parsed as separators between a tag name
     * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C]
     * ... however, UTF8::clean() above already strips the
     * hex-encoded ones, so we'll skip them below.
     * </p>
     *
     * @param string $str
     *
     * @return string
     */
    private function _remove_disallowed_javascript($str)
    {
        do {
            $original = $str;

            if (\stripos($str, '<a') !== false) {
                $strTmp = \preg_replace_callback(
                    '#<a[^\p{L}@>]+([^>]*?)(?:>|$)#iu',
                    function ($matches) {
                        return $this->_js_link_removal_callback($matches);
                    },
                    $str
                );
                if ($strTmp === null) {
                    $strTmp = \preg_replace_callback(
                        '#<a[^\p{L}@>]+([^>]*)(?:>|$)#iu',
                        function ($matches) {
                            return $this->_js_link_removal_callback($matches);
                        },
                        $str
                    );
                }
                $str = (string)$strTmp;
            }

            if (\stripos($str, '<img') !== false) {
                $strTmp = \preg_replace_callback(
                    '#<img[^\p{L}@]+([^>]*?)(?:\s?/?>|$)#iu',
                    function ($matches) {
                        if (
                            \strpos($matches[1], 'base64') !== false
                            &&
                            \preg_match("/([\"'])?data\s*:\s*(?:image\s*\/.*)[^\1]*base64[^\1]*,[^\1]*\1?/iUus", $matches[1])
                        ) {
                            return $matches[0];
                        }

                        return $this->_js_src_removal_callback($matches);
                    },
                    $str
                );
                if ($strTmp === null) {
                    $strTmp = (string) \preg_replace_callback(
                        '#<img[^\p{L}@]+([^>]*)(?:\s?/?>|$)#iu',
                        function ($matches) {
                            if (
                                \strpos($matches[1], 'base64') !== false
                                &&
                                \preg_match("/([\"'])?data\s*:\s*(?:image\s*\/.*)[^\1]*base64[^\1]*,[^\1]*\1?/iUus", $matches[1])
                            ) {
                                return $matches[0];
                            }

                            return $this->_js_src_removal_callback($matches);
                        },
                        $str
                    );
                }
                $str = (string)$strTmp;
            }

            if (\stripos($str, '<audio') !== false) {
                $strTmp = \preg_replace_callback(
                    '#<audio[^\p{L}@]+([^>]*?)(?:\s?/?>|$)#iu',
                    function ($matches) {
                        return $this->_js_src_removal_callback($matches);
                    },
                    $str
                );
                if ($strTmp === null) {
                    $strTmp = (string) \preg_replace_callback(
                        '#<audio[^\p{L}@]+([^>]*)(?:\s?/?>|$)#iu',
                        function ($matches) {
                            return $this->_js_src_removal_callback($matches);
                        },
                        $str
                    );
                }
                $str = (string)$strTmp;
            }

            if (\stripos($str, '<video') !== false) {
                $strTmp = \preg_replace_callback(
                    '#<video[^\p{L}@]+([^>]*?)(?:\s?/?>|$)#iu',
                    function ($matches) {
                        return $this->_js_src_removal_callback($matches);
                    },
                    $str
                );
                if ($strTmp === null) {
                    $strTmp = \preg_replace_callback(
                        '#<video[^\p{L}@]+([^>]*)(?:\s?/?>|$)#iu',
                        function ($matches) {
                            return $this->_js_src_removal_callback($matches);
                        },
                        $str
                    );
                }
                $str = (string)$strTmp;
            }

            if (\stripos($str, '<source') !== false) {
                $str = (string) \preg_replace_callback(
                    '#<source[^\p{L}@]+([^>]*)(?:\s?/?>|$)#iu',
                    function ($matches) {
                        return $this->_js_src_removal_callback($matches);
                    },
                    $str
                );
            }

            if (\stripos($str, 'script') !== false) {
                // INFO: US-ASCII: ¼ === <
                $str = (string) \preg_replace(
                    '#(?:%3C|¼|<)\s*script[^\p{L}@]+(?:[^>]*)(?:\s?/?(?:%3E|¾|>)|$)#iu',
                    $this->_replacement,
                    $str
                );
            }

            if (\stripos($str, 'script') !== false) {
                // INFO: US-ASCII: ¼ === <
                $str = (string) \preg_replace(
                    '#(?:%3C|¼|<)[^\p{L}@]*/*[^\p{L}@]*(?:script[^\p{L}@]+).*(?:%3E|¾|>)?#iUus',
                    $this->_replacement,
                    $str
                );
            }
        } while ($original !== $str);

        return (string) $str;
    }

    /**
     * Remove Evil HTML Attributes (like event handlers and style).
     *
     * It removes the evil attribute and either:
     *
     *  - Everything up until a space. For example, everything between the pipes:
     *
     * <code>
     *   <a |style=document.write('hello');alert('world');| class=link>
     * </code>
     *
     *  - Everything inside the quotes. For example, everything between the pipes:
     *
     * <code>
     *   <a |style="document.write('hello'); alert('world');"| class="link">
     * </code>
     *
     * @param string $str <p>The string to check.</p>
     *
     * @return string
     *                <p>The string with the evil attributes removed.</p>
     */
    private function _remove_evil_attributes($str)
    {
        // replace style-attribute, first (if needed)
        if (
            \stripos($str, 'style') !== false
            &&
            \in_array('style', $this->_evil_attributes_regex, true)
        ) {
            do {
                $count = $temp_count = 0;

                $str = (string) \preg_replace(
                    '/(<[^>]+)(?<!\p{L})(style\s*=\s*"(?:[^"]*?)"|style\s*=\s*\'(?:[^\']*?)\')/iu',
                    '$1' . $this->_replacement,
                    $str,
                    -1,
                    $temp_count
                );
                $count += $temp_count;
            } while ($count);
        }

        if (!$this->_cache_evil_attributes_regex_string) {
            $this->_cache_evil_attributes_regex_string = \implode('|', $this->_evil_attributes_regex);
            $this->_cache_evil_attributes_regex_string .= '|' . \implode('\w*|', $this->_never_allowed_on_events_afterwards);
        }

        do {
            $count = $temp_count = 0;

            // find occurrences of illegal attribute strings with and without quotes (" and ' are octal quotes)
            $regex = '/(.*)((?:<[^>]+)(?<!\p{L}))(?:' . $this->_cache_evil_attributes_regex_string . ')(?:\s*=\s*)(?:\'(?:.*?)\'|"(?:.*?)")(.*)/ius';
            $strTmp = \preg_replace(
                $regex,
                '$1$2' . $this->_replacement . '$3$4',
                $str,
                -1,
                $temp_count
            );
            if ($strTmp === null) {
                $regex = '/(?:' . $this->_cache_evil_attributes_regex_string . ')(?:\s*=\s*)(?:\'(?:.*?)\'|"(?:.*?)")/ius';
                $strTmp = \preg_replace(
                    $regex,
                    $this->_replacement,
                    $str,
                    -1,
                    $temp_count
                );
            }
            $str = (string)$strTmp;
            $count += $temp_count;

            $regex =  '/(.*?)(<[^>]+)(?<!\p{L})(?:' . $this->_cache_evil_attributes_regex_string . ')\s*=\s*(?:[^\s>]*)/ius';
            $strTmp = \preg_replace(
                $regex,
                '$1$2' . $this->_replacement . '$3',
                $str,
                -1,
                $temp_count
            );
            if ($strTmp === null) {
                $regex =  '/(?<!\p{L})(?:' . $this->_cache_evil_attributes_regex_string . ')\s*=\s*(?:[^\s>]*)(.*?)/ius';
                $strTmp = \preg_replace(
                    $regex,
                    '$1$2' . $this->_replacement . '$3',
                    $str,
                    -1,
                    $temp_count
                );
            }
            $str = (string)$strTmp;
            $count += $temp_count;
        } while ($count);

        return (string) $str;
    }

    /**
     * UTF-7 decoding function.
     *
     * @param string $str <p>HTML document for recode ASCII part of UTF-7 back to ASCII.</p>
     *
     * @return string
     */
    private function _repack_utf7($str)
    {
        if (\strpos($str, '-') === false) {
            return $str;
        }

        return (string) \preg_replace_callback(
            '#\+([\p{L}\d]+)-#iu',
            function ($matches) {
                return $this->_repack_utf7_callback($matches);
            },
            $str
        );
    }

    /**
     * Additional UTF-7 decoding function.
     *
     * @param string[] $strings <p>Array of strings for recode ASCII part of UTF-7 back to ASCII.</p>
     *
     * @return string
     */
    private function _repack_utf7_callback($strings)
    {
        $strTmp = \base64_decode($strings[1], true);

        if ($strTmp === false) {
            return $strings[0];
        }

        if (\rtrim(\base64_encode($strTmp), '=') !== \rtrim($strings[1], '=')) {
            return $strings[0];
        }

        $string = (string) \preg_replace_callback(
            '/^((?:\x00.)*?)((?:[^\x00].)+)/us',
            function ($matches) {
                return $this->_repack_utf7_callback_back($matches);
            },
            $strTmp
        );

        return (string) \preg_replace(
            '/\x00(.)/us',
            '$1',
            $string
        );
    }

    /**
     * Additional UTF-7 encoding function.
     *
     * @param string $str <p>String for recode ASCII part of UTF-7 back to ASCII.</p>
     *
     * @return string
     */
    private function _repack_utf7_callback_back($str)
    {
        return $str[1] . '+' . \rtrim(\base64_encode($str[2]), '=') . '-';
    }

    /**
     * Sanitize naughty HTML elements.
     *
     * <p>
     * <br />
     *
     * If a tag containing any of the words in the list
     * below is found, the tag gets converted to entities.
     *
     * <br /><br />
     *
     * So this: <blink>
     * <br />
     * Becomes: &lt;blink&gt;
     * </p>
     *
     * @param string $str
     *
     * @return string
     */
    private function _sanitize_naughty_html($str)
    {
        // init
        $strEnd = '';

        do {
            $original = $str;

            if (
                \strpos($str, '<') === false
                &&
                \strpos($str, '>') === false
            ) {
                return $str;
            }

            if (!$this->_cache__evil_html_tags_str) {
                $this->_cache__evil_html_tags_str = \implode('|', $this->_evil_html_tags);
            }

            $str = (string) \preg_replace_callback(
                '#<(?<start>/*\s*)(?<tagName>' . $this->_cache__evil_html_tags_str . ')(?<end>[^><]*)(?<rest>[><]*)#ius',
                function ($matches) {
                    return $this->_sanitize_naughty_html_callback($matches);
                },
                $str
            );

            if (\strpos($str, '<') === false) {
                return $str;
            }

            if (
                $this->_xss_found
                &&
                \trim($str) === '<'
            ) {
                return '';
            }

            $str = (string) \preg_replace_callback(
                '#<(?!!--|!\[)((?<start>/*\s*)((?<tagName>[\p{L}:]+)(?=[^\p{L}]|$|)|.+)[^\s"\'\p{L}>/=]*[^>]*)(?<closeTag>>)?#iusS', // tags without comments
                function ($matches) {
                    if (
                        $this->_do_not_close_html_tags !== []
                        &&
                        isset($matches['tagName'])
                        &&
                        \in_array($matches['tagName'], $this->_do_not_close_html_tags, true)
                    ) {
                        return $matches[0];
                    }

                    return $this->_close_html_callback($matches);
                },
                $str
            );

            if ($str === $strEnd) {
                return (string) $str;
            }

            $strEnd = $str;
        } while ($original !== $str);

        return (string) $str;
    }

    /**
     * @param string[] $matches
     *
     * @return string
     */
    private function _close_html_callback($matches)
    {
        if (empty($matches['closeTag'])) {
            // allow e.g. "< $2.20" and e.g. "< 1 year"
            if (\preg_match('/^[ .,\d=%€$₢₣£₤₶ℳ₥₦₧₨රුரூ௹रू₹૱₩₪₸₫֏₭₺₼₮₯₰₷₱﷼₲₾₳₴₽₵₡¢¥円৳元៛₠¤฿؋]*$|^[ .,\d=%€$₢₣£₤₶ℳ₥₦₧₨රුரூ௹रू₹૱₩₪₸₫֏₭₺₼₮₯₰₷₱﷼₲₾₳₴₽₵₡¢¥円৳元៛₠¤฿؋]+\p{L}*\s*$/u', $matches[1])) {
                return '<' . \str_replace(['>', '<'], ['&gt;', '&lt;'], $matches[1]);
            }

            return '&lt;' . \str_replace(['>', '<'], ['&gt;', '&lt;'], $matches[1]);
        }

        return '<' . \str_replace(['>', '<'], ['&gt;', '&lt;'], $matches[1]) . '>';
    }

    /**
     * Sanitize naughty HTML.
     *
     * <p>
     * <br />
     * Callback method for AntiXSS->sanitize_naughty_html() to remove naughty HTML elements.
     * </p>
     *
     * @param string[] $matches
     *
     * @return string
     */
    private function _sanitize_naughty_html_callback($matches)
    {
        $fullMatch = $matches[0];

        // skip some edge-cases
        /** @noinspection NotOptimalIfConditionsInspection */
        if (
            (
                \strpos($fullMatch, '=') === false
                &&
                \strpos($fullMatch, ' ') === false
                &&
                \strpos($fullMatch, ':') === false
                &&
                \strpos($fullMatch, '/') === false
                &&
                \strpos($fullMatch, '\\') === false
                &&
                \stripos($fullMatch, '<' . $matches['tagName'] . '>') !== 0
                &&
                \stripos($fullMatch, '</' . $matches['tagName'] . '>') !== 0
                &&
                \stripos($fullMatch, '<' . $matches['tagName'] . '<') !== 0
            )
            ||
            \preg_match('/<\/?' . $matches['tagName'] . '\p{L}+>/ius', $fullMatch) === 1
        ) {
            return $fullMatch;
        }

        return '&lt;' . $matches['start'] . $matches['tagName'] . $matches['end'] // encode opening brace
               // encode captured opening or closing brace to prevent recursive vectors
               . \str_replace(
                   [
                       '>',
                   ],
                   [
                       '&gt;',
                   ],
                   $matches['rest']
               );
    }

    /**
     * Sanitize naughty scripting elements
     *
     * <p>
     * <br />
     *
     * Similar to above, only instead of looking for
     * tags it looks for PHP and JavaScript commands
     * that are disallowed. Rather than removing the
     * code, it simply converts the parenthesis to entities
     * rendering the code un-executable.
     *
     * <br /><br />
     *
     * For example:  <pre>eval('some code')</pre>
     * <br />
     * Becomes:      <pre>eval&#40;'some code'&#41;</pre>
     * </p>
     *
     * @param string $str
     *
     * @return string
     */
    private function _sanitize_naughty_javascript($str)
    {
        if (\strpos($str, '(') !== false) {
            $patterns = [
                'alert',
                'prompt',
                'confirm',
                'cmd',
                'passthru',
                'eval',
                'exec',
                'execScript',
                'setTimeout',
                'setInterval',
                'setImmediate',
                'expression',
                'system',
                'fopen',
                'fsockopen',
                'file',
                'file_get_contents',
                'readfile',
                'unlink',
            ];

            $found = false;
            foreach ($patterns as $pattern) {
                if (\strpos($str, $pattern) !== false) {
                    $found = true;

                    break;
                }
            }

            if ($found === true) {
                $str = (string) \preg_replace(
                    '#(?<!\p{L})(' . \implode('|', $patterns) . ')(\s*)\((.*)\)#uisU',
                    '\\1\\2&#40;\\3&#41;',
                    $str
                );
            }
        }

        return (string) $str;
    }

    /**
     * Add some strings to the "_evil_attributes"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addEvilAttributes(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_evil_attributes_regex_string = '';

        $this->_evil_attributes_regex = \array_merge(
            $strings,
            $this->_evil_attributes_regex
        );

        return $this;
    }

    /**
     * Add some strings to the "_evil_html_tags"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addEvilHtmlTags(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache__evil_html_tags_str = '';

        $this->_evil_html_tags = \array_merge(
            $strings,
            $this->_evil_html_tags
        );

        return $this;
    }

    /**
     * Add some strings to the "_never_allowed_regex"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addNeverAllowedRegex(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_never_allowed_regex_string = '';

        $this->_never_allowed_regex = \array_merge(
            $strings,
            $this->_never_allowed_regex
        );

        return $this;
    }

    /**
     * Remove some strings from the "_never_allowed_regex"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeNeverAllowedRegex(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_never_allowed_regex_string = '';

        $this->_never_allowed_regex = \array_diff(
            $this->_never_allowed_regex,
            \array_intersect($strings, $this->_never_allowed_regex)
        );

        return $this;
    }

    /**
     * Add some strings to the "_never_allowed_on_events_afterwards"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addNeverAllowedOnEventsAfterwards(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_evil_attributes_regex_string = '';

        $this->_never_allowed_on_events_afterwards = \array_merge(
            $strings,
            $this->_never_allowed_on_events_afterwards
        );

        return $this;
    }

    /**
     * Add some strings to the "_never_allowed_str_afterwards"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addNeverAllowedStrAfterwards(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_str_afterwards = \array_merge(
            $strings,
            $this->_never_allowed_str_afterwards
        );

        return $this;
    }

    /**
     * Add some strings to the "_do_not_close_html_tags"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addDoNotCloseHtmlTags(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_do_not_close_html_tags = \array_merge(
            $strings,
            $this->_do_not_close_html_tags
        );

        return $this;
    }

    /**
     * Add some strings to the "_never_allowed_js_callback_regex"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addNeverAllowedJsCallbackRegex(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_js_callback_regex = \array_merge(
            $strings,
            $this->_never_allowed_js_callback_regex
        );

        return $this;
    }
    
    /**
     * Add some strings to the "_never_allowed_call_strings"-array.
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function addNeverAllowedCallStrings(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_call_strings = \array_merge(
            $strings,
            $this->_never_allowed_call_strings
        );

        return $this;
    }

    /**
     * Remove some strings from the "_do_not_close_html_tags"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeDoNotCloseHtmlTags(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_do_not_close_html_tags = \array_diff(
            $this->_do_not_close_html_tags,
            \array_intersect($strings, $this->_do_not_close_html_tags)
        );

        return $this;
    }

    /**
     * Check if the "AntiXSS->xss_clean()"-method found an XSS attack in the last run.
     *
     * @return bool|null
     *                   <p>Will return null if the "xss_clean()" wasn't running at all.</p>
     */
    public function isXssFound()
    {
        return $this->_xss_found;
    }

    /**
     * Remove some strings from the "_evil_attributes"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeEvilAttributes(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_evil_attributes_regex_string = '';

        $this->_evil_attributes_regex = \array_diff(
            $this->_evil_attributes_regex,
            \array_intersect($strings, $this->_evil_attributes_regex)
        );

        return $this;
    }

    /**
     * Remove some strings from the "_evil_html_tags"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeEvilHtmlTags(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache__evil_html_tags_str = '';

        $this->_evil_html_tags = \array_diff(
            $this->_evil_html_tags,
            \array_intersect($strings, $this->_evil_html_tags)
        );

        return $this;
    }

    /**
     * Remove some strings from the "_never_allowed_on_events_afterwards"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeNeverAllowedOnEventsAfterwards(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        // reset
        $this->_cache_evil_attributes_regex_string = '';

        $this->_never_allowed_on_events_afterwards = \array_diff(
            $this->_never_allowed_on_events_afterwards,
            \array_intersect($strings, $this->_never_allowed_on_events_afterwards)
        );

        return $this;
    }

    /**
     * Remove some strings from the "_never_allowed_str_afterwards"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeNeverAllowedStrAfterwards(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_str_afterwards = \array_diff(
            $this->_never_allowed_str_afterwards,
            \array_intersect($strings, $this->_never_allowed_str_afterwards)
        );

        return $this;
    }

    /**
     * Remove some strings from the "_never_allowed_call_strings"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeNeverAllowedCallStrings(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_call_strings = \array_diff(
            $this->_never_allowed_call_strings,
            \array_intersect($strings, $this->_never_allowed_call_strings)
        );

        return $this;
    }

    /**
     * Remove some strings from the "_never_allowed_js_callback_regex"-array.
     *
     * <p>
     * <br />
     * WARNING: Use this method only if you have a really good reason.
     * </p>
     *
     * @param string[] $strings
     *
     * @return $this
     */
    public function removeNeverAllowedJsCallbackRegex(array $strings): self
    {
        if ($strings === []) {
            return $this;
        }

        $this->_never_allowed_js_callback_regex = \array_diff(
            $this->_never_allowed_js_callback_regex,
            \array_intersect($strings, $this->_never_allowed_js_callback_regex)
        );

        return $this;
    }

    /**
     * Set the replacement-string for not allowed strings.
     *
     * @param string $string
     *
     * @return $this
     */
    public function setReplacement($string): self
    {
        $this->_replacement = (string) $string;

        $this->_initNeverAllowedStr();
        $this->_initNeverAllowedRegex();

        return $this;
    }

    /**
     * Set the option to stripe 4-Byte chars.
     *
     * <p>
     * <br />
     * INFO: use it if your DB (MySQL) can't use "utf8mb4" -> preventing stored XSS-attacks
     * </p>
     *
     * @param bool $bool
     *
     * @return $this
     */
    public function setStripe4byteChars($bool): self
    {
        $this->_stripe_4byte_chars = (bool) $bool;

        return $this;
    }

    /**
     * XSS Clean
     *
     * <p>
     * <br />
     * Sanitizes data so that "Cross Site Scripting" hacks can be
     * prevented. This method does a fair amount of work but
     * it is extremely thorough, designed to prevent even the
     * most obscure XSS attempts. But keep in mind that nothing
     * is ever 100% foolproof...
     * </p>
     *
     * <p>
     * <br />
     * <strong>Note:</strong> Should only be used to deal with data upon submission.
     *   It's not something that should be used for general
     *   runtime processing.
     * </p>
     *
     * @see http://channel.bitflux.ch/wiki/XSS_Prevention
     *    Based in part on some code and ideas from Bitflux.
     * @see http://ha.ckers.org/xss.html
     *    To help develop this script I used this great list of
     *    vulnerabilities along with a few other hacks I've
     *    harvested from examining vulnerabilities in other programs.
     *
     * @param string|string[] $str
     *                             <p>input data e.g. string or array of strings</p>
     *
     * @return string|string[]
     *
     * @template TXssCleanInput as string|string[]
     * @phpstan-param TXssCleanInput $str
     * @phpstan-return TXssCleanInput
     */
    public function xss_clean($str)
    {
        // reset
        $this->_xss_found = null;

        // check for an array of strings
        if (\is_array($str)) {
            foreach ($str as &$value) {
                /* @phpstan-ignore-next-line | _xss_found is maybe changed via "xss_clean" */
                if ($this->_xss_found === true) {
                    $alreadyFoundXss = true;
                } else {
                    $alreadyFoundXss = false;
                }
                
                $value = $this->xss_clean($value);

                /* @phpstan-ignore-next-line | _xss_found is maybe changed via "xss_clean" */
                if ($alreadyFoundXss === true) {
                    $this->_xss_found = true;
                }
            }

            /** @var TXssCleanInput $str - hack for phpstan */
            return $str;
        }

        $old_str_backup = $str;

        // process
        do {
            $old_str = $str;
            $str = $this->_do($str);
        } while ($old_str !== $str);

        // keep the old value, if there wasn't any XSS attack
        if ($this->_xss_found !== true) {
            $str = $old_str_backup;
        }

        return $str;
    }
}
<?php

return [
    "\t" => '&Tab;',
    "\n" => '&NewLine;',
    '!'  => '&excl;',
    '"'  => '&quot;',
    '#'  => '&num;',
    '$'  => '&dollar;',
    '%'  => '&percnt;',
    '&'  => '&amp;',
    "'"  => '&apos;',
    '('  => '&lpar;',
    ')'  => '&rpar;',
    '*'  => '&ast;',
    '+'  => '&plus;',
    ','  => '&comma;',
    '.'  => '&period;',
    '/'  => '&sol;',
    ':'  => '&colon;',
    ';'  => '&semi;',
    '<'  => '&lt;',
    '<⃒' => '&nvlt;',
    '='  => '&equals;',
    '=⃥' => '&bne;',
    '>'  => '&gt;',
    '>⃒' => '&nvgt',
    '?'  => '&quest;',
    '@'  => '&commat;',
    '['  => '&lbrack;',
    ']'  => '&rsqb;',
    '^'  => '&Hat;',
    '_'  => '&lowbar;',
    '`'  => '&grave;',
    'fj' => '&fjlig;',
    '{'  => '&lbrace;',
    '|'  => '&vert;',
    '}'  => '&rcub;',
    ' '  => '&nbsp;',
    '¡'  => '&iexcl;',
    '¢'  => '&cent;',
    '£'  => '&pound;',
    '¤'  => '&curren;',
    '¥'  => '&yen;',
    '¦'  => '&brvbar;',
    '§'  => '&sect;',
    '¨'  => '&DoubleDot;',
    '©'  => '&copy;',
    'ª'  => '&ordf;',
    '«'  => '&laquo;',
    '¬'  => '&not;',
    '­'  => '&shy;',
    '®'  => '&reg;',
    '¯'  => '&macr;',
    '°'  => '&deg;',
    '±'  => '&plusmn;',
    '²'  => '&sup2;',
    '³'  => '&sup3;',
    '´'  => '&DiacriticalAcute;',
    'µ'  => '&micro;',
    '¶'  => '&para;',
    '·'  => '&CenterDot;',
    '¸'  => '&Cedilla;',
    '¹'  => '&sup1;',
    'º'  => '&ordm;',
    '»'  => '&raquo;',
    '¼'  => '&frac14;',
    '½'  => '&half;',
    '¾'  => '&frac34;',
    '¿'  => '&iquest;',
    'À'  => '&Agrave;',
    'Á'  => '&Aacute;',
    'Â'  => '&Acirc;',
    'Ã'  => '&Atilde;',
    'Ä'  => '&Auml;',
    'Å'  => '&Aring;',
    'Æ'  => '&AElig;',
    'Ç'  => '&Ccedil;',
    'È'  => '&Egrave;',
    'É'  => '&Eacute;',
    'Ê'  => '&Ecirc;',
    'Ë'  => '&Euml;',
    'Ì'  => '&Igrave;',
    'Í'  => '&Iacute;',
    'Î'  => '&Icirc;',
    'Ï'  => '&Iuml;',
    'Ð'  => '&ETH;',
    'Ñ'  => '&Ntilde;',
    'Ò'  => '&Ograve;',
    'Ó'  => '&Oacute;',
    'Ô'  => '&Ocirc;',
    'Õ'  => '&Otilde;',
    'Ö'  => '&Ouml;',
    '×'  => '&times;',
    'Ø'  => '&Oslash;',
    'Ù'  => '&Ugrave;',
    'Ú'  => '&Uacute;',
    'Û'  => '&Ucirc;',
    'Ü'  => '&Uuml;',
    'Ý'  => '&Yacute;',
    'Þ'  => '&THORN;',
    'ß'  => '&szlig;',
    'à'  => '&agrave;',
    'á'  => '&aacute;',
    'â'  => '&acirc;',
    'ã'  => '&atilde;',
    'ä'  => '&auml;',
    'å'  => '&aring;',
    'æ'  => '&aelig;',
    'ç'  => '&ccedil;',
    'è'  => '&egrave;',
    'é'  => '&eacute;',
    'ê'  => '&ecirc;',
    'ë'  => '&euml;',
    'ì'  => '&igrave;',
    'í'  => '&iacute;',
    'î'  => '&icirc;',
    'ï'  => '&iuml;',
    'ð'  => '&eth;',
    'ñ'  => '&ntilde;',
    'ò'  => '&ograve;',
    'ó'  => '&oacute;',
    'ô'  => '&ocirc;',
    'õ'  => '&otilde;',
    'ö'  => '&ouml;',
    '÷'  => '&divide;',
    'ø'  => '&oslash;',
    'ù'  => '&ugrave;',
    'ú'  => '&uacute;',
    'û'  => '&ucirc;',
    'ü'  => '&uuml;',
    'ý'  => '&yacute;',
    'þ'  => '&thorn;',
    'ÿ'  => '&yuml;',
    'Ā'  => '&Amacr;',
    'ā'  => '&amacr;',
    'Ă'  => '&Abreve;',
    'ă'  => '&abreve;',
    'Ą'  => '&Aogon;',
    'ą'  => '&aogon;',
    'Ć'  => '&Cacute;',
    'ć'  => '&cacute;',
    'Ĉ'  => '&Ccirc;',
    'ĉ'  => '&ccirc;',
    'Ċ'  => '&Cdot;',
    'ċ'  => '&cdot;',
    'Č'  => '&Ccaron;',
    'č'  => '&ccaron;',
    'Ď'  => '&Dcaron;',
    'ď'  => '&dcaron;',
    'Đ'  => '&Dstrok;',
    'đ'  => '&dstrok;',
    'Ē'  => '&Emacr;',
    'ē'  => '&emacr;',
    'Ė'  => '&Edot;',
    'ė'  => '&edot;',
    'Ę'  => '&Eogon;',
    'ę'  => '&eogon;',
    'Ě'  => '&Ecaron;',
    'ě'  => '&ecaron;',
    'Ĝ'  => '&Gcirc;',
    'ĝ'  => '&gcirc;',
    'Ğ'  => '&Gbreve;',
    'ğ'  => '&gbreve;',
    'Ġ'  => '&Gdot;',
    'ġ'  => '&gdot;',
    'Ģ'  => '&Gcedil;',
    'Ĥ'  => '&Hcirc;',
    'ĥ'  => '&hcirc;',
    'Ħ'  => '&Hstrok;',
    'ħ'  => '&hstrok;',
    'Ĩ'  => '&Itilde;',
    'ĩ'  => '&itilde;',
    'Ī'  => '&Imacr;',
    'ī'  => '&imacr;',
    'Į'  => '&Iogon;',
    'į'  => '&iogon;',
    'İ'  => '&Idot;',
    'ı'  => '&inodot;',
    'Ĳ'  => '&IJlig;',
    'ĳ'  => '&ijlig;',
    'Ĵ'  => '&Jcirc;',
    'ĵ'  => '&jcirc;',
    'Ķ'  => '&Kcedil;',
    'ķ'  => '&kcedil;',
    'ĸ'  => '&kgreen;',
    'Ĺ'  => '&Lacute;',
    'ĺ'  => '&lacute;',
    'Ļ'  => '&Lcedil;',
    'ļ'  => '&lcedil;',
    'Ľ'  => '&Lcaron;',
    'ľ'  => '&lcaron;',
    'Ŀ'  => '&Lmidot;',
    'ŀ'  => '&lmidot;',
    'Ł'  => '&Lstrok;',
    'ł'  => '&lstrok;',
    'Ń'  => '&Nacute;',
    'ń'  => '&nacute;',
    'Ņ'  => '&Ncedil;',
    'ņ'  => '&ncedil;',
    'Ň'  => '&Ncaron;',
    'ň'  => '&ncaron;',
    'ŉ'  => '&napos;',
    'Ŋ'  => '&ENG;',
    'ŋ'  => '&eng;',
    'Ō'  => '&Omacr;',
    'ō'  => '&omacr;',
    'Ő'  => '&Odblac;',
    'ő'  => '&odblac;',
    'Œ'  => '&OElig;',
    'œ'  => '&oelig;',
    'Ŕ'  => '&Racute;',
    'ŕ'  => '&racute;',
    'Ŗ'  => '&Rcedil;',
    'ŗ'  => '&rcedil;',
    'Ř'  => '&Rcaron;',
    'ř'  => '&rcaron;',
    'Ś'  => '&Sacute;',
    'ś'  => '&sacute;',
    'Ŝ'  => '&Scirc;',
    'ŝ'  => '&scirc;',
    'Ş'  => '&Scedil;',
    'ş'  => '&scedil;',
    'Š'  => '&Scaron;',
    'š'  => '&scaron;',
    'Ţ'  => '&Tcedil;',
    'ţ'  => '&tcedil;',
    'Ť'  => '&Tcaron;',
    'ť'  => '&tcaron;',
    'Ŧ'  => '&Tstrok;',
    'ŧ'  => '&tstrok;',
    'Ũ'  => '&Utilde;',
    'ũ'  => '&utilde;',
    'Ū'  => '&Umacr;',
    'ū'  => '&umacr;',
    'Ŭ'  => '&Ubreve;',
    'ŭ'  => '&ubreve;',
    'Ů'  => '&Uring;',
    'ů'  => '&uring;',
    'Ű'  => '&Udblac;',
    'ű'  => '&udblac;',
    'Ų'  => '&Uogon;',
    'ų'  => '&uogon;',
    'Ŵ'  => '&Wcirc;',
    'ŵ'  => '&wcirc;',
    'Ŷ'  => '&Ycirc;',
    'ŷ'  => '&ycirc;',
    'Ÿ'  => '&Yuml;',
    'Ź'  => '&Zacute;',
    'ź'  => '&zacute;',
    'Ż'  => '&Zdot;',
    'ż'  => '&zdot;',
    'Ž'  => '&Zcaron;',
    'ž'  => '&zcaron;',
    'ƒ'  => '&fnof;',
    'Ƶ'  => '&imped;',
    'ǵ'  => '&gacute;',
    'ȷ'  => '&jmath;',
    'ˆ'  => '&circ;',
    'ˇ'  => '&Hacek;',
    '˘'  => '&Breve;',
    '˙'  => '&dot;',
    '˚'  => '&ring;',
    '˛'  => '&ogon;',
    '˜'  => '&DiacriticalTilde;',
    '˝'  => '&DiacriticalDoubleAcute;',
    '̑'  => '&DownBreve;',
    'Α'  => '&Alpha;',
    'Β'  => '&Beta;',
    'Γ'  => '&Gamma;',
    'Δ'  => '&Delta;',
    'Ε'  => '&Epsilon;',
    'Ζ'  => '&Zeta;',
    'Η'  => '&Eta;',
    'Θ'  => '&Theta;',
    'Ι'  => '&Iota;',
    'Κ'  => '&Kappa;',
    'Λ'  => '&Lambda;',
    'Μ'  => '&Mu;',
    'Ν'  => '&Nu;',
    'Ξ'  => '&Xi;',
    'Ο'  => '&Omicron;',
    'Π'  => '&Pi;',
    'Ρ'  => '&Rho;',
    'Σ'  => '&Sigma;',
    'Τ'  => '&Tau;',
    'Υ'  => '&Upsilon;',
    'Φ'  => '&Phi;',
    'Χ'  => '&Chi;',
    'Ψ'  => '&Psi;',
    'Ω'  => '&Omega;',
    'α'  => '&alpha;',
    'β'  => '&beta;',
    'γ'  => '&gamma;',
    'δ'  => '&delta;',
    'ε'  => '&epsi;',
    'ζ'  => '&zeta;',
    'η'  => '&eta;',
    'θ'  => '&theta;',
    'ι'  => '&iota;',
    'κ'  => '&kappa;',
    'λ'  => '&lambda;',
    'μ'  => '&mu;',
    'ν'  => '&nu;',
    'ξ'  => '&xi;',
    'ο'  => '&omicron;',
    'π'  => '&pi;',
    'ρ'  => '&rho;',
    'ς'  => '&sigmav;',
    'σ'  => '&sigma;',
    'τ'  => '&tau;',
    'υ'  => '&upsi;',
    'φ'  => '&phi;',
    'χ'  => '&chi;',
    'ψ'  => '&psi;',
    'ω'  => '&omega;',
    'ϑ'  => '&thetasym;',
    'ϒ'  => '&upsih;',
    'ϕ'  => '&straightphi;',
    'ϖ'  => '&piv;',
    'Ϝ'  => '&Gammad;',
    'ϝ'  => '&gammad;',
    'ϰ'  => '&varkappa;',
    'ϱ'  => '&rhov;',
    'ϵ'  => '&straightepsilon;',
    '϶'  => '&backepsilon;',
    'Ё'  => '&IOcy;',
    'Ђ'  => '&DJcy;',
    'Ѓ'  => '&GJcy;',
    'Є'  => '&Jukcy;',
    'Ѕ'  => '&DScy;',
    'І'  => '&Iukcy;',
    'Ї'  => '&YIcy;',
    'Ј'  => '&Jsercy;',
    'Љ'  => '&LJcy;',
    'Њ'  => '&NJcy;',
    'Ћ'  => '&TSHcy;',
    'Ќ'  => '&KJcy;',
    'Ў'  => '&Ubrcy;',
    'Џ'  => '&DZcy;',
    'А'  => '&Acy;',
    'Б'  => '&Bcy;',
    'В'  => '&Vcy;',
    'Г'  => '&Gcy;',
    'Д'  => '&Dcy;',
    'Е'  => '&IEcy;',
    'Ж'  => '&ZHcy;',
    'З'  => '&Zcy;',
    'И'  => '&Icy;',
    'Й'  => '&Jcy;',
    'К'  => '&Kcy;',
    'Л'  => '&Lcy;',
    'М'  => '&Mcy;',
    'Н'  => '&Ncy;',
    'О'  => '&Ocy;',
    'П'  => '&Pcy;',
    'Р'  => '&Rcy;',
    'С'  => '&Scy;',
    'Т'  => '&Tcy;',
    'У'  => '&Ucy;',
    'Ф'  => '&Fcy;',
    'Х'  => '&KHcy;',
    'Ц'  => '&TScy;',
    'Ч'  => '&CHcy;',
    'Ш'  => '&SHcy;',
    'Щ'  => '&SHCHcy;',
    'Ъ'  => '&HARDcy;',
    'Ы'  => '&Ycy;',
    'Ь'  => '&SOFTcy;',
    'Э'  => '&Ecy;',
    'Ю'  => '&YUcy;',
    'Я'  => '&YAcy;',
    'а'  => '&acy;',
    'б'  => '&bcy;',
    'в'  => '&vcy;',
    'г'  => '&gcy;',
    'д'  => '&dcy;',
    'е'  => '&iecy;',
    'ж'  => '&zhcy;',
    'з'  => '&zcy;',
    'и'  => '&icy;',
    'й'  => '&jcy;',
    'к'  => '&kcy;',
    'л'  => '&lcy;',
    'м'  => '&mcy;',
    'н'  => '&ncy;',
    'о'  => '&ocy;',
    'п'  => '&pcy;',
    'р'  => '&rcy;',
    'с'  => '&scy;',
    'т'  => '&tcy;',
    'у'  => '&ucy;',
    'ф'  => '&fcy;',
    'х'  => '&khcy;',
    'ц'  => '&tscy;',
    'ч'  => '&chcy;',
    'ш'  => '&shcy;',
    'щ'  => '&shchcy;',
    'ъ'  => '&hardcy;',
    'ы'  => '&ycy;',
    'ь'  => '&softcy;',
    'э'  => '&ecy;',
    'ю'  => '&yucy;',
    'я'  => '&yacy;',
    'ё'  => '&iocy;',
    'ђ'  => '&djcy;',
    'ѓ'  => '&gjcy;',
    'є'  => '&jukcy;',
    'ѕ'  => '&dscy;',
    'і'  => '&iukcy;',
    'ї'  => '&yicy;',
    'ј'  => '&jsercy;',
    'љ'  => '&ljcy;',
    'њ'  => '&njcy;',
    'ћ'  => '&tshcy;',
    'ќ'  => '&kjcy;',
    'ў'  => '&ubrcy;',
    'џ'  => '&dzcy;',
    ' '  => '&ensp;',
    ' '  => '&emsp;',
    ' '  => '&emsp13;',
    ' '  => '&emsp14;',
    ' '  => '&numsp;',
    ' '  => '&puncsp;',
    ' '  => '&ThinSpace;',
    ' '  => '&hairsp;',
    '​'  => '&ZeroWidthSpace;',
    '‌'  => '&zwnj;',
    '‍'  => '&zwj;',
    '‎'  => '&lrm;',
    '‏'  => '&rlm;',
    '‐'  => '&hyphen;',
    '–'  => '&ndash;',
    '—'  => '&mdash;',
    '―'  => '&horbar;',
    '‖'  => '&Verbar;',
    '‘'  => '&OpenCurlyQuote;',
    '’'  => '&rsquo;',
    '‚'  => '&sbquo;',
    '“'  => '&OpenCurlyDoubleQuote;',
    '”'  => '&rdquo;',
    '„'  => '&bdquo;',
    '†'  => '&dagger;',
    '‡'  => '&Dagger;',
    '•'  => '&bull;',
    '‥'  => '&nldr;',
    '…'  => '&hellip;',
    '‰'  => '&permil;',
    '‱'  => '&pertenk;',
    '′'  => '&prime;',
    '″'  => '&Prime;',
    '‴'  => '&tprime;',
    '‵'  => '&backprime;',
    '‹'  => '&lsaquo;',
    '›'  => '&rsaquo;',
    '‾'  => '&oline;',
    '⁁'  => '&caret;',
    '⁃'  => '&hybull;',
    '⁄'  => '&frasl;',
    '⁏'  => '&bsemi;',
    '⁗'  => '&qprime;',
    ' '  => '&MediumSpace;',
    '  ' => '&ThickSpace;',
    '⁠'  => '&NoBreak;',
    '⁡'  => '&af;',
    '⁢'  => '&InvisibleTimes;',
    '⁣'  => '&ic;',
    '€'  => '&euro;',
    '⃛'  => '&TripleDot;',
    '⃜'  => '&DotDot;',
    'ℂ'  => '&complexes;',
    '℅'  => '&incare;',
    'ℊ'  => '&gscr;',
    'ℋ'  => '&HilbertSpace;',
    'ℌ'  => '&Hfr;',
    'ℍ'  => '&Hopf;',
    'ℎ'  => '&planckh;',
    'ℏ'  => '&planck;',
    'ℐ'  => '&imagline;',
    'ℑ'  => '&Ifr;',
    'ℒ'  => '&lagran;',
    'ℓ'  => '&ell;',
    'ℕ'  => '&naturals;',
    '№'  => '&numero;',
    '℗'  => '&copysr;',
    '℘'  => '&wp;',
    'ℙ'  => '&primes;',
    'ℚ'  => '&rationals;',
    'ℛ'  => '&realine;',
    'ℜ'  => '&Rfr;',
    'ℝ'  => '&Ropf;',
    '℞'  => '&rx;',
    '™'  => '&trade;',
    'ℤ'  => '&Zopf;',
    '℧'  => '&mho;',
    'ℨ'  => '&Zfr;',
    '℩'  => '&iiota;',
    'ℬ'  => '&Bscr;',
    'ℭ'  => '&Cfr;',
    'ℯ'  => '&escr;',
    'ℰ'  => '&expectation;',
    'ℱ'  => '&Fouriertrf;',
    'ℳ'  => '&Mellintrf;',
    'ℴ'  => '&orderof;',
    'ℵ'  => '&aleph;',
    'ℶ'  => '&beth;',
    'ℷ'  => '&gimel;',
    'ℸ'  => '&daleth;',
    'ⅅ'  => '&CapitalDifferentialD;',
    'ⅆ'  => '&DifferentialD;',
    'ⅇ'  => '&exponentiale;',
    'ⅈ'  => '&ImaginaryI;',
    '⅓'  => '&frac13;',
    '⅔'  => '&frac23;',
    '⅕'  => '&frac15;',
    '⅖'  => '&frac25;',
    '⅗'  => '&frac35;',
    '⅘'  => '&frac45;',
    '⅙'  => '&frac16;',
    '⅚'  => '&frac56;',
    '⅛'  => '&frac18;',
    '⅜'  => '&frac38;',
    '⅝'  => '&frac58;',
    '⅞'  => '&frac78;',
    '←'  => '&larr;',
    '↑'  => '&uarr;',
    '→'  => '&srarr;',
    '↓'  => '&darr;',
    '↔'  => '&harr;',
    '↕'  => '&UpDownArrow;',
    '↖'  => '&nwarrow;',
    '↗'  => '&UpperRightArrow;',
    '↘'  => '&LowerRightArrow;',
    '↙'  => '&swarr;',
    '↚'  => '&nleftarrow;',
    '↛'  => '&nrarr;',
    '↝'  => '&rarrw;',
    '↝̸' => '&nrarrw;',
    '↞'  => '&Larr;',
    '↟'  => '&Uarr;',
    '↠'  => '&twoheadrightarrow;',
    '↡'  => '&Darr;',
    '↢'  => '&larrtl;',
    '↣'  => '&rarrtl;',
    '↤'  => '&LeftTeeArrow;',
    '↥'  => '&UpTeeArrow;',
    '↦'  => '&map;',
    '↧'  => '&DownTeeArrow;',
    '↩'  => '&larrhk;',
    '↪'  => '&rarrhk;',
    '↫'  => '&larrlp;',
    '↬'  => '&looparrowright;',
    '↭'  => '&harrw;',
    '↮'  => '&nleftrightarrow;',
    '↰'  => '&Lsh;',
    '↱'  => '&rsh;',
    '↲'  => '&ldsh;',
    '↳'  => '&rdsh;',
    '↵'  => '&crarr;',
    '↶'  => '&curvearrowleft;',
    '↷'  => '&curarr;',
    '↺'  => '&olarr;',
    '↻'  => '&orarr;',
    '↼'  => '&leftharpoonup;',
    '↽'  => '&leftharpoondown;',
    '↾'  => '&RightUpVector;',
    '↿'  => '&uharl;',
    '⇀'  => '&rharu;',
    '⇁'  => '&rhard;',
    '⇂'  => '&RightDownVector;',
    '⇃'  => '&dharl;',
    '⇄'  => '&rightleftarrows;',
    '⇅'  => '&udarr;',
    '⇆'  => '&lrarr;',
    '⇇'  => '&llarr;',
    '⇈'  => '&upuparrows;',
    '⇉'  => '&rrarr;',
    '⇊'  => '&downdownarrows;',
    '⇋'  => '&leftrightharpoons;',
    '⇌'  => '&rightleftharpoons;',
    '⇍'  => '&nLeftarrow;',
    '⇎'  => '&nhArr;',
    '⇏'  => '&nrArr;',
    '⇐'  => '&DoubleLeftArrow;',
    '⇑'  => '&DoubleUpArrow;',
    '⇒'  => '&Implies;',
    '⇓'  => '&Downarrow;',
    '⇔'  => '&hArr;',
    '⇕'  => '&Updownarrow;',
    '⇖'  => '&nwArr;',
    '⇗'  => '&neArr;',
    '⇘'  => '&seArr;',
    '⇙'  => '&swArr;',
    '⇚'  => '&lAarr;',
    '⇛'  => '&rAarr;',
    '⇝'  => '&zigrarr;',
    '⇤'  => '&LeftArrowBar;',
    '⇥'  => '&RightArrowBar;',
    '⇵'  => '&DownArrowUpArrow;',
    '⇽'  => '&loarr;',
    '⇾'  => '&roarr;',
    '⇿'  => '&hoarr;',
    '∀'  => '&forall;',
    '∁'  => '&comp;',
    '∂'  => '&part;',
    '∂̸' => '&npart;',
    '∃'  => '&Exists;',
    '∄'  => '&nexist;',
    '∅'  => '&empty;',
    '∇'  => '&nabla;',
    '∈'  => '&isinv;',
    '∉'  => '&notin;',
    '∋'  => '&ReverseElement;',
    '∌'  => '&notniva;',
    '∏'  => '&prod;',
    '∐'  => '&Coproduct;',
    '∑'  => '&sum;',
    '−'  => '&minus;',
    '∓'  => '&MinusPlus;',
    '∔'  => '&plusdo;',
    '∖'  => '&ssetmn;',
    '∗'  => '&lowast;',
    '∘'  => '&compfn;',
    '√'  => '&Sqrt;',
    '∝'  => '&prop;',
    '∞'  => '&infin;',
    '∟'  => '&angrt;',
    '∠'  => '&angle;',
    '∠⃒' => '&nang;',
    '∡'  => '&angmsd;',
    '∢'  => '&angsph;',
    '∣'  => '&mid;',
    '∤'  => '&nshortmid;',
    '∥'  => '&shortparallel;',
    '∦'  => '&nparallel;',
    '∧'  => '&and;',
    '∨'  => '&or;',
    '∩'  => '&cap;',
    '∩︀' => '&caps;',
    '∪'  => '&cup;',
    '∪︀' => '&cups',
    '∫'  => '&Integral;',
    '∬'  => '&Int;',
    '∭'  => '&tint;',
    '∮'  => '&ContourIntegral;',
    '∯'  => '&DoubleContourIntegral;',
    '∰'  => '&Cconint;',
    '∱'  => '&cwint;',
    '∲'  => '&cwconint;',
    '∳'  => '&awconint;',
    '∴'  => '&there4;',
    '∵'  => '&Because;',
    '∶'  => '&ratio;',
    '∷'  => '&Colon;',
    '∸'  => '&minusd;',
    '∺'  => '&mDDot;',
    '∻'  => '&homtht;',
    '∼'  => '&sim;',
    '∼⃒' => '&nvsim;',
    '∽'  => '&bsim;',
    '∽̱' => '&race;',
    '∾'  => '&ac;',
    '∾̳' => '&acE;',
    '∿'  => '&acd;',
    '≀'  => '&wr;',
    '≁'  => '&NotTilde;',
    '≂'  => '&esim;',
    '≂̸' => '&nesim;',
    '≃'  => '&simeq;',
    '≄'  => '&nsime;',
    '≅'  => '&TildeFullEqual;',
    '≆'  => '&simne;',
    '≇'  => '&ncong;',
    '≈'  => '&approx;',
    '≉'  => '&napprox;',
    '≊'  => '&ape;',
    '≋'  => '&apid;',
    '≋̸' => '&napid;',
    '≌'  => '&bcong;',
    '≍'  => '&CupCap;',
    '≍⃒' => '&nvap;',
    '≎'  => '&bump;',
    '≎̸' => '&nbump;',
    '≏'  => '&HumpEqual;',
    '≏̸' => '&nbumpe;',
    '≐'  => '&esdot;',
    '≐̸' => '&nedot;',
    '≑'  => '&doteqdot;',
    '≒'  => '&fallingdotseq;',
    '≓'  => '&risingdotseq;',
    '≔'  => '&coloneq;',
    '≕'  => '&eqcolon;',
    '≖'  => '&ecir;',
    '≗'  => '&circeq;',
    '≙'  => '&wedgeq;',
    '≚'  => '&veeeq;',
    '≜'  => '&triangleq;',
    '≟'  => '&equest;',
    '≠'  => '&NotEqual;',
    '≡'  => '&Congruent;',
    '≡⃥' => '&bnequiv;',
    '≢'  => '&NotCongruent;',
    '≤'  => '&leq;',
    '≤⃒' => '&nvle;',
    '≥'  => '&ge;',
    '≥⃒' => '&nvge;',
    '≦'  => '&lE;',
    '≦̸' => '&nlE;',
    '≧'  => '&geqq;',
    '≧̸' => '&NotGreaterFullEqual;',
    '≨'  => '&lneqq;',
    '≨︀' => '&lvertneqq;',
    '≩'  => '&gneqq;',
    '≩︀' => '&gvertneqq;',
    '≪'  => '&ll;',
    '≪̸' => '&nLtv;',
    '≪⃒' => '&nLt;',
    '≫'  => '&gg;',
    '≫̸' => '&NotGreaterGreater;',
    '≫⃒' => '&nGt;',
    '≬'  => '&between;',
    '≭'  => '&NotCupCap;',
    '≮'  => '&NotLess;',
    '≯'  => '&ngtr;',
    '≰'  => '&NotLessEqual;',
    '≱'  => '&ngeq;',
    '≲'  => '&LessTilde;',
    '≳'  => '&GreaterTilde;',
    '≴'  => '&nlsim;',
    '≵'  => '&ngsim;',
    '≶'  => '&lessgtr;',
    '≷'  => '&gl;',
    '≸'  => '&ntlg;',
    '≹'  => '&NotGreaterLess;',
    '≺'  => '&prec;',
    '≻'  => '&succ;',
    '≼'  => '&PrecedesSlantEqual;',
    '≽'  => '&succcurlyeq;',
    '≾'  => '&precsim;',
    '≿'  => '&SucceedsTilde;',
    '≿̸' => '&NotSucceedsTilde;',
    '⊀'  => '&npr;',
    '⊁'  => '&NotSucceeds;',
    '⊂'  => '&sub;',
    '⊂⃒' => '&vnsub;',
    '⊃'  => '&sup;',
    '⊃⃒' => '&nsupset;',
    '⊄'  => '&nsub;',
    '⊅'  => '&nsup;',
    '⊆'  => '&SubsetEqual;',
    '⊇'  => '&supe;',
    '⊈'  => '&NotSubsetEqual;',
    '⊉'  => '&NotSupersetEqual;',
    '⊊'  => '&subsetneq;',
    '⊊︀' => '&vsubne;',
    '⊋'  => '&supsetneq;',
    '⊋︀' => '&vsupne;',
    '⊍'  => '&cupdot;',
    '⊎'  => '&UnionPlus;',
    '⊏'  => '&sqsub;',
    '⊏̸' => '&NotSquareSubset;',
    '⊐'  => '&sqsupset;',
    '⊐̸' => '&NotSquareSuperset;',
    '⊑'  => '&SquareSubsetEqual;',
    '⊒'  => '&SquareSupersetEqual;',
    '⊓'  => '&sqcap;',
    '⊓︀' => '&sqcaps;',
    '⊔'  => '&sqcup;',
    '⊔︀' => '&sqcups;',
    '⊕'  => '&CirclePlus;',
    '⊖'  => '&ominus;',
    '⊗'  => '&CircleTimes;',
    '⊘'  => '&osol;',
    '⊙'  => '&CircleDot;',
    '⊚'  => '&ocir;',
    '⊛'  => '&oast;',
    '⊝'  => '&odash;',
    '⊞'  => '&boxplus;',
    '⊟'  => '&boxminus;',
    '⊠'  => '&timesb;',
    '⊡'  => '&sdotb;',
    '⊢'  => '&vdash;',
    '⊣'  => '&dashv;',
    '⊤'  => '&DownTee;',
    '⊥'  => '&perp;',
    '⊧'  => '&models;',
    '⊨'  => '&DoubleRightTee;',
    '⊩'  => '&Vdash;',
    '⊪'  => '&Vvdash;',
    '⊫'  => '&VDash;',
    '⊬'  => '&nvdash;',
    '⊭'  => '&nvDash;',
    '⊮'  => '&nVdash;',
    '⊯'  => '&nVDash;',
    '⊰'  => '&prurel;',
    '⊲'  => '&vartriangleleft;',
    '⊳'  => '&vrtri;',
    '⊴'  => '&LeftTriangleEqual;',
    '⊴⃒' => '&nvltrie;',
    '⊵'  => '&RightTriangleEqual;',
    '⊵⃒' => '&nvrtrie;',
    '⊶'  => '&origof;',
    '⊷'  => '&imof;',
    '⊸'  => '&mumap;',
    '⊹'  => '&hercon;',
    '⊺'  => '&intcal;',
    '⊻'  => '&veebar;',
    '⊽'  => '&barvee;',
    '⊾'  => '&angrtvb;',
    '⊿'  => '&lrtri;',
    '⋀'  => '&xwedge;',
    '⋁'  => '&xvee;',
    '⋂'  => '&bigcap;',
    '⋃'  => '&bigcup;',
    '⋄'  => '&diamond;',
    '⋅'  => '&sdot;',
    '⋆'  => '&Star;',
    '⋇'  => '&divonx;',
    '⋈'  => '&bowtie;',
    '⋉'  => '&ltimes;',
    '⋊'  => '&rtimes;',
    '⋋'  => '&lthree;',
    '⋌'  => '&rthree;',
    '⋍'  => '&backsimeq;',
    '⋎'  => '&curlyvee;',
    '⋏'  => '&curlywedge;',
    '⋐'  => '&Sub;',
    '⋑'  => '&Supset;',
    '⋒'  => '&Cap;',
    '⋓'  => '&Cup;',
    '⋔'  => '&pitchfork;',
    '⋕'  => '&epar;',
    '⋖'  => '&lessdot;',
    '⋗'  => '&gtrdot;',
    '⋘'  => '&Ll;',
    '⋘̸' => '&nLl;',
    '⋙'  => '&Gg;',
    '⋙̸' => '&nGg;',
    '⋚'  => '&lesseqgtr;',
    '⋚︀' => '&lesg;',
    '⋛'  => '&gtreqless;',
    '⋛︀' => '&gesl;',
    '⋞'  => '&curlyeqprec;',
    '⋟'  => '&cuesc;',
    '⋠'  => '&NotPrecedesSlantEqual;',
    '⋡'  => '&NotSucceedsSlantEqual;',
    '⋢'  => '&NotSquareSubsetEqual;',
    '⋣'  => '&NotSquareSupersetEqual;',
    '⋦'  => '&lnsim;',
    '⋧'  => '&gnsim;',
    '⋨'  => '&precnsim;',
    '⋩'  => '&scnsim;',
    '⋪'  => '&nltri;',
    '⋫'  => '&ntriangleright;',
    '⋬'  => '&nltrie;',
    '⋭'  => '&NotRightTriangleEqual;',
    '⋮'  => '&vellip;',
    '⋯'  => '&ctdot;',
    '⋰'  => '&utdot;',
    '⋱'  => '&dtdot;',
    '⋲'  => '&disin;',
    '⋳'  => '&isinsv;',
    '⋴'  => '&isins;',
    '⋵'  => '&isindot;',
    '⋵̸' => '&notindot;',
    '⋶'  => '&notinvc;',
    '⋷'  => '&notinvb;',
    '⋹'  => '&isinE;',
    '⋹̸' => '&notinE;',
    '⋺'  => '&nisd;',
    '⋻'  => '&xnis;',
    '⋼'  => '&nis;',
    '⋽'  => '&notnivc;',
    '⋾'  => '&notnivb;',
    '⌅'  => '&barwed;',
    '⌆'  => '&doublebarwedge;',
    '⌈'  => '&lceil;',
    '⌉'  => '&RightCeiling;',
    '⌊'  => '&LeftFloor;',
    '⌋'  => '&RightFloor;',
    '⌌'  => '&drcrop;',
    '⌍'  => '&dlcrop;',
    '⌎'  => '&urcrop;',
    '⌏'  => '&ulcrop;',
    '⌐'  => '&bnot;',
    '⌒'  => '&profline;',
    '⌓'  => '&profsurf;',
    '⌕'  => '&telrec;',
    '⌖'  => '&target;',
    '⌜'  => '&ulcorner;',
    '⌝'  => '&urcorner;',
    '⌞'  => '&llcorner;',
    '⌟'  => '&drcorn;',
    '⌢'  => '&frown;',
    '⌣'  => '&smile;',
    '⌭'  => '&cylcty;',
    '⌮'  => '&profalar;',
    '⌶'  => '&topbot;',
    '⌽'  => '&ovbar;',
    '⌿'  => '&solbar;',
    '⍼'  => '&angzarr;',
    '⎰'  => '&lmoust;',
    '⎱'  => '&rmoust;',
    '⎴'  => '&OverBracket;',
    '⎵'  => '&bbrk;',
    '⎶'  => '&bbrktbrk;',
    '⏜'  => '&OverParenthesis;',
    '⏝'  => '&UnderParenthesis;',
    '⏞'  => '&OverBrace;',
    '⏟'  => '&UnderBrace;',
    '⏢'  => '&trpezium;',
    '⏧'  => '&elinters;',
    '␣'  => '&blank;',
    'Ⓢ'  => '&oS;',
    '─'  => '&HorizontalLine;',
    '│'  => '&boxv;',
    '┌'  => '&boxdr;',
    '┐'  => '&boxdl;',
    '└'  => '&boxur;',
    '┘'  => '&boxul;',
    '├'  => '&boxvr;',
    '┤'  => '&boxvl;',
    '┬'  => '&boxhd;',
    '┴'  => '&boxhu;',
    '┼'  => '&boxvh;',
    '═'  => '&boxH;',
    '║'  => '&boxV;',
    '╒'  => '&boxdR;',
    '╓'  => '&boxDr;',
    '╔'  => '&boxDR;',
    '╕'  => '&boxdL;',
    '╖'  => '&boxDl;',
    '╗'  => '&boxDL;',
    '╘'  => '&boxuR;',
    '╙'  => '&boxUr;',
    '╚'  => '&boxUR;',
    '╛'  => '&boxuL;',
    '╜'  => '&boxUl;',
    '╝'  => '&boxUL;',
    '╞'  => '&boxvR;',
    '╟'  => '&boxVr;',
    '╠'  => '&boxVR;',
    '╡'  => '&boxvL;',
    '╢'  => '&boxVl;',
    '╣'  => '&boxVL;',
    '╤'  => '&boxHd;',
    '╥'  => '&boxhD;',
    '╦'  => '&boxHD;',
    '╧'  => '&boxHu;',
    '╨'  => '&boxhU;',
    '╩'  => '&boxHU;',
    '╪'  => '&boxvH;',
    '╫'  => '&boxVh;',
    '╬'  => '&boxVH;',
    '▀'  => '&uhblk;',
    '▄'  => '&lhblk;',
    '█'  => '&block;',
    '░'  => '&blk14;',
    '▒'  => '&blk12;',
    '▓'  => '&blk34;',
    '□'  => '&Square;',
    '▪'  => '&squarf;',
    '▫'  => '&EmptyVerySmallSquare;',
    '▭'  => '&rect;',
    '▮'  => '&marker;',
    '▱'  => '&fltns;',
    '△'  => '&bigtriangleup;',
    '▴'  => '&blacktriangle;',
    '▵'  => '&triangle;',
    '▸'  => '&blacktriangleright;',
    '▹'  => '&rtri;',
    '▽'  => '&bigtriangledown;',
    '▾'  => '&blacktriangledown;',
    '▿'  => '&triangledown;',
    '◂'  => '&blacktriangleleft;',
    '◃'  => '&ltri;',
    '◊'  => '&lozenge;',
    '○'  => '&cir;',
    '◬'  => '&tridot;',
    '◯'  => '&bigcirc;',
    '◸'  => '&ultri;',
    '◹'  => '&urtri;',
    '◺'  => '&lltri;',
    '◻'  => '&EmptySmallSquare;',
    '◼'  => '&FilledSmallSquare;',
    '★'  => '&starf;',
    '☆'  => '&star;',
    '☎'  => '&phone;',
    '♀'  => '&female;',
    '♂'  => '&male;',
    '♠'  => '&spadesuit;',
    '♣'  => '&clubs;',
    '♥'  => '&hearts;',
    '♦'  => '&diamondsuit;',
    '♪'  => '&sung;',
    '♭'  => '&flat;',
    '♮'  => '&natur;',
    '♯'  => '&sharp;',
    '✓'  => '&check;',
    '✗'  => '&cross;',
    '✠'  => '&maltese;',
    '✶'  => '&sext;',
    '❘'  => '&VerticalSeparator;',
    '❲'  => '&lbbrk;',
    '❳'  => '&rbbrk;',
    '⟈'  => '&bsolhsub;',
    '⟉'  => '&suphsol;',
    '⟦'  => '&LeftDoubleBracket;',
    '⟧'  => '&RightDoubleBracket;',
    '⟨'  => '&langle;',
    '⟩'  => '&RightAngleBracket;',
    '⟪'  => '&Lang;',
    '⟫'  => '&Rang;',
    '⟬'  => '&loang;',
    '⟭'  => '&roang;',
    '⟵'  => '&longleftarrow;',
    '⟶'  => '&LongRightArrow;',
    '⟷'  => '&LongLeftRightArrow;',
    '⟸'  => '&xlArr;',
    '⟹'  => '&DoubleLongRightArrow;',
    '⟺'  => '&xhArr;',
    '⟼'  => '&xmap;',
    '⟿'  => '&dzigrarr;',
    '⤂'  => '&nvlArr;',
    '⤃'  => '&nvrArr;',
    '⤄'  => '&nvHarr;',
    '⤅'  => '&Map;',
    '⤌'  => '&lbarr;',
    '⤍'  => '&bkarow;',
    '⤎'  => '&lBarr;',
    '⤏'  => '&dbkarow;',
    '⤐'  => '&drbkarow;',
    '⤑'  => '&DDotrahd;',
    '⤒'  => '&UpArrowBar;',
    '⤓'  => '&DownArrowBar;',
    '⤖'  => '&Rarrtl;',
    '⤙'  => '&latail;',
    '⤚'  => '&ratail;',
    '⤛'  => '&lAtail;',
    '⤜'  => '&rAtail;',
    '⤝'  => '&larrfs;',
    '⤞'  => '&rarrfs;',
    '⤟'  => '&larrbfs;',
    '⤠'  => '&rarrbfs;',
    '⤣'  => '&nwarhk;',
    '⤤'  => '&nearhk;',
    '⤥'  => '&searhk;',
    '⤦'  => '&swarhk;',
    '⤧'  => '&nwnear;',
    '⤨'  => '&toea;',
    '⤩'  => '&seswar;',
    '⤪'  => '&swnwar;',
    '⤳'  => '&rarrc;',
    '⤳̸' => '&nrarrc;',
    '⤵'  => '&cudarrr;',
    '⤶'  => '&ldca;',
    '⤷'  => '&rdca;',
    '⤸'  => '&cudarrl;',
    '⤹'  => '&larrpl;',
    '⤼'  => '&curarrm;',
    '⤽'  => '&cularrp;',
    '⥅'  => '&rarrpl;',
    '⥈'  => '&harrcir;',
    '⥉'  => '&Uarrocir;',
    '⥊'  => '&lurdshar;',
    '⥋'  => '&ldrushar;',
    '⥎'  => '&LeftRightVector;',
    '⥏'  => '&RightUpDownVector;',
    '⥐'  => '&DownLeftRightVector;',
    '⥑'  => '&LeftUpDownVector;',
    '⥒'  => '&LeftVectorBar;',
    '⥓'  => '&RightVectorBar;',
    '⥔'  => '&RightUpVectorBar;',
    '⥕'  => '&RightDownVectorBar;',
    '⥖'  => '&DownLeftVectorBar;',
    '⥗'  => '&DownRightVectorBar;',
    '⥘'  => '&LeftUpVectorBar;',
    '⥙'  => '&LeftDownVectorBar;',
    '⥚'  => '&LeftTeeVector;',
    '⥛'  => '&RightTeeVector;',
    '⥜'  => '&RightUpTeeVector;',
    '⥝'  => '&RightDownTeeVector;',
    '⥞'  => '&DownLeftTeeVector;',
    '⥟'  => '&DownRightTeeVector;',
    '⥠'  => '&LeftUpTeeVector;',
    '⥡'  => '&LeftDownTeeVector;',
    '⥢'  => '&lHar;',
    '⥣'  => '&uHar;',
    '⥤'  => '&rHar;',
    '⥥'  => '&dHar;',
    '⥦'  => '&luruhar;',
    '⥧'  => '&ldrdhar;',
    '⥨'  => '&ruluhar;',
    '⥩'  => '&rdldhar;',
    '⥪'  => '&lharul;',
    '⥫'  => '&llhard;',
    '⥬'  => '&rharul;',
    '⥭'  => '&lrhard;',
    '⥮'  => '&udhar;',
    '⥯'  => '&ReverseUpEquilibrium;',
    '⥰'  => '&RoundImplies;',
    '⥱'  => '&erarr;',
    '⥲'  => '&simrarr;',
    '⥳'  => '&larrsim;',
    '⥴'  => '&rarrsim;',
    '⥵'  => '&rarrap;',
    '⥶'  => '&ltlarr;',
    '⥸'  => '&gtrarr;',
    '⥹'  => '&subrarr;',
    '⥻'  => '&suplarr;',
    '⥼'  => '&lfisht;',
    '⥽'  => '&rfisht;',
    '⥾'  => '&ufisht;',
    '⥿'  => '&dfisht;',
    '⦅'  => '&lopar;',
    '⦆'  => '&ropar;',
    '⦋'  => '&lbrke;',
    '⦌'  => '&rbrke;',
    '⦍'  => '&lbrkslu;',
    '⦎'  => '&rbrksld;',
    '⦏'  => '&lbrksld;',
    '⦐'  => '&rbrkslu;',
    '⦑'  => '&langd;',
    '⦒'  => '&rangd;',
    '⦓'  => '&lparlt;',
    '⦔'  => '&rpargt;',
    '⦕'  => '&gtlPar;',
    '⦖'  => '&ltrPar;',
    '⦚'  => '&vzigzag;',
    '⦜'  => '&vangrt;',
    '⦝'  => '&angrtvbd;',
    '⦤'  => '&ange;',
    '⦥'  => '&range;',
    '⦦'  => '&dwangle;',
    '⦧'  => '&uwangle;',
    '⦨'  => '&angmsdaa;',
    '⦩'  => '&angmsdab;',
    '⦪'  => '&angmsdac;',
    '⦫'  => '&angmsdad;',
    '⦬'  => '&angmsdae;',
    '⦭'  => '&angmsdaf;',
    '⦮'  => '&angmsdag;',
    '⦯'  => '&angmsdah;',
    '⦰'  => '&bemptyv;',
    '⦱'  => '&demptyv;',
    '⦲'  => '&cemptyv;',
    '⦳'  => '&raemptyv;',
    '⦴'  => '&laemptyv;',
    '⦵'  => '&ohbar;',
    '⦶'  => '&omid;',
    '⦷'  => '&opar;',
    '⦹'  => '&operp;',
    '⦻'  => '&olcross;',
    '⦼'  => '&odsold;',
    '⦾'  => '&olcir;',
    '⦿'  => '&ofcir;',
    '⧀'  => '&olt;',
    '⧁'  => '&ogt;',
    '⧂'  => '&cirscir;',
    '⧃'  => '&cirE;',
    '⧄'  => '&solb;',
    '⧅'  => '&bsolb;',
    '⧉'  => '&boxbox;',
    '⧍'  => '&trisb;',
    '⧎'  => '&rtriltri;',
    '⧏'  => '&LeftTriangleBar;',
    '⧏̸' => '&NotLeftTriangleBar;',
    '⧐'  => '&RightTriangleBar;',
    '⧐̸' => '&NotRightTriangleBar;',
    '⧜'  => '&iinfin;',
    '⧝'  => '&infintie;',
    '⧞'  => '&nvinfin;',
    '⧣'  => '&eparsl;',
    '⧤'  => '&smeparsl;',
    '⧥'  => '&eqvparsl;',
    '⧫'  => '&lozf;',
    '⧴'  => '&RuleDelayed;',
    '⧶'  => '&dsol;',
    '⨀'  => '&xodot;',
    '⨁'  => '&bigoplus;',
    '⨂'  => '&bigotimes;',
    '⨄'  => '&biguplus;',
    '⨆'  => '&bigsqcup;',
    '⨌'  => '&iiiint;',
    '⨍'  => '&fpartint;',
    '⨐'  => '&cirfnint;',
    '⨑'  => '&awint;',
    '⨒'  => '&rppolint;',
    '⨓'  => '&scpolint;',
    '⨔'  => '&npolint;',
    '⨕'  => '&pointint;',
    '⨖'  => '&quatint;',
    '⨗'  => '&intlarhk;',
    '⨢'  => '&pluscir;',
    '⨣'  => '&plusacir;',
    '⨤'  => '&simplus;',
    '⨥'  => '&plusdu;',
    '⨦'  => '&plussim;',
    '⨧'  => '&plustwo;',
    '⨩'  => '&mcomma;',
    '⨪'  => '&minusdu;',
    '⨭'  => '&loplus;',
    '⨮'  => '&roplus;',
    '⨯'  => '&Cross;',
    '⨰'  => '&timesd;',
    '⨱'  => '&timesbar;',
    '⨳'  => '&smashp;',
    '⨴'  => '&lotimes;',
    '⨵'  => '&rotimes;',
    '⨶'  => '&otimesas;',
    '⨷'  => '&Otimes;',
    '⨸'  => '&odiv;',
    '⨹'  => '&triplus;',
    '⨺'  => '&triminus;',
    '⨻'  => '&tritime;',
    '⨼'  => '&iprod;',
    '⨿'  => '&amalg;',
    '⩀'  => '&capdot;',
    '⩂'  => '&ncup;',
    '⩃'  => '&ncap;',
    '⩄'  => '&capand;',
    '⩅'  => '&cupor;',
    '⩆'  => '&cupcap;',
    '⩇'  => '&capcup;',
    '⩈'  => '&cupbrcap;',
    '⩉'  => '&capbrcup;',
    '⩊'  => '&cupcup;',
    '⩋'  => '&capcap;',
    '⩌'  => '&ccups;',
    '⩍'  => '&ccaps;',
    '⩐'  => '&ccupssm;',
    '⩓'  => '&And;',
    '⩔'  => '&Or;',
    '⩕'  => '&andand;',
    '⩖'  => '&oror;',
    '⩗'  => '&orslope;',
    '⩘'  => '&andslope;',
    '⩚'  => '&andv;',
    '⩛'  => '&orv;',
    '⩜'  => '&andd;',
    '⩝'  => '&ord;',
    '⩟'  => '&wedbar;',
    '⩦'  => '&sdote;',
    '⩪'  => '&simdot;',
    '⩭'  => '&congdot;',
    '⩭̸' => '&ncongdot;',
    '⩮'  => '&easter;',
    '⩯'  => '&apacir;',
    '⩰'  => '&apE;',
    '⩰̸' => '&napE;',
    '⩱'  => '&eplus;',
    '⩲'  => '&pluse;',
    '⩳'  => '&Esim;',
    '⩴'  => '&Colone;',
    '⩵'  => '&Equal;',
    '⩷'  => '&ddotseq;',
    '⩸'  => '&equivDD;',
    '⩹'  => '&ltcir;',
    '⩺'  => '&gtcir;',
    '⩻'  => '&ltquest;',
    '⩼'  => '&gtquest;',
    '⩽'  => '&les;',
    '⩽̸' => '&nles;',
    '⩾'  => '&ges;',
    '⩾̸' => '&nges;',
    '⩿'  => '&lesdot;',
    '⪀'  => '&gesdot;',
    '⪁'  => '&lesdoto;',
    '⪂'  => '&gesdoto;',
    '⪃'  => '&lesdotor;',
    '⪄'  => '&gesdotol;',
    '⪅'  => '&lap;',
    '⪆'  => '&gap;',
    '⪇'  => '&lne;',
    '⪈'  => '&gne;',
    '⪉'  => '&lnap;',
    '⪊'  => '&gnap;',
    '⪋'  => '&lesseqqgtr;',
    '⪌'  => '&gEl;',
    '⪍'  => '&lsime;',
    '⪎'  => '&gsime;',
    '⪏'  => '&lsimg;',
    '⪐'  => '&gsiml;',
    '⪑'  => '&lgE;',
    '⪒'  => '&glE;',
    '⪓'  => '&lesges;',
    '⪔'  => '&gesles;',
    '⪕'  => '&els;',
    '⪖'  => '&egs;',
    '⪗'  => '&elsdot;',
    '⪘'  => '&egsdot;',
    '⪙'  => '&el;',
    '⪚'  => '&eg;',
    '⪝'  => '&siml;',
    '⪞'  => '&simg;',
    '⪟'  => '&simlE;',
    '⪠'  => '&simgE;',
    '⪡'  => '&LessLess;',
    '⪡̸' => '&NotNestedLessLess;',
    '⪢'  => '&GreaterGreater;',
    '⪢̸' => '&NotNestedGreaterGreater;',
    '⪤'  => '&glj;',
    '⪥'  => '&gla;',
    '⪦'  => '&ltcc;',
    '⪧'  => '&gtcc;',
    '⪨'  => '&lescc;',
    '⪩'  => '&gescc;',
    '⪪'  => '&smt;',
    '⪫'  => '&lat;',
    '⪬'  => '&smte;',
    '⪬︀' => '&smtes;',
    '⪭'  => '&late;',
    '⪭︀' => '&lates;',
    '⪮'  => '&bumpE;',
    '⪯'  => '&preceq;',
    '⪯̸' => '&NotPrecedesEqual;',
    '⪰'  => '&SucceedsEqual;',
    '⪰̸' => '&NotSucceedsEqual;',
    '⪳'  => '&prE;',
    '⪴'  => '&scE;',
    '⪵'  => '&precneqq;',
    '⪶'  => '&scnE;',
    '⪷'  => '&precapprox;',
    '⪸'  => '&succapprox;',
    '⪹'  => '&precnapprox;',
    '⪺'  => '&succnapprox;',
    '⪻'  => '&Pr;',
    '⪼'  => '&Sc;',
    '⪽'  => '&subdot;',
    '⪾'  => '&supdot;',
    '⪿'  => '&subplus;',
    '⫀'  => '&supplus;',
    '⫁'  => '&submult;',
    '⫂'  => '&supmult;',
    '⫃'  => '&subedot;',
    '⫄'  => '&supedot;',
    '⫅'  => '&subE;',
    '⫅̸' => '&nsubE;',
    '⫆'  => '&supseteqq;',
    '⫆̸' => '&nsupseteqq;',
    '⫇'  => '&subsim;',
    '⫈'  => '&supsim;',
    '⫋'  => '&subsetneqq;',
    '⫋︀' => '&vsubnE;',
    '⫌'  => '&supnE;',
    '⫌︀' => '&varsupsetneqq;',
    '⫏'  => '&csub;',
    '⫐'  => '&csup;',
    '⫑'  => '&csube;',
    '⫒'  => '&csupe;',
    '⫓'  => '&subsup;',
    '⫔'  => '&supsub;',
    '⫕'  => '&subsub;',
    '⫖'  => '&supsup;',
    '⫗'  => '&suphsub;',
    '⫘'  => '&supdsub;',
    '⫙'  => '&forkv;',
    '⫚'  => '&topfork;',
    '⫛'  => '&mlcp;',
    '⫤'  => '&Dashv;',
    '⫦'  => '&Vdashl;',
    '⫧'  => '&Barv;',
    '⫨'  => '&vBar;',
    '⫩'  => '&vBarv;',
    '⫫'  => '&Vbar;',
    '⫬'  => '&Not;',
    '⫭'  => '&bNot;',
    '⫮'  => '&rnmid;',
    '⫯'  => '&cirmid;',
    '⫰'  => '&midcir;',
    '⫱'  => '&topcir;',
    '⫲'  => '&nhpar;',
    '⫳'  => '&parsim;',
    '⫽'  => '&parsl;',
    '⫽⃥' => '&nparsl;',
    'ﬀ'  => '&fflig;',
    'ﬁ'  => '&filig;',
    'ﬂ'  => '&fllig;',
    'ﬃ'  => '&ffilig;',
    'ﬄ'  => '&ffllig;',
    '𝒜'  => '&Ascr;',
    '𝒞'  => '&Cscr;',
    '𝒟'  => '&Dscr;',
    '𝒢'  => '&Gscr;',
    '𝒥'  => '&Jscr;',
    '𝒦'  => '&Kscr;',
    '𝒩'  => '&Nscr;',
    '𝒪'  => '&Oscr;',
    '𝒫'  => '&Pscr;',
    '𝒬'  => '&Qscr;',
    '𝒮'  => '&Sscr;',
    '𝒯'  => '&Tscr;',
    '𝒰'  => '&Uscr;',
    '𝒱'  => '&Vscr;',
    '𝒲'  => '&Wscr;',
    '𝒳'  => '&Xscr;',
    '𝒴'  => '&Yscr;',
    '𝒵'  => '&Zscr;',
    '𝒶'  => '&ascr;',
    '𝒷'  => '&bscr;',
    '𝒸'  => '&cscr;',
    '𝒹'  => '&dscr;',
    '𝒻'  => '&fscr;',
    '𝒽'  => '&hscr;',
    '𝒾'  => '&iscr;',
    '𝒿'  => '&jscr;',
    '𝓀'  => '&kscr;',
    '𝓁'  => '&lscr;',
    '𝓂'  => '&mscr;',
    '𝓃'  => '&nscr;',
    '𝓅'  => '&pscr;',
    '𝓆'  => '&qscr;',
    '𝓇'  => '&rscr;',
    '𝓈'  => '&sscr;',
    '𝓉'  => '&tscr;',
    '𝓊'  => '&uscr;',
    '𝓋'  => '&vscr;',
    '𝓌'  => '&wscr;',
    '𝓍'  => '&xscr;',
    '𝓎'  => '&yscr;',
    '𝓏'  => '&zscr;',
    '𝔄'  => '&Afr;',
    '𝔅'  => '&Bfr;',
    '𝔇'  => '&Dfr;',
    '𝔈'  => '&Efr;',
    '𝔉'  => '&Ffr;',
    '𝔊'  => '&Gfr;',
    '𝔍'  => '&Jfr;',
    '𝔎'  => '&Kfr;',
    '𝔏'  => '&Lfr;',
    '𝔐'  => '&Mfr;',
    '𝔑'  => '&Nfr;',
    '𝔒'  => '&Ofr;',
    '𝔓'  => '&Pfr;',
    '𝔔'  => '&Qfr;',
    '𝔖'  => '&Sfr;',
    '𝔗'  => '&Tfr;',
    '𝔘'  => '&Ufr;',
    '𝔙'  => '&Vfr;',
    '𝔚'  => '&Wfr;',
    '𝔛'  => '&Xfr;',
    '𝔜'  => '&Yfr;',
    '𝔞'  => '&afr;',
    '𝔟'  => '&bfr;',
    '𝔠'  => '&cfr;',
    '𝔡'  => '&dfr;',
    '𝔢'  => '&efr;',
    '𝔣'  => '&ffr;',
    '𝔤'  => '&gfr;',
    '𝔥'  => '&hfr;',
    '𝔦'  => '&ifr;',
    '𝔧'  => '&jfr;',
    '𝔨'  => '&kfr;',
    '𝔩'  => '&lfr;',
    '𝔪'  => '&mfr;',
    '𝔫'  => '&nfr;',
    '𝔬'  => '&ofr;',
    '𝔭'  => '&pfr;',
    '𝔮'  => '&qfr;',
    '𝔯'  => '&rfr;',
    '𝔰'  => '&sfr;',
    '𝔱'  => '&tfr;',
    '𝔲'  => '&ufr;',
    '𝔳'  => '&vfr;',
    '𝔴'  => '&wfr;',
    '𝔵'  => '&xfr;',
    '𝔶'  => '&yfr;',
    '𝔷'  => '&zfr;',
    '𝔸'  => '&Aopf;',
    '𝔹'  => '&Bopf;',
    '𝔻'  => '&Dopf;',
    '𝔼'  => '&Eopf;',
    '𝔽'  => '&Fopf;',
    '𝔾'  => '&Gopf;',
    '𝕀'  => '&Iopf;',
    '𝕁'  => '&Jopf;',
    '𝕂'  => '&Kopf;',
    '𝕃'  => '&Lopf;',
    '𝕄'  => '&Mopf;',
    '𝕆'  => '&Oopf;',
    '𝕊'  => '&Sopf;',
    '𝕋'  => '&Topf;',
    '𝕌'  => '&Uopf;',
    '𝕍'  => '&Vopf;',
    '𝕎'  => '&Wopf;',
    '𝕏'  => '&Xopf;',
    '𝕐'  => '&Yopf;',
    '𝕒'  => '&aopf;',
    '𝕓'  => '&bopf;',
    '𝕔'  => '&copf;',
    '𝕕'  => '&dopf;',
    '𝕖'  => '&eopf;',
    '𝕗'  => '&fopf;',
    '𝕘'  => '&gopf;',
    '𝕙'  => '&hopf;',
    '𝕚'  => '&iopf;',
    '𝕛'  => '&jopf;',
    '𝕜'  => '&kopf;',
    '𝕝'  => '&lopf;',
    '𝕞'  => '&mopf;',
    '𝕟'  => '&nopf;',
    '𝕠'  => '&oopf;',
    '𝕡'  => '&popf;',
    '𝕢'  => '&qopf;',
    '𝕣'  => '&ropf;',
    '𝕤'  => '&sopf;',
    '𝕥'  => '&topf;',
    '𝕦'  => '&uopf;',
    '𝕧'  => '&vopf;',
    '𝕨'  => '&wopf;',
    '𝕩'  => '&xopf;',
    '𝕪'  => '&yopf;',
    '𝕫'  => '&zopf;',
];
<?php

declare(strict_types=1);

namespace Arrayy;

use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckInterface;
use Arrayy\TypeCheck\TypeCheckPhpDoc;

/**
 * Arrayy - Methods to manage arrays.
 *
 * ## 🇷🇺 Русским гражданам
 * В Украине сейчас идет война. Силами РФ наносятся удары по гражданской инфраструктуре в [Харькове][1], [Киеве][2], [Чернигове][3], [Сумах][4], [Ирпене][5] и десятках других городов. Гибнут люди - и гражданское население, и военные, в том числе российские призывники, которых бросили воевать. Чтобы лишить собственный народ доступа к информации, правительство РФ запретило называть войну войной, закрыло независимые СМИ и принимает сейчас ряд диктаторских законов. Эти законы призваны заткнуть рот всем, кто против войны. За обычный призыв к миру сейчас можно получить несколько лет тюрьмы.
 * Не молчите! Молчание - знак вашего согласия с политикой российского правительства.
 *  **Вы можете сделать выбор НЕ МОЛЧАТЬ.**
 * ---
 * ## 🇺🇸 To people of Russia
 * There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilian infrastructure in [Kharkiv][1], [Kyiv][2], [Chernihiv][3], [Sumy][4], [Irpin][5] and dozens of other cities. People are dying – both civilians and military servicemen, including Russian conscripts who were thrown into the fighting. In order to deprive its own people of access to information, the government of the Russian Federation has forbidden calling a war a war, shut down independent media and is passing a number of dictatorial laws. These laws are meant to silence all those who are against war. You can be jailed for multiple years for simply calling for peace.
 * Do not be silent! Silence is a sign that you accept the Russian government's policy.
 * **You can choose NOT TO BE SILENT.**
 * ---
 * - [1] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/P7K2MSZDGFMIJPDD7CI2GIROJI.jpg "Kharkiv under attack"
 * - [2] https://gdb.voanews.com/01bd0000-0aff-0242-fad0-08d9fc92c5b3_cx0_cy5_cw0_w1023_r1_s.jpg "Kyiv under attack"
 * - [3] https://ichef.bbci.co.uk/news/976/cpsprodpb/163DD/production/_123510119_hi074310744.jpg "Chernihiv under attack"
 * - [4] https://www.youtube.com/watch?v=8K-bkqKKf2A "Sumy under attack"
 * - [5] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/K4MTMLEHTRKGFK3GSKAT4GR3NE.jpg "Irpin under attack"
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @template TKey of array-key
 * @template T
 * @extends \ArrayObject<TKey,T>
 * @implements \IteratorAggregate<TKey,T>
 * @implements \ArrayAccess<TKey,T>
 */
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
{
    const ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES = '!!!!Arrayy_Helper_Types_For_All_Properties!!!!';

    const ARRAYY_HELPER_WALK = '!!!!Arrayy_Helper_Walk!!!!';

    /**
     * @var array
     *
     * @phpstan-var array<array-key|TKey,T>
     */
    protected $array = [];

    /**
     * @var \Arrayy\ArrayyRewindableGenerator|null
     *
     * @phpstan-var \Arrayy\ArrayyRewindableGenerator<TKey,T>|null
     */
    protected $generator;

    /**
     * @var string
     *
     * @phpstan-var class-string<\Arrayy\ArrayyIterator>
     */
    protected $iteratorClass = ArrayyIterator::class;

    /**
     * @var non-empty-string
     */
    protected $pathSeparator = '.';

    /**
     * @var bool
     */
    protected $checkPropertyTypes = false;

    /**
     * @var bool
     */
    protected $checkForMissingPropertiesInConstructor = false;

    /**
     * @var bool
     */
    protected $checkPropertiesMismatchInConstructor = false;

    /**
     * @var bool
     */
    protected $checkPropertiesMismatch = true;

    /**
     * @var array<array-key,TypeCheckInterface>|TypeCheckArray<array-key,TypeCheckInterface>
     */
    protected $properties = [];

    /**
     * Initializes
     *
     * @param mixed  $data                         <p>
     *                                             Should be an array or a generator, otherwise it will try
     *                                             to convert it into an array.
     *                                             </p>
     * @param string $iteratorClass                optional <p>
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
     *                                             need this option.
     *                                             </p>
     * @param bool   $checkPropertiesInConstructor optional <p>
     *                                             You need to extend the "Arrayy"-class and you need to set
     *                                             the $checkPropertiesMismatchInConstructor class property
     *                                             to
     *                                             true, otherwise this option didn't not work anyway.
     *                                             </p>
     *
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    public function __construct(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        $data = $this->fallbackForArray($data);

        // used only for serialize + unserialize, all other methods are overwritten
        /**
         * @psalm-suppress InvalidArgument - why?
         */
        parent::__construct([], 0, $iteratorClass);

        $this->setInitialValuesAndProperties($data, $checkPropertiesInConstructor);

        $this->setIteratorClass($iteratorClass);
    }

    /**
     * @return void
     */
    public function __clone()
    {
        if (!\is_array($this->properties)) {
            $this->properties = clone $this->properties;
        }

        if ($this->generator !== null) {
            $this->generator = clone $this->generator;
        }
    }

    /**
     * Call object as function.
     *
     * @param mixed $key
     *
     * @return mixed
     *
     * @phpstan-param TKey $key
     * @phpstan-return false|T|array<TKey,T>
     */
    public function __invoke($key = null)
    {
        if ($key !== null) {
            $this->generatorToArray();

            return $this->array[$key] ?? false;
        }

        /** @var array<TKey,T> $return */
        $return = $this->toArray();

        return $return;
    }

    /**
     * Whether or not an element exists by key.
     *
     * @param mixed $key
     *
     * @return bool
     *              <p>True is the key/index exists, otherwise false.</p>
     *
     * @phpstan-param TKey $key
     */
    public function __isset($key): bool
    {
        return $this->offsetExists($key);
    }

    /**
     * Assigns a value to the specified element.
     *
     * @param mixed $key
     * @param mixed $value
     *
     * @return void
     *
     * @phpstan-param TKey $key
     * @phpstan-param T $value
     */
    public function __set($key, $value)
    {
        $this->internalSet($key, $value);
    }

    /**
     * magic to string
     *
     * @return string
     */
    public function __toString(): string
    {
        return $this->toString();
    }

    /**
     * Unset element by key.
     *
     * @param mixed $key
     *
     * @phpstan-param TKey $key
     */
    public function __unset($key)
    {
        $this->internalRemove($key);
    }

    /**
     * Get a value by key.
     *
     * @param mixed $key
     *
     * @return mixed
     *               <p>Get a Value from the current array.</p>
     *
     * @phpstan-param TKey $key
     * @phpstan-return null|self<array-key,T>|T
     */
    public function &__get($key)
    {
        $return = $this->get($key, null, null, true);

        if (\is_array($return) === true) {
            $return = static::create(
                [],
                $this->iteratorClass,
                false
            )->createByReference($return);
        }

        return $return;
    }

    /**
     * Add new values (optional using dot-notation).
     *
     * @param mixed           $value
     * @param int|string|null $key
     *
     * @return static
     *                <p>(Immutable) Return this Arrayy object, with the appended values.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey $key
     * @phpstan-return static<TKey,T>
     *
     * @psalm-mutation-free
     */
    public function add($value, $key = null)
    {
        if ($key !== null) {
            $get = $this->get($key);
            if ($get !== null) {
                $value = \array_merge_recursive(
                    !$get instanceof self ? [$get] : $get->getArray(),
                    !\is_array($value) ? [$value] : $value
                );
            }

            $this->internalSet($key, $value);

            return $this;
        }

        return $this->append($value);
    }

    /**
     * Append a (key) + value to the current array.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř'])->append('foo'); // Arrayy['fòô' => 'bàř', 0 => 'foo']
     * </code>
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with the appended values.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey|null $key
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function append($value, $key = null): self
    {
        $this->generatorToArray();

        if ($this->properties !== []) {
            $this->checkType($key, $value);
        }

        if ($key !== null) {
            if (
                isset($this->array[$key])
                &&
                \is_array($this->array[$key])
            ) {
                $this->array[$key][] = $value;
            } else {
                $this->array[$key] = $value;
            }
        } else {
            $this->array[] = $value;
        }

        return $this;
    }

    /**
     * Append a (key) + value to the current array.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř'])->appendImmutable('foo')->getArray(); // ['fòô' => 'bàř', 0 => 'foo']
     * </code>
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object, with the appended values.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey $key
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function appendImmutable($value, $key = null): self
    {
        /**
         * @phpstan-return \Generator<TKey,T> $generator
         */
        $generator = function () use ($key, $value): \Generator {
            if ($this->properties !== []) {
                $this->checkType($key, $value);
            }

            foreach ($this->getGenerator() as $keyOld => $itemOld) {
                yield $keyOld => $itemOld;
            }

            if ($key !== null) {
                yield $key => $value;
            } else {
                yield $value;
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Sort the entries by value.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function asort(int $sort_flags = 0): self
    {
        $this->generatorToArray();

        \asort($this->array, $sort_flags);

        return $this;
    }

    /**
     * Sort the entries by value.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function asortImmutable(int $sort_flags = 0): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->asort($sort_flags);

        return $that;
    }

    /**
     * Counts all elements in an array, or something in an object.
     *
     * EXAMPLE: <code>
     * a([-9, -8, -7, 1.32])->count(); // 4
     * </code>
     *
     * <p>
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
     * implemented and used in PHP.
     * </p>
     *
     * @see http://php.net/manual/en/function.count.php
     *
     * @param int $mode [optional] If the optional mode parameter is set to
     *                  COUNT_RECURSIVE (or 1), count
     *                  will recursively count the array. This is particularly useful for
     *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
     *
     * @return int
     *             <p>
     *             The number of elements in var, which is
     *             typically an array, since anything else will have one
     *             element.
     *             </p>
     *             <p>
     *             If var is not an array or an object with
     *             implemented Countable interface,
     *             1 will be returned.
     *             There is one exception, if var is &null;,
     *             0 will be returned.
     *             </p>
     *             <p>
     *             Caution: count may return 0 for a variable that isn't set,
     *             but it may also return 0 for a variable that has been initialized with an
     *             empty array. Use isset to test if a variable is set.
     *             </p>
     * @psalm-mutation-free
     */
    public function count(int $mode = \COUNT_NORMAL): int
    {
        if (
            $this->generator
            &&
            $mode === \COUNT_NORMAL
        ) {
            return \iterator_count($this->generator);
        }

        return \count($this->toArray(), $mode);
    }

    /**
     * Exchange the array for another one.
     *
     * @param array|mixed|static $data
     *
     * 1. use the current array, if it's a array
     * 2. fallback to empty array, if there is nothing
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
     * 5. call "__toArray()" on object, if the method exists
     * 6. cast a string or object with "__toString()" into an array
     * 7. throw a "InvalidArgumentException"-Exception
     *
     * @return array
     *
     * @phpstan-param  T|array<TKey,T>|self<TKey,T> $data
     * @phpstan-return array<TKey,T>
     */
    public function exchangeArray($data): array
    {
        /** @phpstan-var array<TKey,T> array */
        $array = $this->fallbackForArray($data);

        $this->array = $array;
        $this->generator = null;

        return $this->array;
    }

    /**
     * Creates a copy of the ArrayyObject.
     *
     * @return array
     *
     * @phpstan-return array<int|string|TKey,T>
     */
    public function getArrayCopy(): array
    {
        $this->generatorToArray();

        return $this->array;
    }

    /**
     * Returns a new iterator, thus implementing the \Iterator interface.
     *
     * EXAMPLE: <code>
     * a(['foo', 'bar'])->getIterator(); // ArrayyIterator['foo', 'bar']
     * </code>
     *
     * @return \Iterator<mixed, mixed>
     *                          <p>An iterator for the values in the array.</p>
     * @phpstan-return \Iterator<TKey, T>
     */
    public function getIterator(): \Iterator
    {
        if ($this->generator instanceof ArrayyRewindableGenerator) {
            $generator = clone $this->generator;

            /** @phpstan-var \Arrayy\ArrayyRewindableGenerator<TKey,T> */
            $generatorTmp = new ArrayyRewindableExtendedGenerator(
                static function () use ($generator): \Generator {
                    yield from $generator;
                },
                null,
                static::class
            );

            $this->generator = $generatorTmp;

            return $this->generator;
        }

        $iterator = $this->getIteratorClass();

        if ($iterator === ArrayyIterator::class) {
            return new $iterator($this->toArray(), 0, static::class);
        }

        $return = new $iterator($this->toArray());
        \assert($return instanceof \Iterator);

        return $return;
    }

    /**
     * Gets the iterator classname for the ArrayObject.
     *
     * @return string
     *
     * @phpstan-return class-string
     */
    public function getIteratorClass(): string
    {
        return $this->iteratorClass;
    }

    /**
     * Sort the entries by key.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function ksort(int $sort_flags = 0): self
    {
        $this->generatorToArray();

        \ksort($this->array, $sort_flags);

        return $this;
    }

    /**
     * Sort the entries by key.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function ksortImmutable(int $sort_flags = 0): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->ksort($sort_flags);

        return $that;
    }

    /**
     * Sort an array using a case insensitive "natural order" algorithm.
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function natcasesort(): self
    {
        $this->generatorToArray();

        \natcasesort($this->array);

        return $this;
    }

    /**
     * Sort an array using a case insensitive "natural order" algorithm.
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function natcasesortImmutable(): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->natcasesort();

        return $that;
    }

    /**
     * Sort entries using a "natural order" algorithm.
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function natsort(): self
    {
        $this->generatorToArray();

        \natsort($this->array);

        return $this;
    }

    /**
     * Sort entries using a "natural order" algorithm.
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function natsortImmutable(): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->natsort();

        return $that;
    }

    /**
     * Whether or not an offset exists.
     *
     * @param bool|int|string $offset
     *
     * @return bool
     *
     * @psalm-mutation-free
     */
    #[\ReturnTypeWillChange]
    public function offsetExists($offset): bool
    {
        // php cast "bool"-index into "int"-index
        if ((bool) $offset === $offset) {
            $offset = (int) $offset;
        }
        \assert(\is_int($offset) || \is_string($offset));

        $offsetExists = $this->keyExists($offset);
        if ($offsetExists === true) {
            return true;
        }

        /**
         * https://github.com/vimeo/psalm/issues/2536
         *
         * @psalm-suppress PossiblyInvalidArgument
         * @psalm-suppress InvalidScalarArgument
         */
        if (
            $this->pathSeparator
            &&
            (string) $offset === $offset
            &&
            \strpos($offset, $this->pathSeparator) !== false
        ) {
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
            if ($explodedPath !== false) {
                /** @var string $lastOffset - helper for phpstan */
                $lastOffset = \array_pop($explodedPath);
                $containerPath = \implode($this->pathSeparator, $explodedPath);

                /**
                 * @psalm-suppress MissingClosureReturnType
                 * @psalm-suppress MissingClosureParamType
                 */
                $this->callAtPath(
                    $containerPath,
                    static function ($container) use ($lastOffset, &$offsetExists) {
                        $offsetExists = \array_key_exists($lastOffset, $container);
                    }
                );
            }
        }

        return $offsetExists;
    }

    /**
     * Returns the value at specified offset.
     *
     * @param int|string $offset
     *
     * @return mixed
     *               <p>Will return null if the offset did not exists.</p>
     *
     * @phpstan-param TKey $offset
     */
    #[\ReturnTypeWillChange]
    public function &offsetGet($offset)
    {
        // init
        $value = null;

        if ($this->offsetExists($offset)) {
            $value = &$this->__get($offset);
        }

        return $value;
    }

    /**
     * Assigns a value to the specified offset + check the type.
     *
     * @param int|string|null $offset
     * @param mixed           $value
     *
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($offset, $value)
    {
        $this->generatorToArray();

        if ($offset === null) {
            if ($this->properties !== []) {
                $this->checkType(null, $value);
            }

            $this->array[] = $value;
        } else {
            $this->internalSet(
                $offset,
                $value,
                true
            );
        }
    }

    /**
     * Unset an offset.
     *
     * @param int|string $offset
     *
     * @return void
     *              <p>(Mutable) Return nothing.</p>
     */
    #[\ReturnTypeWillChange]
    public function offsetUnset($offset)
    {
        $this->generatorToArray();

        if ($this->array === []) {
            return;
        }

        if ($this->keyExists($offset)) {
            unset($this->array[$offset]);

            return;
        }

        /**
         * https://github.com/vimeo/psalm/issues/2536
         *
         * @psalm-suppress PossiblyInvalidArgument
         * @psalm-suppress InvalidScalarArgument
         */
        if (
            $this->pathSeparator
            &&
            (string) $offset === $offset
            &&
            \strpos($offset, $this->pathSeparator) !== false
        ) {
            $path = \explode($this->pathSeparator, (string) $offset);

            if ($path !== false) {
                $pathToUnset = \array_pop($path);

                /**
                 * @psalm-suppress MissingClosureReturnType
                 * @psalm-suppress MissingClosureParamType
                 */
                $this->callAtPath(
                    \implode($this->pathSeparator, $path),
                    static function (&$offset) use ($pathToUnset) {
                        if (\is_array($offset)) {
                            unset($offset[$pathToUnset]);
                        } else {
                            $offset = null;
                        }
                    }
                );
            }
        }

        unset($this->array[$offset]);
    }

    /**
     * Serialize the current "Arrayy"-object.
     *
     * EXAMPLE: <code>
     * a([1, 4, 7])->serialize();
     * </code>
     *
     * @return string
     */
    public function serialize(): string
    {
        $this->generatorToArray();

        if (\PHP_VERSION_ID < 70400) {
            return parent::serialize();
        }

        return \serialize($this);
    }

    /**
     * Sets the iterator classname for the current "Arrayy"-object.
     *
     * @param string $iteratorClass
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     *
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    #[\ReturnTypeWillChange]
    public function setIteratorClass($iteratorClass)
    {
        if (\class_exists($iteratorClass)) {
            $this->iteratorClass = $iteratorClass;

            return;
        }

        if (\strpos($iteratorClass, '\\') === 0) {
            /** @var class-string<\Arrayy\ArrayyIterator<TKey,T>> $iteratorClass */
            $iteratorClass = '\\' . $iteratorClass;
            if (\class_exists($iteratorClass)) {
                /**
                 * @psalm-suppress PropertyTypeCoercion
                 */
                $this->iteratorClass = $iteratorClass;

                return;
            }
        }

        throw new \InvalidArgumentException('The iterator class does not exist: ' . $iteratorClass);
    }

    /**
     * Sort the entries with a user-defined comparison function and maintain key association.
     *
     * @param callable $callable
     *
     *@throws \InvalidArgumentException
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(T,T):int $callable
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function uasort($callable): self
    {
        if (!\is_callable($callable)) {
            throw new \InvalidArgumentException('Passed function must be callable');
        }

        $this->generatorToArray();

        \uasort($this->array, $callable);

        return $this;
    }

    /**
     * Sort the entries with a user-defined comparison function and maintain key association.
     *
     * @param callable $callable
     *
     *@throws \InvalidArgumentException
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(T,T):int $callable
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function uasortImmutable($callable): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->uasort($callable);

        return $that;
    }

    /**
     * Sort the entries by keys using a user-defined comparison function.
     *
     * @param callable $callable
     *
     * @throws \InvalidArgumentException
     *
     * @return static
     *                <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(TKey,TKey):int $callable
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function uksort($callable): self
    {
        return $this->customSortKeys($callable);
    }

    /**
     * Sort the entries by keys using a user-defined comparison function.
     *
     * @param callable $callable
     *
     * @throws \InvalidArgumentException
     *
     * @return static
     *                <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(TKey,TKey):int $callable
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function uksortImmutable($callable): self
    {
        return $this->customSortKeysImmutable($callable);
    }

    /**
     * Unserialize an string and return the instance of the "Arrayy"-class.
     *
     * EXAMPLE: <code>
     * $serialized = a([1, 4, 7])->serialize();
     * a()->unserialize($serialized);
     * </code>
     *
     * @param string $string
     *
     * @return $this
     *
     * @phpstan-return static<TKey,T>
     */
    #[\ReturnTypeWillChange]
    public function unserialize($string): self
    {
        if (\PHP_VERSION_ID < 70400) {
            parent::unserialize($string);

            return $this;
        }

        return \unserialize($string, ['allowed_classes' => [__CLASS__, TypeCheckPhpDoc::class]]);
    }

    /**
     * Append a (key) + values to the current array.
     *
     * EXAMPLE: <code>
     * a(['fòô' => ['bàř']])->appendArrayValues(['foo1', 'foo2'], 'fòô'); // Arrayy['fòô' => ['bàř', 'foo1', 'foo2']]
     * </code>
     *
     * @param array $values
     * @param mixed $key
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with the appended values.</p>
     *
     * @phpstan-param  array<T> $values
     * @phpstan-param  TKey|null $key
     * @phpstan-return static<TKey,T>
     */
    public function appendArrayValues(array $values, $key = null)
    {
        $this->generatorToArray();

        if ($key !== null) {
            if (
                isset($this->array[$key])
                &&
                \is_array($this->array[$key])
            ) {
                foreach ($values as $value) {
                    $this->array[$key][] = $value;
                }
            } else {
                foreach ($values as $value) {
                    $this->array[$key] = $value;
                }
            }
        } else {
            foreach ($values as $value) {
                $this->array[] = $value;
            }
        }

        return $this;
    }

    /**
     * Add a suffix to each key.
     *
     * @param int|string $prefix
     *
     * @return static
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function appendToEachKey($prefix): self
    {
        // init
        $result = [];

        foreach ($this->getGenerator() as $key => $item) {
            if ($item instanceof self) {
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
            } elseif (\is_array($item)) {
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
                    ->appendToEachKey($prefix)
                    ->toArray();
            } else {
                $result[$prefix . $key] = $item;
            }
        }

        return self::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Add a prefix to each value.
     *
     * @param float|int|string $prefix
     *
     * @return static
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function appendToEachValue($prefix): self
    {
        // init
        $result = [];

        foreach ($this->getGenerator() as $key => $item) {
            if ($item instanceof self) {
                $result[$key] = $item->appendToEachValue($prefix);
            } elseif (\is_array($item)) {
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
            } elseif (\is_object($item) === true) {
                $result[$key] = $item;
            } else {
                $result[$key] = $prefix . $item;
            }
        }

        return self::create($result, $this->iteratorClass, false);
    }

    /**
     * Sort an array in reverse order and maintain index association.
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function arsort(): self
    {
        $this->generatorToArray();

        \arsort($this->array);

        return $this;
    }

    /**
     * Sort an array in reverse order and maintain index association.
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function arsortImmutable(): self
    {
        $that = clone $this;

        $that->generatorToArray();

        \arsort($that->array);

        return $that;
    }

    /**
     * Iterate over the current array and execute a callback for each loop.
     *
     * EXAMPLE: <code>
     * $result = A::create();
     * $closure = function ($value, $key) use ($result) {
     *     $result[$key] = ':' . $value . ':';
     * };
     * a(['foo', 'bar' => 'bis'])->at($closure); // Arrayy[':foo:', 'bar' => ':bis:']
     * </code>
     *
     * @param \Closure $closure
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param \Closure(T,TKey):mixed $closure <p>INFO: \Closure result is not used, but void is not supported in PHP 7.0</p>
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function at(\Closure $closure): self
    {
        $that = clone $this;

        foreach ($that->getGenerator() as $key => $value) {
            $closure($value, $key);
        }

        return static::create(
            $that->toArray(),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Returns the average value of the current array.
     *
     * EXAMPLE: <code>
     * a([-9, -8, -7, 1.32])->average(2); // -5.67
     * </code>
     *
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
     *
     * @return float|int
     *                   <p>The average value.</p>
     * @psalm-mutation-free
     */
    public function average($decimals = 0)
    {
        $count = \count($this->toArray(), \COUNT_NORMAL);

        if (!$count) {
            return 0;
        }

        if ((int) $decimals !== $decimals) {
            $decimals = 0;
        }

        return \round(\array_sum($this->toArray()) / $count, $decimals);
    }

    /**
     * Changes all keys in an array.
     *
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
     *                  or <strong>CASE_LOWER</strong> (default)</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function changeKeyCase(int $case = \CASE_LOWER): self
    {
        if (
            $case !== \CASE_LOWER
            &&
            $case !== \CASE_UPPER
        ) {
            $case = \CASE_LOWER;
        }

        $return = [];
        foreach ($this->getGenerator() as $key => $value) {
            if ($case === \CASE_LOWER) {
                $key = \mb_strtolower((string) $key);
            } else {
                $key = \mb_strtoupper((string) $key);
            }

            $return[$key] = $value;
        }

        return static::create(
            $return,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Change the path separator of the array wrapper.
     *
     * By default, the separator is: "."
     *
     * @param non-empty-string $separator <p>Separator to set.</p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function changeSeparator($separator): self
    {
        $this->pathSeparator = $separator;

        return $this;
    }

    /**
     * Create a chunked version of the current array.
     *
     * EXAMPLE: <code>
     * a([-9, -8, -7, 1.32])->chunk(2); // Arrayy[[-9, -8], [-7, 1.32]]
     * </code>
     *
     * @param int  $size         <p>Size of each chunk.</p>
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
     *
     * @return static|static[]
     *                <p>(Immutable) A new array of chunks from the original array.</p>
     *
     * @phpstan-return static<int, static<array-key,T>>
     * @psalm-mutation-free
     */
    public function chunk($size, $preserveKeys = false): self
    {
        if ($preserveKeys) {
            $generator = function () use ($size) {
                $values = [];
                $tmpCounter = 0;
                foreach ($this->getGenerator() as $key => $value) {
                    ++$tmpCounter;

                    $values[$key] = $value;
                    if ($tmpCounter === $size) {
                        yield $values;

                        $values = [];
                        $tmpCounter = 0;
                    }
                }

                if ($values !== []) {
                    yield $values;
                }
            };
        } else {
            $generator = function () use ($size) {
                $values = [];
                $tmpCounter = 0;
                foreach ($this->getGenerator() as $value) {
                    ++$tmpCounter;

                    $values[] = $value;
                    if ($tmpCounter === $size) {
                        yield $values;

                        $values = [];
                        $tmpCounter = 0;
                    }
                }

                if ($values !== []) {
                    yield $values;
                }
            };
        }

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Clean all falsy values from the current array.
     *
     * EXAMPLE: <code>
     * a([-8 => -9, 1, 2 => false])->clean(); // Arrayy[-8 => -9, 1]
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function clean(): self
    {
        return $this->filter(
            static function ($value) {
                return (bool) $value;
            }
        );
    }

    /**
     * WARNING!!! -> Clear the current full array or a $key of it.
     *
     * EXAMPLE: <code>
     * a([-8 => -9, 1, 2 => false])->clear(); // Arrayy[]
     * </code>
     *
     * @param int|int[]|string|string[]|null $key
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with an empty array.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function clear($key = null): self
    {
        if ($key !== null) {
            if (\is_array($key)) {
                foreach ($key as $keyTmp) {
                    $this->offsetUnset($keyTmp);
                }
            } else {
                $this->offsetUnset($key);
            }

            return $this;
        }

        $this->array = [];
        $this->generator = null;

        return $this;
    }

    /**
     * Check if an item is in the current array.
     *
     * EXAMPLE: <code>
     * a([1, true])->containsOnly(true); // false
     * </code>
     *
     * @param float|int|string $value
     * @param bool             $recursive
     * @param bool             $strict
     *
     * @return bool
     * @psalm-mutation-free
     */
    public function containsOnly($value, bool $recursive = false, bool $strict = true): bool
    {
        if ($recursive === true) {
            return $this->in_array_recursive($value, $this->toArray(), $strict);
        }

        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        $tmpCount = 0;
        foreach ($this->getGeneratorByReference() as &$valueFromArray) {
            $tmpCount++;

            if ($strict) {
                if ($value !== $valueFromArray) {
                    return false;
                }
            } else {
                /** @noinspection NestedPositiveIfStatementsInspection */
                if ($value != $valueFromArray) {
                    return false;
                }
            }
        }

        return $tmpCount !== 0;
    }

    /**
     * Check if an item is in the current array.
     *
     * EXAMPLE: <code>
     * a([1, true])->contains(true); // true
     * </code>
     *
     * @param float|int|string $value
     * @param bool             $recursive
     * @param bool             $strict
     *
     * @return bool
     * @psalm-mutation-free
     */
    public function contains($value, bool $recursive = false, bool $strict = true): bool
    {
        if ($recursive === true) {
            return $this->in_array_recursive($value, $this->toArray(), $strict);
        }

        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->getGeneratorByReference() as &$valueFromArray) {
            if ($strict) {
                if ($value === $valueFromArray) {
                    return true;
                }
            } else {
                /** @noinspection NestedPositiveIfStatementsInspection */
                if ($value == $valueFromArray) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Check if an (case-insensitive) string is in the current array.
     *
     * EXAMPLE: <code>
     * a(['E', 'é'])->containsCaseInsensitive('É'); // true
     * </code>
     *
     * @param mixed $value
     * @param bool  $recursive
     *
     * @return bool
     * @psalm-mutation-free
     *
     * @psalm-suppress InvalidCast - hack for int|float|bool support
     */
    public function containsCaseInsensitive($value, $recursive = false): bool
    {
        if ($value === null) {
            return false;
        }

        if ($recursive === true) {
            /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
            foreach ($this->getGeneratorByReference() as &$valueTmp) {
                if (\is_array($valueTmp)) {
                    $return = (new self($valueTmp))->containsCaseInsensitive($value, $recursive);
                    if ($return === true) {
                        return $return;
                    }
                } elseif (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
                    return true;
                }
            }

            return false;
        }

        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->getGeneratorByReference() as &$valueTmp) {
            if (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if the given key/index exists in the array.
     *
     * EXAMPLE: <code>
     * a([1 => true])->containsKey(1); // true
     * </code>
     *
     * @param int|string $key <p>key/index to search for</p>
     *
     * @return bool
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
     *
     * @psalm-mutation-free
     */
    public function containsKey($key): bool
    {
        return $this->offsetExists($key);
    }

    /**
     * Check if all given needles are present in the array as key/index.
     *
     * EXAMPLE: <code>
     * a([1 => true])->containsKeys(array(1 => 0)); // true
     * </code>
     *
     * @param array $needles   <p>The keys you are searching for.</p>
     * @param bool  $recursive
     *
     * @return bool
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
     *
     * @phpstan-param array<TKey> $needles
     * @psalm-mutation-free
     */
    public function containsKeys(array $needles, bool $recursive = false): bool
    {
        if ($recursive === true) {
            return
                \count(
                    \array_intersect(
                        $needles,
                        $this->keys(true)->toArray()
                    ),
                    \COUNT_RECURSIVE
                )
                ===
                \count(
                    $needles,
                    \COUNT_RECURSIVE
                );
        }

        return \count(
            \array_intersect($needles, $this->keys()->toArray()),
            \COUNT_NORMAL
        )
                ===
                \count(
                    $needles,
                    \COUNT_NORMAL
                );
    }

    /**
     * Check if all given needles are present in the array as key/index.
     *
     * @param array $needles <p>The keys you are searching for.</p>
     *
     * @return bool
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
     *
     * @phpstan-param array<TKey> $needles
     * @psalm-mutation-free
     */
    public function containsKeysRecursive(array $needles): bool
    {
        return $this->containsKeys($needles, true);
    }

    /**
     * alias: for "Arrayy->contains()"
     *
     * @param float|int|string $value
     *
     * @return bool
     *
     * @see Arrayy::contains()
     * @psalm-mutation-free
     */
    public function containsValue($value): bool
    {
        return $this->contains($value);
    }

    /**
     * alias: for "Arrayy->contains($value, true)"
     *
     * @param float|int|string $value
     *
     * @return bool
     *
     * @see Arrayy::contains()
     * @psalm-mutation-free
     */
    public function containsValueRecursive($value): bool
    {
        return $this->contains($value, true);
    }

    /**
     * Check if all given needles are present in the array.
     *
     * EXAMPLE: <code>
     * a([1, true])->containsValues(array(1, true)); // true
     * </code>
     *
     * @param array $needles
     *
     * @return bool
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
     *
     * @phpstan-param array<T> $needles
     * @psalm-mutation-free
     */
    public function containsValues(array $needles): bool
    {
        return \count(
            \array_intersect(
                $needles,
                $this->toArray()
            ),
            \COUNT_NORMAL
        )
               ===
               \count(
                   $needles,
                   \COUNT_NORMAL
               );
    }

    /**
     * Counts all the values of an array
     *
     * @see          http://php.net/manual/en/function.array-count-values.php
     *
     * @return static
     *                <p>
     *                (Immutable)
     *                An associative Arrayy-object of values from input as
     *                keys and their count as value.
     *                </p>
     *
     * @phpstan-return static<array-key,int>
     * @psalm-mutation-free
     */
    public function countValues(): self
    {
        /** @phpstan-var static<array-key,int> $return - help for phpstan */
        $return = self::create(\array_count_values($this->toArray()), $this->iteratorClass);

        return $return;
    }

    /**
     * Creates an Arrayy object.
     *
     * @param mixed  $data
     * @param string $iteratorClass
     * @param bool   $checkPropertiesInConstructor
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public static function create(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        return new static(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    /**
     * Flatten an array with the given character as a key delimiter.
     *
     * EXAMPLE: <code>
     * $dot = a(['foo' => ['abc' => 'xyz', 'bar' => ['baz']]]);
     * $flatten = $dot->flatten();
     * $flatten['foo.abc']; // 'xyz'
     * $flatten['foo.bar.0']; // 'baz'
     * </code>
     *
     * @param string     $delimiter
     * @param string     $prepend
     * @param array|null $items
     *
     * @return array
     */
    public function flatten($delimiter = '.', $prepend = '', $items = null)
    {
        // init
        $flatten = [];

        if ($items === null) {
            $items = $this->getArray();
        }

        foreach ($items as $key => $value) {
            if (\is_array($value) && $value !== []) {
                $flatten[] = $this->flatten($delimiter, $prepend . $key . $delimiter, $value);
            } else {
                $flatten[] = [$prepend . $key => $value];
            }
        }

        if (\count($flatten) === 0) {
            return [];
        }

        return \array_merge_recursive([], ...$flatten);
    }

    /**
     * WARNING: Creates an Arrayy object by reference.
     *
     * @param array $array
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return $this<TKey,T>
     *
     * @internal this will not check any types because it's set directly as reference
     */
    public function createByReference(array &$array = []): self
    {
        $this->array = &$array;
        $this->generator = null;

        return $this;
    }

    /**
     * Create an new instance from a callable function which will return an Generator.
     *
     * @param callable $generatorFunction
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param callable():\Generator<TKey,T> $generatorFunction
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public static function createFromGeneratorFunction(callable $generatorFunction): self
    {
        return self::create($generatorFunction);
    }

    /**
     * Create an new instance filled with a copy of values from a "Generator"-object.
     *
     * @param \Generator $generator
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param \Generator<TKey,T> $generator
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public static function createFromGeneratorImmutable(\Generator $generator): self
    {
        return self::create(\iterator_to_array($generator, true));
    }

    /**
     * Create an new Arrayy object via JSON.
     *
     * @param string $json
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-return static<int|string,mixed>
     * @psalm-mutation-free
     */
    public static function createFromJson(string $json): self
    {
        return static::create(\json_decode($json, true));
    }

    /**
     * Create an new Arrayy object via JSON.
     *
     * @param array $array
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param array<TKey,T> $array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public static function createFromArray(array $array): self
    {
        return static::create($array);
    }

    /**
     * Create an new instance filled with values from an object that is iterable.
     *
     * @param \Traversable $object <p>iterable object</p>
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param \Traversable<array-key,T> $object
     * @phpstan-return static<array-key,T>
     * @psalm-mutation-free
     */
    public static function createFromObject(\Traversable $object): self
    {
        // init
        $arrayy = new static();

        if ($object instanceof self) {
            $objectArray = $object->getGenerator();
        } else {
            $objectArray = $object;
        }

        foreach ($objectArray as $key => $value) {
            /**
             * @psalm-suppress ImpureMethodCall - object is already re-created
             */
            $arrayy->internalSet($key, $value);
        }

        return $arrayy;
    }

    /**
     * Create an new instance filled with values from an object.
     *
     * @param object $object
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-return static<array-key,mixed>
     * @psalm-mutation-free
     */
    public static function createFromObjectVars($object): self
    {
        return self::create(self::objectToArray($object));
    }

    /**
     * Create an new Arrayy object via string.
     *
     * @param string                $str       <p>The input string.</p>
     * @param non-empty-string|null $delimiter <p>The boundary string.</p>
     * @param string|null           $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
     *                                         used.</p>
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-return static<int,string>
     * @psalm-mutation-free
     */
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
    {
        if ($regEx) {
            \preg_match_all($regEx, $str, $array);

            if (!empty($array)) {
                $array = $array[0];
            }
        } else {
            /** @noinspection NestedPositiveIfStatementsInspection */
            if ($delimiter !== null) {
                $array = \explode($delimiter, $str);
            } else {
                $array = [$str];
            }
        }

        // trim all string in the array
        /**
         * @psalm-suppress MissingClosureParamType
         */
        \array_walk(
            $array,
            static function (&$val) {
                if ((string) $val === $val) {
                    $val = \trim($val);
                }
            }
        );

        /** @var static<int,string> $return - help for phpstan */
        $return = static::create($array);

        return $return;
    }

    /**
     * Create an new instance filled with a copy of values from a "Traversable"-object.
     *
     * @param \Traversable $traversable
     * @param bool         $use_keys    [optional] <p>
     *                                  Whether to use the iterator element keys as index.
     *                                  </p>
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-param \Traversable<array-key|TKey,T> $traversable
     * @phpstan-return static<int|TKey,T>
     * @psalm-mutation-free
     */
    public static function createFromTraversableImmutable(\Traversable $traversable, bool $use_keys = true): self
    {
        return self::create(\iterator_to_array($traversable, $use_keys));
    }

    /**
     * Create an new instance containing a range of elements.
     *
     * @param float|int|string $low  <p>First value of the sequence.</p>
     * @param float|int|string $high <p>The sequence is ended upon reaching the end value.</p>
     * @param float|int        $step <p>Used as the increment between elements in the sequence.</p>
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
     *
     * @phpstan-return static<int,int|string>
     * @psalm-mutation-free
     */
    public static function createWithRange($low, $high, $step = 1): self
    {
        /** @phpstan-var static<int,int|string> $return - help for phpstan */
        $return = static::create(\range($low, $high, $step));

        return $return;
    }

    /**
     * Gets the element of the array at the current internal iterator position.
     *
     * @return false|mixed
     *
     * @phpstan-return false|T
     */
    public function current()
    {
        if ($this->generator) {
            return $this->generator->current();
        }

        return \current($this->array);
    }

    /**
     * Custom sort by index via "uksort".
     *
     * EXAMPLE: <code>
     * $callable = function ($a, $b) {
     *     if ($a == $b) {
     *         return 0;
     *     }
     *     return ($a > $b) ? 1 : -1;
     * };
     * $arrayy = a(['three' => 3, 'one' => 1, 'two' => 2]);
     * $resultArrayy = $arrayy->customSortKeys($callable); // Arrayy['one' => 1, 'three' => 3, 'two' => 2]
     * </code>
     *
     * @see          http://php.net/manual/en/function.uksort.php
     *
     * @param callable $callable
     *
     * @throws \InvalidArgumentException
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(TKey,TKey):int $callable
     * @phpstan-return static<TKey,T>
     */
    public function customSortKeys(callable $callable): self
    {
        $this->generatorToArray();

        \uksort($this->array, $callable);

        return $this;
    }

    /**
     * Custom sort by index via "uksort".
     *
     * @see          http://php.net/manual/en/function.uksort.php
     *
     * @param callable $callable
     *
     * @throws \InvalidArgumentException
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(TKey,TKey):int $callable
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function customSortKeysImmutable(callable $callable): self
    {
        $that = clone $this;

        $that->generatorToArray();

        /**
         * @psalm-suppress ImpureFunctionCall - object is already cloned
         */
        \uksort($that->array, $callable);

        return $that;
    }

    /**
     * Custom sort by value via "usort".
     *
     * EXAMPLE: <code>
     * $callable = function ($a, $b) {
     *     if ($a == $b) {
     *         return 0;
     *     }
     *     return ($a > $b) ? 1 : -1;
     * };
     * $arrayy = a(['three' => 3, 'one' => 1, 'two' => 2]);
     * $resultArrayy = $arrayy->customSortValues($callable); // Arrayy[1, 2, 3]
     * </code>
     *
     * @see          http://php.net/manual/en/function.usort.php
     *
     * @param callable $callable
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(T,T):int $callable
     * @phpstan-return static<int,T>
     */
    public function customSortValues(callable $callable): self
    {
        $this->generatorToArray();

        \usort($this->array, $callable);

        return $this;
    }

    /**
     * Custom sort by value via "usort".
     *
     * @see          http://php.net/manual/en/function.usort.php
     *
     * @param callable $callable
     *
     * @throws \InvalidArgumentException
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  callable(T,T):int $callable
     * @phpstan-return static<int,T>
     * @psalm-mutation-free
     */
    public function customSortValuesImmutable($callable): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->customSortValues($callable);

        return $that;
    }

    /**
     * Delete the given key or keys.
     *
     * @param int|int[]|string|string[] $keyOrKeys
     *
     * @return void
     */
    public function delete($keyOrKeys)
    {
        $keyOrKeys = (array) $keyOrKeys;

        foreach ($keyOrKeys as $key) {
            $this->offsetUnset($key);
        }
    }

    /**
     * Return elements where the values that are only in the current array.
     *
     * EXAMPLE: <code>
     * a([1 => 1, 2 => 2])->diff([1 => 1]); // Arrayy[2 => 2]
     * </code>
     *
     * @param array ...$array
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> ...$array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function diff(array ...$array): self
    {
        if (\count($array) > 1) {
            $array = \array_merge([], ...$array);
        } else {
            $array = $array[0];
        }

        $generator = function () use ($array): \Generator {
            foreach ($this->getGenerator() as $key => $value) {
                if (\in_array($value, $array, true) === false) {
                    yield $key => $value;
                }
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return elements where the keys are only in the current array.
     *
     * @param array ...$array
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> ...$array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function diffKey(array ...$array): self
    {
        if (\count($array) > 1) {
            $array = \array_replace([], ...$array);
        } else {
            $array = $array[0];
        }

        $generator = function () use ($array): \Generator {
            foreach ($this->getGenerator() as $key => $value) {
                if (\array_key_exists($key, $array) === false) {
                    yield $key => $value;
                }
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return elements where the values and keys are only in the current array.
     *
     * @param array ...$array
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function diffKeyAndValue(array ...$array): self
    {
        if (\count($array) > 1) {
            $array = \array_merge([], ...$array);
        } else {
            $array = $array[0];
        }

        $generator = function () use ($array): \Generator {
            foreach ($this->getGenerator() as $key => $value) {
                $isset = isset($array[$key]);

                if (
                    !$isset
                    ||
                    $array[$key] !== $value
                ) {
                    yield $key => $value;
                }
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return elements where the values are only in the current multi-dimensional array.
     *
     * EXAMPLE: <code>
     * a([1 => [1 => 1], 2 => [2 => 2]])->diffRecursive([1 => [1 => 1]]); // Arrayy[2 => [2 => 2]]
     * </code>
     *
     * @param array                 $array
     * @param array|\Generator|null $helperVariableForRecursion <p>(only for internal usage)</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-param  null|array<TKey,T>|\Generator<TKey,T> $helperVariableForRecursion
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
    {
        // init
        $result = [];

        if (
            $helperVariableForRecursion !== null
            &&
            \is_array($helperVariableForRecursion)
        ) {
            $arrayForTheLoop = $helperVariableForRecursion;
        } else {
            $arrayForTheLoop = $this->getGenerator();
        }

        foreach ($arrayForTheLoop as $key => $value) {
            if ($value instanceof self) {
                $value = $value->toArray();
            }

            if (\array_key_exists($key, $array)) {
                if ($value !== $array[$key]) {
                    $result[$key] = $value;
                }
            } else {
                $result[$key] = $value;
            }
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return elements where the values that are only in the new $array.
     *
     * EXAMPLE: <code>
     * a([1 => 1])->diffReverse([1 => 1, 2 => 2]); // Arrayy[2 => 2]
     * </code>
     *
     * @param array $array
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function diffReverse(array $array = []): self
    {
        return static::create(
            \array_diff($array, $this->toArray()),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Divide an array into two arrays. One with keys and the other with values.
     *
     * EXAMPLE: <code>
     * a(['a' => 1, 'b' => ''])->divide(); // Arrayy[Arrayy['a', 'b'], Arrayy[1, '']]
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function divide(): self
    {
        return static::create(
            [
                $this->keys(),
                $this->values(),
            ],
            $this->iteratorClass,
            false
        );
    }

    /**
     * Iterate over the current array and modify the array's value.
     *
     * EXAMPLE: <code>
     * $result = A::create();
     * $closure = function ($value) {
     *     return ':' . $value . ':';
     * };
     * a(['foo', 'bar' => 'bis'])->each($closure); // Arrayy[':foo:', 'bar' => ':bis:']
     * </code>
     *
     * @param \Closure $closure
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param \Closure(T,?TKey):T $closure
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function each(\Closure $closure): self
    {
        // init
        $array = [];

        foreach ($this->getGenerator() as $key => $value) {
            $array[$key] = $closure($value, $key);
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Sets the internal iterator to the last element in the array and returns this element.
     *
     * @return false|mixed
     *
     * @phpstan-return T|false
     */
    public function end()
    {
        if ($this->generator) {
            $count = $this->count();
            if ($count === 0) {
                return false;
            }

            $counter = 0;
            /** @noinspection PhpUnusedLocalVariableInspection */
            foreach ($this->getIterator() as $item) {
                if (++$counter === $count - 1) {
                    break;
                }
            }
        }

        return \end($this->array);
    }

    /**
     * Check if a value is in the current array using a closure.
     *
     * EXAMPLE: <code>
     * $callable = function ($value, $key) {
     *     return 2 === $key and 'two' === $value;
     * };
     * a(['foo', 2 => 'two'])->exists($callable); // true
     * </code>
     *
     * @param \Closure $closure
     *
     * @return bool
     *              <p>Returns true if the given value is found, false otherwise.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function exists(\Closure $closure): bool
    {
        // init
        $isExists = false;

        foreach ($this->getGenerator() as $key => $value) {
            if ($closure($value, $key)) {
                $isExists = true;

                break;
            }
        }

        return $isExists;
    }

    /**
     * Fill the array until "$num" with "$default" values.
     *
     * EXAMPLE: <code>
     * a(['bar'])->fillWithDefaults(3, 'foo'); // Arrayy['bar', 'foo', 'foo']
     * </code>
     *
     * @param int   $num
     * @param mixed $default
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param T $default
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function fillWithDefaults(int $num, $default = null): self
    {
        if ($num < 0) {
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
        }

        $this->generatorToArray();

        $tmpArray = $this->array;

        $count = \count($tmpArray);

        while ($count < $num) {
            $tmpArray[] = $default;
            ++$count;
        }

        return static::create(
            $tmpArray,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Find all items in an array that pass the truth test.
     *
     * EXAMPLE: <code>
     * $closure = function ($value) {
     *     return $value % 2 !== 0;
     * }
     * a([1, 2, 3, 4])->filter($closure); // Arrayy[0 => 1, 2 => 3]
     * </code>
     *
     * @param \Closure|null $closure [optional] <p>
     *                               The callback function to use
     *                               </p>
     *                               <p>
     *                               If no callback is supplied, all entries of
     *                               input equal to false (see
     *                               converting to
     *                               boolean) will be removed.
     *                               </p>
     * @param int           $flag    [optional] <p>
     *                               Flag determining what arguments are sent to <i>callback</i>:
     *                               </p>
     *                               <ul>
     *                               <li>
     *                               <b>ARRAY_FILTER_USE_KEY</b> (1) - pass key as the only argument
     *                               to <i>callback</i> instead of the value
     *                               </li>
     *                               <li>
     *                               <b>ARRAY_FILTER_USE_BOTH</b> (2) - pass both value and key as
     *                               arguments to <i>callback</i> instead of the value
     *                               </li>
     *                               </ul>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param null|(\Closure(T,TKey=):bool)|(\Closure(T):bool)|(\Closure(TKey):bool) $closure
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH)
    {
        if (!$closure) {
            return $this->clean();
        }

        if ($flag === \ARRAY_FILTER_USE_KEY) {
            $generator = function () use ($closure) {
                foreach ($this->getGenerator() as $key => $value) {
                    if ($closure($key) === true) {
                        yield $key => $value;
                    }
                }
            };
        } elseif ($flag === \ARRAY_FILTER_USE_BOTH) {
            /** @noinspection PhpSillyAssignmentInspection - hack for phpstan - https://github.com/phpstan/phpstan/issues/4192 */
            /** @phpstan-var \Closure(T,TKey):bool $closure */
            $closure = $closure;

            $generator = function () use ($closure) {
                foreach ($this->getGenerator() as $key => $value) {
                    if ($closure($value, $key) === true) {
                        yield $key => $value;
                    }
                }
            };
        } else {
            $generator = function () use ($closure) {
                foreach ($this->getGenerator() as $key => $value) {
                    if ($closure($value) === true) {
                        yield $key => $value;
                    }
                }
            };
        }

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
     * property within that.
     *
     * @param string      $property
     * @param mixed       $value
     * @param string|null $comparisonOp
     *                                  <p>
     *                                  'eq' (equals),<br />
     *                                  'gt' (greater),<br />
     *                                  'gte' || 'ge' (greater or equals),<br />
     *                                  'lt' (less),<br />
     *                                  'lte' || 'le' (less or equals),<br />
     *                                  'ne' (not equals),<br />
     *                                  'contains',<br />
     *                                  'notContains',<br />
     *                                  'newer' (via strtotime),<br />
     *                                  'older' (via strtotime),<br />
     *                                  </p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param array|T $value
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     *
     * @psalm-suppress MissingClosureReturnType
     * @psalm-suppress MissingClosureParamType
     */
    public function filterBy(
        string $property,
        $value,
        string $comparisonOp = null
    ): self {
        if (!$comparisonOp) {
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
        }

        $ops = [
            'eq' => static function ($item, $prop, $value): bool {
                return $item[$prop] === $value;
            },
            'gt' => static function ($item, $prop, $value): bool {
                return $item[$prop] > $value;
            },
            'ge' => static function ($item, $prop, $value): bool {
                return $item[$prop] >= $value;
            },
            'gte' => static function ($item, $prop, $value): bool {
                return $item[$prop] >= $value;
            },
            'lt' => static function ($item, $prop, $value): bool {
                return $item[$prop] < $value;
            },
            'le' => static function ($item, $prop, $value): bool {
                return $item[$prop] <= $value;
            },
            'lte' => static function ($item, $prop, $value): bool {
                return $item[$prop] <= $value;
            },
            'ne' => static function ($item, $prop, $value): bool {
                return $item[$prop] !== $value;
            },
            'contains' => static function ($item, $prop, $value): bool {
                return \in_array($item[$prop], (array) $value, true);
            },
            'notContains' => static function ($item, $prop, $value): bool {
                return !\in_array($item[$prop], (array) $value, true);
            },
            'newer' => static function ($item, $prop, $value): bool {
                return \strtotime($item[$prop]) > \strtotime($value);
            },
            'older' => static function ($item, $prop, $value): bool {
                return \strtotime($item[$prop]) < \strtotime($value);
            },
        ];

        $result = \array_values(
            \array_filter(
                $this->toArray(false, true),
                static function ($item) use (
                    $property,
                    $value,
                    $ops,
                    $comparisonOp
                ) {
                    $item = (array) $item;
                    $itemArrayy = static::create($item);
                    $item[$property] = $itemArrayy->get($property, []);

                    return $ops[$comparisonOp]($item, $property, $value);
                }
            )
        );

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Find the first item in an array that passes the truth test, otherwise return false.
     *
     * EXAMPLE: <code>
     * $search = 'foo';
     * $closure = function ($value, $key) use ($search) {
     *     return $value === $search;
     * };
     * a(['foo', 'bar', 'lall'])->find($closure); // 'foo'
     * </code>
     *
     * @param \Closure $closure
     *
     * @return false|mixed
     *                     <p>Return false if we did not find the value.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     * @phpstan-return T|false
     */
    public function find(\Closure $closure)
    {
        foreach ($this->getGenerator() as $key => $value) {
            if ($closure($value, $key)) {
                return $value;
            }
        }

        return false;
    }

    /**
     * find by ...
     *
     * EXAMPLE: <code>
     * $array = [
     *     0 => ['id' => 123, 'name' => 'foo', 'group' => 'primary', 'value' => 123456, 'when' => '2014-01-01'],
     *     1 => ['id' => 456, 'name' => 'bar', 'group' => 'primary', 'value' => 1468, 'when' => '2014-07-15'],
     * ];
     * a($array)->filterBy('name', 'foo'); // Arrayy[0 => ['id' => 123, 'name' => 'foo', 'group' => 'primary', 'value' => 123456, 'when' => '2014-01-01']]
     * </code>
     *
     * @param string $property
     * @param mixed  $value
     * @param string $comparisonOp
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param array|T $value
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
    {
        return $this->filterBy($property, $value, $comparisonOp);
    }

    /**
     * Get the first value from the current array.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->first(); // 'foo'
     * </code>
     *
     * @return mixed|null
     *                    <p>Return null if there wasn't a element.</p>
     *
     * @phpstan-return T|null
     * @psalm-mutation-free
     */
    public function first()
    {
        $key_first = $this->firstKey();
        if ($key_first === null) {
            return null;
        }

        return $this->get($key_first);
    }

    /**
     * Get the first key from the current array.
     *
     * @return mixed|null
     *                    <p>Return null if there wasn't a element.</p>
     *
     * @phpstan-return TKey|null
     *
     * @psalm-mutation-free
     */
    public function firstKey()
    {
        $this->generatorToArray();

        /** @phpstan-var TKey|null $return - help for phpstan */
        $return = \array_key_first($this->array);

        return $return;
    }

    /**
     * Get the first value(s) from the current array.
     * And will return an empty array if there was no first entry.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->firstsImmutable(2); // Arrayy[0 => 'foo', 1 => 'bar']
     * </code>
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function firstsImmutable(int $number = null): self
    {
        $arrayTmp = $this->toArray();

        if ($number === null) {
            $array = (array) \array_shift($arrayTmp);
        } else {
            $array = \array_splice($arrayTmp, 0, $number);
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get the first value(s) from the current array.
     * And will return an empty array if there was no first entry.
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<array-key,TKey>
     * @psalm-mutation-free
     */
    public function firstsKeys(int $number = null): self
    {
        $arrayTmp = $this->keys()->toArray();

        if ($number === null) {
            $array = (array) \array_shift($arrayTmp);
        } else {
            $array = \array_splice($arrayTmp, 0, $number);
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get and remove the first value(s) from the current array.
     * And will return an empty array if there was no first entry.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->firstsMutable(); // 'foo'
     * </code>
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return $this
     *               <p>(Mutable)</p>
     *
     * @phpstan-return ($number is null ? static<int,T> : static<TKey,T>)
     */
    public function firstsMutable(int $number = null): self
    {
        $this->generatorToArray();

        if ($number === null) {
            $shift = \array_shift($this->array);
            /* @phpstan-ignore-next-line | I am not sure if "array<int, T of mixed>" is an error here? */
            $this->array = $shift !== null ? [$shift] : [];
        } else {
            $splice = \array_splice($this->array, 0, $number);
            $this->array = $splice;
        }

        return $this;
    }

    /**
     * Exchanges all keys with their associated values in an array.
     *
     * EXAMPLE: <code>
     * a([0 => 'foo', 1 => 'bar'])->flip(); // Arrayy['foo' => 0, 'bar' => 1]
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<array-key,TKey>
     * @psalm-mutation-free
     */
    public function flip(): self
    {
        $generator = function (): \Generator {
            foreach ($this->getGenerator() as $key => $value) {
                yield (string) $value => $key;
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get a value from an array (optional using dot-notation).
     *
     * EXAMPLE: <code>
     * $arrayy = a(['user' => ['lastname' => 'Moelleken']]);
     * $arrayy->get('user.lastname'); // 'Moelleken'
     * // ---
     * $arrayy = new A();
     * $arrayy['user'] = ['lastname' => 'Moelleken'];
     * $arrayy['user.firstname'] = 'Lars';
     * $arrayy['user']['lastname']; // Moelleken
     * $arrayy['user.lastname']; // Moelleken
     * $arrayy['user.firstname']; // Lars
     * </code>
     *
     * @param int|string $key
     *                                   <p>The key to look for.</p>
     * @param mixed      $fallback
     *                                   <p>Value to fallback to.</p>
     * @param array|null $array
     *                                   <p>The array to get from, if it's set to "null" we use the current array from the
     *                                   class.</p>
     * @param bool       $useByReference
     *
     * @return mixed|static
     *
     * @phpstan-param TKey $key
     * @phpstan-param array<array-key,mixed>|array<TKey,T> $array
     * @psalm-mutation-free
     */
    public function get(
        $key = null,
        $fallback = null,
        array $array = null,
        bool $useByReference = false
    ) {
        if ($array === null && $key === null) {
            if ($useByReference) {
                return $this;
            }

            return clone $this;
        }

        if ($array !== null) {
            if ($useByReference) {
                $usedArray = &$array;
            } else {
                $usedArray = $array;
            }
        } else {
            $this->generatorToArray();

            if ($useByReference) {
                $usedArray = &$this->array;
            } else {
                $usedArray = $this->array;
            }
        }

        if ($key === null) {
            return static::create(
                [],
                $this->iteratorClass,
                false
            )->createByReference($usedArray);
        }

        // php cast "bool"-index into "int"-index
        /* @phpstan-ignore-next-line | this is only a fallback */
        if ((bool) $key === $key) {
            $key = (int) $key;
        }

        if (\array_key_exists($key, $usedArray) === true) {
            if (\is_array($usedArray[$key])) {
                return static::create(
                    [],
                    $this->iteratorClass,
                    false
                )->createByReference($usedArray[$key]);
            }

            return $usedArray[$key];
        }

        // crawl through array, get key according to object or not
        $usePath = false;
        if (
            $this->pathSeparator
            &&
            (string) $key === $key
            &&
            \strpos($key, $this->pathSeparator) !== false
        ) {
            $segments = \explode($this->pathSeparator, (string) $key);
            if ($segments !== false) {
                $usePath = true;
                $usedArrayTmp = $usedArray; // do not use the reference for dot-annotations

                foreach ($segments as $segment) {
                    if (
                        (
                            \is_array($usedArrayTmp)
                            ||
                            $usedArrayTmp instanceof \ArrayAccess
                        )
                        &&
                        isset($usedArrayTmp[$segment])
                    ) {
                        $usedArrayTmp = $usedArrayTmp[$segment];

                        continue;
                    }

                    if (
                        \is_object($usedArrayTmp) === true
                        &&
                        \property_exists($usedArrayTmp, $segment)
                    ) {
                        $usedArrayTmp = $usedArrayTmp->{$segment};

                        continue;
                    }

                    if (isset($segments[0]) && $segments[0] === '*') {
                        $segmentsTmp = $segments;
                        unset($segmentsTmp[0]);
                        $keyTmp = \implode('.', $segmentsTmp);
                        $returnTmp = static::create(
                            [],
                            $this->iteratorClass,
                            false
                        );
                        foreach ($this->getAll() as $dataTmp) {
                            if ($dataTmp instanceof self) {
                                $returnTmp->add($dataTmp->get($keyTmp));

                                continue;
                            }

                            if (
                                (
                                    \is_array($dataTmp)
                                    ||
                                    $dataTmp instanceof \ArrayAccess
                                )
                                &&
                                isset($dataTmp[$keyTmp])
                            ) {
                                $returnTmp->add($dataTmp[$keyTmp]);

                                continue;
                            }

                            if (
                                \is_object($dataTmp) === true
                                &&
                                \property_exists($dataTmp, $keyTmp)
                            ) {
                                $returnTmp->add($dataTmp->{$keyTmp});

                                continue;
                            }
                        }

                        if ($returnTmp->count() > 0) {
                            return $returnTmp;
                        }
                    }

                    return $fallback instanceof \Closure ? $fallback() : $fallback;
                }
            }
        }

        if (isset($usedArrayTmp)) {
            if (!$usePath && !isset($usedArrayTmp[$key])) {
                return $fallback instanceof \Closure ? $fallback() : $fallback;
            }

            if (\is_array($usedArrayTmp)) {
                return static::create(
                    [],
                    $this->iteratorClass,
                    false
                )->createByReference($usedArrayTmp);
            }

            return $usedArrayTmp;
        }

        if (!$usePath && !isset($usedArray[$key])) {
            return $fallback instanceof \Closure ? $fallback() : $fallback;
        }

        return static::create(
            [],
            $this->iteratorClass,
            false
        )->createByReference($usedArray);
    }

    /**
     * alias: for "Arrayy->toArray()"
     *
     * @return array
     *
     * @see          Arrayy::getArray()
     *
     * @phpstan-return array<TKey,T>
     */
    public function getAll(): array
    {
        /** @var array<TKey,T> $return */
        $return = $this->toArray();

        return $return;
    }

    /**
     * Get the current array from the "Arrayy"-object.
     *
     * alias for "toArray()"
     *
     * @param bool $convertAllArrayyElements <p>
     *                                       Convert all Child-"Arrayy" objects also to arrays.
     *                                       </p>
     * @param bool $preserveKeys             <p>
     *                                       e.g.: A generator maybe return the same key more than once,
     *                                       so maybe you will ignore the keys.
     *                                       </p>
     *
     * @return array
     *
     * @phpstan-return array<array-key,T>|array<TKey,T>
     * @psalm-mutation-free
     *
     * @see Arrayy::toArray()
     */
    public function getArray(
        bool $convertAllArrayyElements = false,
        bool $preserveKeys = true
    ): array {
        return $this->toArray(
            $convertAllArrayyElements,
            $preserveKeys
        );
    }

    /**
     * @param string $json
     *
     * @return static
     *                <p>(Immutable)</p>
     */
    public static function createFromJsonMapper(string $json)
    {
        // init
        $class = static::create();

        $jsonObject = \json_decode($json, false);

        $mapper = new \Arrayy\Mapper\Json();
        $mapper->undefinedPropertyHandler = static function ($object, $key, $jsonValue) use ($class) {
            if ($class->checkPropertiesMismatchInConstructor) {
                throw new \TypeError('Property mismatch - input: ' . \print_r(['key' => $key, 'jsonValue' => $jsonValue], true) . ' for object: ' . \get_class($object));
            }
        };

        /** @var static $return - hack for phpstan */
        $return = $mapper->map($jsonObject, $class);

        return $return;
    }

    /**
     * @return array<array-key,TypeCheckInterface>|TypeCheckArray<array-key,TypeCheckInterface>
     *
     * @internal
     */
    public function getPhpDocPropertiesFromClass()
    {
        if ($this->properties === []) {
            $this->properties = $this->getPropertiesFromPhpDoc();
        }

        return $this->properties;
    }

    /**
     * Get the current array from the "Arrayy"-object as list.
     *
     * alias for "toList()"
     *
     * @param bool $convertAllArrayyElements <p>
     *                                       Convert all Child-"Arrayy" objects also to arrays.
     *                                       </p>
     *
     * @return array
     *
     * @phpstan-return list<T>
     * @psalm-mutation-free
     *
     * @see Arrayy::toList()
     */
    public function getList(bool $convertAllArrayyElements = false): array
    {
        return $this->toList($convertAllArrayyElements);
    }

    /**
     * Returns the values from a single column of the input array, identified by
     * the $columnKey, can be used to extract data-columns from multi-arrays.
     *
     * EXAMPLE: <code>
     * a([['foo' => 'bar', 'id' => 1], ['foo => 'lall', 'id' => 2]])->getColumn('foo', 'id'); // Arrayy[1 => 'bar', 2 => 'lall']
     * </code>
     *
     * INFO: Optionally, you may provide an $indexKey to index the values in the returned
     *       array by the values from the $indexKey column in the input array.
     *
     * @param int|string|null $columnKey
     * @param int|string|null $indexKey
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function getColumn($columnKey = null, $indexKey = null): self
    {
        if ($columnKey === null && $indexKey === null) {
            $generator = function () {
                foreach ($this->getGenerator() as $value) {
                    yield $value;
                }
            };
        } else {
            $generator = function () use ($columnKey, $indexKey) {
                foreach ($this->getGenerator() as $value) {
                    // reset
                    $newKey = null;
                    $newValue = null;
                    $newValueFound = false;

                    if ($indexKey !== null) {
                        foreach ($value as $keyInner => $valueInner) {
                            if ($indexKey === $keyInner) {
                                $newKey = $valueInner;
                            }

                            if ($columnKey === $keyInner) {
                                $newValue = $valueInner;
                                $newValueFound = true;
                            }
                        }
                    } else {
                        foreach ($value as $keyInner => $valueInner) {
                            if ($columnKey === $keyInner) {
                                $newValue = $valueInner;
                                $newValueFound = true;
                            }
                        }
                    }

                    if ($newValueFound === false) {
                        if ($newKey !== null) {
                            yield $newKey => $value;
                        } else {
                            yield $value;
                        }
                    } else {
                        /** @noinspection NestedPositiveIfStatementsInspection */
                        if ($newKey !== null) {
                            yield $newKey => $newValue;
                        } else {
                            yield $newValue;
                        }
                    }
                }
            };
        }

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get the current array from the "Arrayy"-object as generator by reference.
     *
     * @return \Generator
     *
     * @phpstan-return \Generator<mixed,T>|\Generator<TKey,T>
     */
    public function &getGeneratorByReference(): \Generator
    {
        if ($this->generator instanceof ArrayyRewindableGenerator) {
            foreach ($this->generator as $key => $value) {
                yield $key => $value;
            }

            return;
        }

        // -> false-positive -> see "&$value"
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->array as $key => &$value) {
            yield $key => $value;
        }
    }

    /**
     * Get the current array from the "Arrayy"-object as generator.
     *
     * @return \Generator
     *
     * @phpstan-return \Generator<mixed,T>|\Generator<TKey,T>
     * @psalm-mutation-free
     */
    public function getGenerator(): \Generator
    {
        if ($this->generator instanceof ArrayyRewindableGenerator) {
            yield from $this->generator;

            return;
        }

        yield from $this->array;
    }

    /**
     * Get the current array from the "Arrayy"-object as generator.
     *
     * @return \Generator
     *
     * @phpstan-return \Generator<mixed,T>|\Generator<TKey,T>
     * @psalm-mutation-free
     */
    public function getBackwardsGenerator(): \Generator
    {
        yield from $this->reverseKeepIndex();
    }

    /**
     * alias: for "Arrayy->keys()"
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @see          Arrayy::keys()
     *
     * @phpstan-return static<int,TKey>
     * @psalm-mutation-free
     */
    public function getKeys()
    {
        return $this->keys();
    }

    /**
     * Get the current array from the "Arrayy"-object as object.
     *
     * @return \stdClass
     */
    public function getObject(): \stdClass
    {
        return self::arrayToObject($this->toArray());
    }

    /**
     * alias: for "Arrayy->randomImmutable()"
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @see          Arrayy::randomImmutable()
     *
     * @phpstan-return static<array-key,T>
     */
    public function getRandom(): self
    {
        return $this->randomImmutable();
    }

    /**
     * alias: for "Arrayy->randomKey()"
     *
     * @return mixed|null
     *                    <p>Get a key/index or null if there wasn't a key/index.</p>
     *
     * @phpstan-return null|TKey
     *
     * @see Arrayy::randomKey()
     */
    public function getRandomKey()
    {
        return $this->randomKey();
    }

    /**
     * alias: for "Arrayy->randomKeys()"
     *
     * @param int $number
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @see          Arrayy::randomKeys()
     *
     * @phpstan-return static<TKey,T>
     */
    public function getRandomKeys(int $number): self
    {
        return $this->randomKeys($number);
    }

    /**
     * alias: for "Arrayy->randomValue()"
     *
     * @return mixed|null
     *                    <p>Get a random value or null if there wasn't a value.</p>
     *
     * @phpstan-return null|T
     *
     * @see Arrayy::randomValue()
     */
    public function getRandomValue()
    {
        return $this->randomValue();
    }

    /**
     * alias: for "Arrayy->randomValues()"
     *
     * @param int $number
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @see          Arrayy::randomValues()
     *
     * @phpstan-return static<TKey,T>
     */
    public function getRandomValues(int $number): self
    {
        return $this->randomValues($number);
    }

    /**
     * Gets all values.
     *
     * @return static
     *                <p>The values of all elements in this array, in the order they
     *                appear in the array.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function getValues()
    {
        $this->generatorToArray(false);

        return static::create(
            \array_values($this->array),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Gets all values via Generator.
     *
     * @return \Generator
     *                    <p>The values of all elements in this array, in the order they
     *                    appear in the array as Generator.</p>
     *
     * @phpstan-return \Generator<TKey,T>
     */
    public function getValuesYield(): \Generator
    {
        yield from $this->getGenerator();
    }

    /**
     * Group values from a array according to the results of a closure.
     *
     * @param callable|int|string $grouper  <p>A callable function name.</p>
     * @param bool                $saveKeys
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param \Closure(T,TKey):TKey|TKey $grouper
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function group($grouper, bool $saveKeys = false): self
    {
        // init
        $result = [];

        // Iterate over values, group by property/results from closure.
        foreach ($this->getGenerator() as $key => $value) {
            if (\is_callable($grouper) === true) {
                $groupKey = $grouper($value, $key);
            } else {
                $groupKey = $this->get($grouper);
            }

            $newValue = $this->get($groupKey, null, $result);

            if ($groupKey instanceof self) {
                $groupKey = $groupKey->toArray();
            }

            if ($newValue instanceof self) {
                $newValue = $newValue->toArray();
            }

            // Add to result.
            if ($groupKey !== null) {
                $result[$groupKey] = $newValue;

                if ($saveKeys) {
                    $result[$groupKey][$key] = $value;
                } else {
                    $result[$groupKey][] = $value;
                }
            }
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Check if an array has a given key.
     *
     * @param mixed $key
     *
     * @return bool
     *
     * @phpstan-param null|TKey|TKey[] $key
     */
    public function has($key): bool
    {
        static $UN_FOUND = null;

        if ($UN_FOUND === null) {
            // Generate unique string to use as marker.
            $UN_FOUND = 'arrayy--' . \uniqid('arrayy', true);
        }

        if (\is_array($key)) {
            if ($key === []) {
                return false;
            }

            foreach ($key as $keyTmp) {
                $found = ($this->get($keyTmp, $UN_FOUND) !== $UN_FOUND);
                if ($found === false) {
                    return false;
                }
            }

            return true;
        }

        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
    }

    /**
     * Check if an array has a given value.
     *
     * INFO: If you need to search recursive please use ```contains($value, true)```.
     *
     * @param mixed $value
     *
     * @return bool
     *
     * @phpstan-param T $value
     */
    public function hasValue($value): bool
    {
        return $this->contains($value);
    }

    /**
     * Implodes the values of this array.
     *
     * EXAMPLE: <code>
     * a([0 => -9, 1, 2])->implode('|'); // '-9|1|2'
     * </code>
     *
     * @param string $glue
     * @param string $prefix
     *
     * @return string
     * @psalm-mutation-free
     */
    public function implode(string $glue = '', string $prefix = ''): string
    {
        return $prefix . $this->implode_recursive($glue, $this->toArray(), false);
    }

    /**
     * Implodes the keys of this array.
     *
     * @param string $glue
     *
     * @return string
     * @psalm-mutation-free
     */
    public function implodeKeys(string $glue = ''): string
    {
        return $this->implode_recursive($glue, $this->toArray(), true);
    }

    /**
     * Given a list and an iterate-function that returns
     * a key for each element in the list (or a property name),
     * returns an object with an index of each item.
     *
     * @param int|string $key
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param array-key $key
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function indexBy($key): self
    {
        // init
        $results = [];

        foreach ($this->getGenerator() as $a) {
            if (\array_key_exists($key, $a) === true) {
                $results[$a[$key]] = $a;
            }
        }

        return static::create(
            $results,
            $this->iteratorClass,
            false
        );
    }

    /**
     * alias: for "Arrayy->searchIndex()"
     *
     * @param mixed $value
     *                     <p>The value to search for.</p>
     *
     * @return false|int|string
     *
     * @phpstan-param T $value
     * @phpstan-return false|TKey
     *
     * @see Arrayy::searchIndex()
     */
    public function indexOf($value)
    {
        return $this->searchIndex($value);
    }

    /**
     * Get everything but the last..$to items.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->initial(2); // Arrayy[0 => 'foo']
     * </code>
     *
     * @param int $to
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function initial(int $to = 1): self
    {
        return $this->firstsImmutable(\count($this->toArray(), \COUNT_NORMAL) - $to);
    }

    /**
     * Return an array with all elements found in input array.
     *
     * EXAMPLE: <code>
     * a(['foo', 'bar'])->intersection(['bar', 'baz']); // Arrayy['bar']
     * </code>
     *
     * @param array $search
     * @param bool  $keepKeys
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $search
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function intersection(array $search, bool $keepKeys = false): self
    {
        if ($keepKeys) {
            /**
             * @psalm-suppress MissingClosureReturnType
             * @psalm-suppress MissingClosureParamType
             */
            return static::create(
                \array_uintersect(
                    $this->toArray(),
                    $search,
                    static function ($a, $b) {
                        return $a === $b ? 0 : -1;
                    }
                ),
                $this->iteratorClass,
                false
            );
        }

        return static::create(
            \array_values(\array_intersect($this->toArray(), $search)),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return an array with all elements found in input array.
     *
     * @param array ...$array
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<array<TKey,T>> ...$array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function intersectionMulti(...$array): self
    {
        return static::create(
            \array_values(\array_intersect($this->toArray(), ...$array)),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
     *
     * EXAMPLE: <code>
     * a(['foo', 'bar'])->intersects(['föö', 'bär']); // false
     * </code>
     *
     * @param array $search
     *
     * @return bool
     *
     * @phpstan-param array<TKey,T> $search
     */
    public function intersects(array $search): bool
    {
        return $this->intersection($search)->count() > 0;
    }

    /**
     * Invoke a function on all of an array's values.
     *
     * @param callable $callable
     * @param mixed    $arguments
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  callable(T,mixed=):mixed $callable
     * @phpstan-return static<int, T>|static<TKey, T>
     * @psalm-mutation-free
     */
    public function invoke($callable, $arguments = []): self
    {
        // If one argument given for each iteration, create an array for it.
        if (!\is_array($arguments)) {
            $arguments = \array_fill(
                0,
                $this->count(),
                $arguments
            );
        }

        // If the callable has arguments, pass them.
        if ($arguments) {
            $array = \array_map($callable, $this->toArray(), $arguments);
        } else {
            $array = $this->map($callable);
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Check whether array is associative or not.
     *
     * EXAMPLE: <code>
     * a(['foo' => 'bar', 2, 3])->isAssoc(); // true
     * </code>
     *
     * @param bool $recursive
     *
     * @return bool
     *              <p>Returns true if associative, false otherwise.</p>
     */
    public function isAssoc(bool $recursive = false): bool
    {
        if ($this->isEmpty()) {
            return false;
        }

        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->keys($recursive)->getGeneratorByReference() as &$key) {
            if ((string) $key !== $key) {
                return false;
            }
        }

        return true;
    }

    /**
     * Check if a given key or keys are empty.
     *
     * @param int|int[]|string|string[]|null $keys
     *
     * @return bool
     *              <p>Returns true if empty, false otherwise.</p>
     * @psalm-mutation-free
     */
    public function isEmpty($keys = null): bool
    {
        if ($this->generator) {
            return $this->toArray() === [];
        }

        if ($keys === null) {
            return $this->array === [];
        }

        foreach ((array) $keys as $key) {
            if (!empty($this->get($key))) {
                return false;
            }
        }

        return true;
    }

    /**
     * Check if the current array is equal to the given "$array" or not.
     *
     * EXAMPLE: <code>
     * a(['💩'])->isEqual(['💩']); // true
     * </code>
     *
     * @param array $array
     *
     * @return bool
     *
     * @phpstan-param array<TKey,T> $array
     */
    public function isEqual(array $array): bool
    {
        return $this->toArray() === $array;
    }

    /**
     * Check if the current array is a multi-array.
     *
     * EXAMPLE: <code>
     * a(['foo' => [1, 2 , 3]])->isMultiArray(); // true
     * </code>
     *
     * @return bool
     */
    public function isMultiArray(): bool
    {
        foreach ($this->getGenerator() as $value) {
            if (\is_array($value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check whether array is numeric or not.
     *
     * @return bool
     *              <p>Returns true if numeric, false otherwise.</p>
     */
    public function isNumeric(): bool
    {
        if ($this->isEmpty()) {
            return false;
        }

        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->keys()->getGeneratorByReference() as &$key) {
            if ((int) $key !== $key) {
                return false;
            }
        }

        return true;
    }

    /**
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
     *
     * EXAMPLE: <code>
     * a([0 => 'foo', 1 => 'lall', 2 => 'foobar'])->isSequential(); // true
     * </code>
     *
     * INFO: If the array is empty we count it as non-sequential.
     *
     * @param bool $recursive
     *
     * @return bool
     * @psalm-mutation-free
     */
    public function isSequential(bool $recursive = false): bool
    {
        $i = 0;
        foreach ($this->getGenerator() as $key => $value) {
            if (
                $recursive
                &&
                (\is_array($value) || $value instanceof \Traversable)
                &&
                self::create($value)->isSequential() === false
            ) {
                return false;
            }

            if ($key !== $i) {
                return false;
            }

            ++$i;
        }

        return !($i === 0);
    }

    /**
     * @return array
     *
     * @phpstan-return array<TKey,T>
     */
    public function jsonSerialize(): array
    {
        /** @var array<TKey,T> $return */
        $return = $this->toArray();

        return $return;
    }

    /**
     * Gets the key/index of the element at the current internal iterator position.
     *
     * @return int|string|null
     * @phpstan-return array-key|null
     */
    public function key()
    {
        if ($this->generator) {
            return $this->generator->key();
        }

        return \key($this->array);
    }

    /**
     * Checks if the given key exists in the provided array.
     *
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
     *       then you need to use "Arrayy->offsetExists()".
     *
     * @param int|string $key the key to look for
     *
     * @return bool
     * @psalm-mutation-free
     */
    public function keyExists($key): bool
    {
        foreach ($this->getGenerator() as $keyTmp => $value) {
            if ($key === $keyTmp) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get all keys from the current array.
     *
     * EXAMPLE: <code>
     * a([1 => 'foo', 2 => 'foo2', 3 => 'bar'])->keys(); // Arrayy[1, 2, 3]
     * </code>
     *
     * @param bool       $recursive
     *                                  [optional] <p>
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
     *                                  </p>
     * @param mixed|null $search_values
     *                                  [optional] <p>
     *                                  If specified, then only keys containing these values are returned.
     *                                  </p>
     * @param bool       $strict
     *                                  [optional] <p>
     *                                  Determines if strict comparison (===) should be used during the search.
     *                                  </p>
     *
     * @return static
     *                <p>(Immutable) An array of all the keys in input.</p>
     *
     * @phpstan-param null|T|T[] $search_values
     * @phpstan-return static<int,TKey>
     *
     * @psalm-mutation-free
     */
    public function keys(
        bool $recursive = false,
        $search_values = null,
        bool $strict = true
    ): self {

        // recursive

        if ($recursive === true) {
            $array = $this->array_keys_recursive(
                null,
                $search_values,
                $strict
            );

            return static::create(
                $array,
                $this->iteratorClass,
                false
            );
        }

        // non recursive

        if ($search_values === null) {
            $arrayFunction = function (): \Generator {
                foreach ($this->getGenerator() as $key => $value) {
                    yield $key;
                }
            };
        } else {
            $arrayFunction = function () use ($search_values, $strict): \Generator {
                $is_array_tmp = \is_array($search_values);

                /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
                foreach ($this->getGeneratorByReference() as $key => &$value) {
                    if (
                        (
                            $is_array_tmp === false
                            &&
                            $strict === true
                            &&
                            $search_values === $value
                        )
                        ||
                        (
                            $is_array_tmp === false
                            &&
                            $strict === false
                            &&
                            $search_values == $value
                        )
                        ||
                        (
                            $is_array_tmp === true
                            &&
                            \in_array($value, $search_values, $strict)
                        )
                    ) {
                        yield $key;
                    }
                }
            };
        }

        return static::create(
            $arrayFunction,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Sort an array by key in reverse order.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function krsort(int $sort_flags = 0): self
    {
        $this->generatorToArray();

        \krsort($this->array, $sort_flags);

        return $this;
    }

    /**
     * Sort an array by key in reverse order.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function krsortImmutable(int $sort_flags = 0): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->krsort($sort_flags);

        return $that;
    }

    /**
     * Get the last value from the current array.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->last(); // 'lall'
     * </code>
     *
     * @return mixed|null
     *                    <p>Return null if there wasn't a element.</p>
     *
     * @phpstan-return T|null
     * @psalm-mutation-free
     */
    public function last()
    {
        $key_last = $this->lastKey();
        if ($key_last === null) {
            return null;
        }

        /** @var T $value_last */
        $value_last = $this->get($key_last);

        return $value_last;
    }

    /**
     * Get the last key from the current array.
     *
     * @return mixed|null
     *                    <p>Return null if there wasn't a element.</p>
     *
     * @phpstan-return null|TKey
     * @psalm-mutation-free
     */
    public function lastKey()
    {
        $this->generatorToArray();

        return \array_key_last($this->array);
    }

    /**
     * Get the last value(s) from the current array.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->lasts(2); // Arrayy[0 => 'bar', 1 => 'lall']
     * </code>
     *
     * @param int|null $number
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function lastsImmutable(int $number = null): self
    {
        if ($this->isEmpty()) {
            return static::create(
                [],
                $this->iteratorClass,
                false
            );
        }

        if ($number === null) {
            $poppedValue = $this->last();

            if ($poppedValue === null) {
                $poppedValue = [$poppedValue];
            } else {
                $poppedValue = (array) $poppedValue;
            }

            $arrayy = static::create(
                $poppedValue,
                $this->iteratorClass,
                false
            );
        } else {
            $arrayy = $this->rest(-$number);
        }

        return $arrayy;
    }

    /**
     * Get the last value(s) from the current array.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->lasts(2); // Arrayy[0 => 'bar', 1 => 'lall']
     * </code>
     *
     * @param int|null $number
     *
     * @return $this
     *               <p>(Mutable)</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function lastsMutable(int $number = null): self
    {
        if ($this->isEmpty()) {
            return $this;
        }

        $this->array = $this->lastsImmutable($number)->toArray();
        $this->generator = null;

        return $this;
    }

    /**
     * Count the values from the current array.
     *
     * alias: for "Arrayy->count()"
     *
     * @param int $mode
     *
     * @return int
     *
     * @see Arrayy::count()
     */
    public function length(int $mode = \COUNT_NORMAL): int
    {
        return $this->count($mode);
    }

    /**
     * Apply the given function to the every element of the array,
     * collecting the results.
     *
     * EXAMPLE: <code>
     * a(['foo', 'Foo'])->map('mb_strtoupper'); // Arrayy['FOO', 'FOO']
     * </code>
     *
     * @param callable $callable
     * @param bool     $useKeyAsSecondParameter
     * @param mixed    ...$arguments
     *
     * @return static
     *                <p>(Immutable) Arrayy object with modified elements.</p>
     *
     * @template T2
     *              <p>The output value type.</p>
     *
     * @phpstan-param callable(T,TKey=,mixed=):T2 $callable
     * @phpstan-return static<TKey,T2>
     * @psalm-mutation-free
     */
    public function map(
        callable $callable,
        bool $useKeyAsSecondParameter = false,
        ...$arguments
    ) {
        /**
         * @psalm-suppress ImpureFunctionCall - func_num_args is only used to detect the number of args
         */
        $useArguments = \func_num_args() > 2;

        return static::create(
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
                foreach ($this->getGenerator() as $key => $value) {
                    if ($useArguments) {
                        if ($useKeyAsSecondParameter) {
                            yield $key => $callable($value, $key, ...$arguments);
                        } else {
                            yield $key => $callable($value, ...$arguments);
                        }
                    } else {
                        /** @noinspection NestedPositiveIfStatementsInspection */
                        if ($useKeyAsSecondParameter) {
                            yield $key => $callable($value, $key);
                        } else {
                            yield $key => $callable($value);
                        }
                    }
                }
            },
            $this->iteratorClass,
            false
        );
    }

    /**
     * Check if all items in current array match a truth test.
     *
     * EXAMPLE: <code>
     * $closure = function ($value, $key) {
     *     return ($value % 2 === 0);
     * };
     * a([2, 4, 8])->matches($closure); // true
     * </code>
     *
     * @param \Closure $closure
     *
     * @return bool
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function matches(\Closure $closure): bool
    {
        if ($this->count() === 0) {
            return false;
        }

        foreach ($this->getGenerator() as $key => $value) {
            $value = $closure($value, $key);

            if ($value === false) {
                return false;
            }
        }

        return true;
    }

    /**
     * Check if any item in the current array matches a truth test.
     *
     * EXAMPLE: <code>
     * $closure = function ($value, $key) {
     *     return ($value % 2 === 0);
     * };
     * a([1, 4, 7])->matches($closure); // true
     * </code>
     *
     * @param \Closure $closure
     *
     * @return bool
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function matchesAny(\Closure $closure): bool
    {
        if ($this->count() === 0) {
            return false;
        }

        foreach ($this->getGenerator() as $key => $value) {
            $value = $closure($value, $key);

            if ($value === true) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get the max value from an array.
     *
     * EXAMPLE: <code>
     * a([-9, -8, -7, 1.32])->max(); // 1.32
     * </code>
     *
     * @return false|float|int|string
     *                                <p>Will return false if there are no values.</p>
     */
    public function max()
    {
        if ($this->count() === 0) {
            return false;
        }

        $max = false;
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->getGeneratorByReference() as &$value) {
            if (
                $max === false
                ||
                $value > $max
            ) {
                $max = $value;
            }
        }

        return $max;
    }

    /**
     * Merge the new $array into the current array.
     *
     * - keep key,value from the current array, also if the index is in the new $array
     *
     * EXAMPLE: <code>
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
     * a($array1)->mergeAppendKeepIndex($array2); // Arrayy[1 => 'one', 'foo' => 'bar2', 3 => 'three']
     * // ---
     * $array1 = [0 => 'one', 1 => 'foo'];
     * $array2 = [0 => 'foo', 1 => 'bar2'];
     * a($array1)->mergeAppendKeepIndex($array2); // Arrayy[0 => 'foo', 1 => 'bar2']
     * </code>
     *
     * @param array $array
     * @param bool  $recursive
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<int|TKey,T> $array
     * @phpstan-return static<int|TKey,T>
     * @psalm-mutation-free
     */
    public function mergeAppendKeepIndex(array $array = [], bool $recursive = false): self
    {
        if ($recursive === true) {
            $array = $this->getArrayRecursiveHelperArrayy($array);
            $result = \array_replace_recursive($this->toArray(), $array);
        } else {
            $result = \array_replace($this->toArray(), $array);
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Merge the new $array into the current array.
     *
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
     * - create new indexes
     *
     * EXAMPLE: <code>
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
     * a($array1)->mergeAppendNewIndex($array2); // Arrayy[0 => 'one', 'foo' => 'bar2', 1 => 'three']
     * // ---
     * $array1 = [0 => 'one', 1 => 'foo'];
     * $array2 = [0 => 'foo', 1 => 'bar2'];
     * a($array1)->mergeAppendNewIndex($array2); // Arrayy[0 => 'one', 1 => 'foo', 2 => 'foo', 3 => 'bar2']
     * </code>
     *
     * @param array $array
     * @param bool  $recursive
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<int,T>
     * @psalm-mutation-free
     */
    public function mergeAppendNewIndex(array $array = [], bool $recursive = false): self
    {
        if ($recursive === true) {
            $array = $this->getArrayRecursiveHelperArrayy($array);
            $result = \array_merge_recursive($this->toArray(), $array);
        } else {
            $result = \array_merge($this->toArray(), $array);
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Merge the the current array into the $array.
     *
     * - use key,value from the new $array, also if the index is in the current array
     *
     * EXAMPLE: <code>
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
     * a($array1)->mergePrependKeepIndex($array2); // Arrayy['foo' => 'bar1', 3 => 'three', 1 => 'one']
     * // ---
     * $array1 = [0 => 'one', 1 => 'foo'];
     * $array2 = [0 => 'foo', 1 => 'bar2'];
     * a($array1)->mergePrependKeepIndex($array2); // Arrayy[0 => 'one', 1 => 'foo']
     * </code>
     *
     * @param array $array
     * @param bool  $recursive
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function mergePrependKeepIndex(array $array = [], bool $recursive = false): self
    {
        if ($recursive === true) {
            $array = $this->getArrayRecursiveHelperArrayy($array);
            $result = \array_replace_recursive($array, $this->toArray());
        } else {
            $result = \array_replace($array, $this->toArray());
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Merge the current array into the new $array.
     *
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
     * - create new indexes
     *
     * EXAMPLE: <code>
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
     * a($array1)->mergePrependNewIndex($array2); // Arrayy['foo' => 'bar1', 0 => 'three', 1 => 'one']
     * // ---
     * $array1 = [0 => 'one', 1 => 'foo'];
     * $array2 = [0 => 'foo', 1 => 'bar2'];
     * a($array1)->mergePrependNewIndex($array2); // Arrayy[0 => 'foo', 1 => 'bar2', 2 => 'one', 3 => 'foo']
     * </code>
     *
     * @param array $array
     * @param bool  $recursive
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<int,T>
     * @psalm-mutation-free
     */
    public function mergePrependNewIndex(array $array = [], bool $recursive = false): self
    {
        if ($recursive === true) {
            $array = $this->getArrayRecursiveHelperArrayy($array);
            $result = \array_merge_recursive($array, $this->toArray());
        } else {
            $result = \array_merge($array, $this->toArray());
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * @return ArrayyMeta|mixed|static
     */
    public static function meta()
    {
        return (new ArrayyMeta())->getMetaObject(static::class);
    }

    /**
     * Get the min value from an array.
     *
     * EXAMPLE: <code>
     * a([-9, -8, -7, 1.32])->min(); // -9
     * </code>
     *
     * @return false|mixed
     *                     <p>Will return false if there are no values.</p>
     *
     * @phpstan-return false|T
     */
    public function min()
    {
        if ($this->count() === 0) {
            return false;
        }

        $min = false;
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->getGeneratorByReference() as &$value) {
            if (
                $min === false
                ||
                $value < $min
            ) {
                $min = $value;
            }
        }

        return $min;
    }

    /**
     * Get the most used value from the array.
     *
     * @return mixed|null
     *                    <p>(Immutable) Return null if there wasn't an element.</p>
     *
     * @phpstan-return T|null
     * @psalm-mutation-free
     */
    public function mostUsedValue()
    {
        /* @phpstan-ignore-next-line | false-positive? maybe because we switch key-value via "countValues"? */
        return $this->countValues()->arsortImmutable()->firstKey();
    }

    /**
     * Get the most used value from the array.
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<array-key,T>
     * @psalm-mutation-free
     */
    public function mostUsedValues(int $number = null): self
    {
        return $this->countValues()->arsortImmutable()->firstsKeys($number);
    }

    /**
     * Move an array element to a new index.
     *
     * EXAMPLE: <code>
     * $arr2 = new A(['A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e']);
     * $newArr2 = $arr2->moveElement('D', 1); // Arrayy['A' => 'a', 'D' => 'd', 'B' => 'b', 'C' => 'c', 'E' => 'e']
     * </code>
     *
     * @param int|string $from
     * @param int        $to
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function moveElement($from, $to): self
    {
        $array = $this->toArray();

        if ((int) $from === $from) {
            $tmp = \array_splice($array, $from, 1);
            \array_splice($array, (int) $to, 0, $tmp);
            $output = $array;
        } elseif ((string) $from === $from) {
            $indexToMove = \array_search($from, \array_keys($array), true);
            $itemToMove = $array[$from];
            if ($indexToMove !== false) {
                \array_splice($array, $indexToMove, 1);
            }
            $i = 0;
            $output = [];
            foreach ($array as $key => $item) {
                if ($i === $to) {
                    $output[$from] = $itemToMove;
                }
                $output[$key] = $item;
                ++$i;
            }
        } else {
            $output = [];
        }

        return static::create(
            $output,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Move an array element to the first place.
     *
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
     *       loss the keys of an indexed array.
     *
     * @param int|string $key
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function moveElementToFirstPlace($key): self
    {
        $array = $this->toArray();

        if ($this->offsetExists($key)) {
            $tmpValue = $this->get($key);
            unset($array[$key]);
            $array = [$key => $tmpValue] + $array;
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Move an array element to the last place.
     *
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
     *       loss the keys of an indexed array.
     *
     * @param int|string $key
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function moveElementToLastPlace($key): self
    {
        $array = $this->toArray();

        if ($this->offsetExists($key)) {
            $tmpValue = $this->get($key);
            unset($array[$key]);
            $array += [$key => $tmpValue];
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Moves the internal iterator position to the next element and returns this element.
     *
     * @return false|mixed
     *                     <p>(Mutable) Will return false if there are no values.</p>
     *
     * @phpstan-return false|T
     */
    public function next()
    {
        if ($this->generator) {
            $this->generator->next();

            return $this->generator->current() ?? false;
        }

        return \next($this->array);
    }

    /**
     * Get the next nth keys and values from the array.
     *
     * @param int $step
     * @param int $offset
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function nth(int $step, int $offset = 0): self
    {
        $arrayFunction = function () use ($step, $offset): \Generator {
            $position = 0;
            foreach ($this->getGenerator() as $key => $value) {
                if ($position++ % $step !== $offset) {
                    continue;
                }

                yield $key => $value;
            }
        };

        return static::create(
            $arrayFunction,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get a subset of the items from the given array.
     *
     * @param int[]|string[] $keys
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param array-key[] $keys
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function only(array $keys): self
    {
        $keys = \array_flip($keys);

        $generator = function () use ($keys): \Generator {
            foreach ($this->getGenerator() as $key => $value) {
                if (isset($keys[$key])) {
                    yield $key => $value;
                }
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Pad array to the specified size with a given value.
     *
     * @param int   $size  <p>Size of the result array.</p>
     * @param mixed $value <p>Empty value by default.</p>
     *
     * @return static
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function pad(int $size, $value): self
    {
        return static::create(
            \array_pad($this->toArray(), $size, $value),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Partitions this array in two array according to a predicate.
     * Keys are preserved in the resulting array.
     *
     * @param \Closure $closure
     *                          <p>The predicate on which to partition.</p>
     *
     * @return array<int, static>
     *                    <p>An array with two elements. The first element contains the array
     *                    of elements where the predicate returned TRUE, the second element
     *                    contains the array of elements where the predicate returned FALSE.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     * @phpstan-return array<int, static<TKey,T>>
     */
    public function partition(\Closure $closure): array
    {
        // init
        $matches = [];
        $noMatches = [];

        foreach ($this->getGenerator() as $key => $value) {
            if ($closure($value, $key)) {
                $matches[$key] = $value;
            } else {
                $noMatches[$key] = $value;
            }
        }

        return [self::create($matches), self::create($noMatches)];
    }

    /**
     * Pop a specified value off the end of the current array.
     *
     * @return mixed|null
     *                    <p>(Mutable) The popped element from the current array or null if the array is e.g. empty.</p>
     *
     * @phpstan-return T|null
     */
    public function pop()
    {
        $this->generatorToArray();

        return \array_pop($this->array);
    }

    /**
     * Prepend a (key) + value to the current array.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř'])->prepend('foo'); // Arrayy[0 => 'foo', 'fòô' => 'bàř']
     * </code>
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey|null $key
     * @phpstan-return static<TKey,T>
     */
    public function prepend($value, $key = null)
    {
        $this->generatorToArray();

        if ($this->properties !== []) {
            $this->checkType($key, $value);
        }

        if ($key === null) {
            \array_unshift($this->array, $value);
        } else {
            $this->array = [$key => $value] + $this->array;
        }

        return $this;
    }

    /**
     * Prepend a (key) + value to the current array.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř'])->prependImmutable('foo')->getArray(); // [0 => 'foo', 'fòô' => 'bàř']
     * </code>
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object, with the prepended value.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey $key
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function prependImmutable($value, $key = null)
    {
        $generator = function () use ($key, $value): \Generator {
            if ($this->properties !== []) {
                $this->checkType($key, $value);
            }

            if ($key !== null) {
                yield $key => $value;
            } else {
                yield $value;
            }

            foreach ($this->getGenerator() as $keyOld => $itemOld) {
                yield $keyOld => $itemOld;
            }
        };

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Add a suffix to each key.
     *
     * @param float|int|string $suffix
     *
     * @return static
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function prependToEachKey($suffix): self
    {
        // init
        $result = [];

        foreach ($this->getGenerator() as $key => $item) {
            if ($item instanceof self) {
                $result[$key] = $item->prependToEachKey($suffix);
            } elseif (\is_array($item)) {
                $result[$key] = self::create(
                    $item,
                    $this->iteratorClass,
                    false
                )->prependToEachKey($suffix)
                    ->toArray();
            } else {
                $result[$key . $suffix] = $item;
            }
        }

        return self::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Add a suffix to each value.
     *
     * @param float|int|string $suffix
     *
     * @return static
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function prependToEachValue($suffix): self
    {
        // init
        $result = [];

        foreach ($this->getGenerator() as $key => $item) {
            if ($item instanceof self) {
                $result[$key] = $item->prependToEachValue($suffix);
            } elseif (\is_array($item)) {
                $result[$key] = self::create(
                    $item,
                    $this->iteratorClass,
                    false
                )->prependToEachValue($suffix)
                    ->toArray();
            } elseif (\is_object($item) === true) {
                $result[$key] = $item;
            } else {
                $result[$key] = $item . $suffix;
            }
        }

        return self::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return the value of a given key and
     * delete the key.
     *
     * @param int|int[]|string|string[]|null $keyOrKeys
     * @param mixed                          $fallback
     *
     * @return mixed
     *
     * @template TFallback $fallback
     * @phpstan-param TFallback $fallback
     * @phpstan-return TFallback|T|T[]
     */
    public function pull($keyOrKeys = null, $fallback = null)
    {
        if ($keyOrKeys === null) {
            $array = $this->toArray();
            $this->clear();

            return $array;
        }

        if (\is_array($keyOrKeys)) {
            $valueOrValues = [];
            foreach ($keyOrKeys as $key) {
                $valueOrValues[] = $this->get($key, $fallback);
                $this->offsetUnset($key);
            }
        } else {
            $valueOrValues = $this->get($keyOrKeys, $fallback);
            $this->offsetUnset($keyOrKeys);
        }

        /** @var T|T[]|TFallback $valueOrValues */
        return $valueOrValues;
    }

    /**
     * Push one or more values onto the end of array at once.
     *
     * @param mixed ...$args
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
     *
     * @noinspection ReturnTypeCanBeDeclaredInspection
     *
     * @phpstan-param  array<TKey,T> ...$args
     * @phpstan-return static<TKey,T>
     */
    public function push(...$args)
    {
        $this->generatorToArray();

        if (
            $this->checkPropertyTypes
            &&
            $this->properties !== []
        ) {
            foreach ($args as $key => $value) {
                $this->checkType($key, $value);
            }
        }

        \array_push($this->array, ...$args);

        return $this;
    }

    /**
     * Get a random value from the current array.
     *
     * EXAMPLE: <code>
     * a([1, 2, 3, 4])->randomImmutable(2); // e.g.: Arrayy[1, 4]
     * </code>
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<array-key,T>
     */
    public function randomImmutable(int $number = null): self
    {
        $this->generatorToArray();

        if ($this->count() === 0) {
            return static::create(
                [],
                $this->iteratorClass,
                false
            );
        }

        if ($number === null) {
            $arrayRandValue = [$this->array[\array_rand($this->array)]];

            return static::create(
                $arrayRandValue,
                $this->iteratorClass,
                false
            );
        }

        $arrayTmp = $this->array;
        \shuffle($arrayTmp);

        return static::create(
            $arrayTmp,
            $this->iteratorClass,
            false
        )->firstsImmutable($number);
    }

    /**
     * Pick a random key/index from the keys of this array.
     *
     * EXAMPLE: <code>
     * $arrayy = A::create([1 => 'one', 2 => 'two']);
     * $arrayy->randomKey(); // e.g. 2
     * </code>
     *
     * @throws \RangeException If array is empty
     *
     * @return mixed|null
     *                    <p>Get a key/index or null if there wasn't a key/index.</p>
     *
     * @phpstan-return null|TKey
     */
    public function randomKey()
    {
        $result = $this->randomKeys(1);

        if (!isset($result[0])) {
            $result[0] = null;
        }

        return $result[0];
    }

    /**
     * Pick a given number of random keys/indexes out of this array.
     *
     * EXAMPLE: <code>
     * a([1 => 'one', 2 => 'two'])->randomKeys(); // e.g. Arrayy[1, 2]
     * </code>
     *
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
     *
     * @throws \RangeException If array is empty
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function randomKeys(int $number): self
    {
        $this->generatorToArray();

        $count = $this->count();

        if (
            $number === 0
            ||
            $number > $count
        ) {
            throw new \RangeException(
                \sprintf(
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
                    $number,
                    $count
                )
            );
        }

        $result = (array) \array_rand($this->array, $number);

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get a random value from the current array.
     *
     * EXAMPLE: <code>
     * a([1, 2, 3, 4])->randomMutable(2); // e.g.: Arrayy[1, 4]
     * </code>
     *
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function randomMutable(int $number = null): self
    {
        $this->generatorToArray();

        if ($this->count() === 0) {
            return static::create(
                [],
                $this->iteratorClass,
                false
            );
        }

        if ($number === null) {
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
            $this->array = $arrayRandValue;

            return $this;
        }

        \shuffle($this->array);

        return $this->firstsMutable($number);
    }

    /**
     * Pick a random value from the values of this array.
     *
     * EXAMPLE: <code>
     * a([1 => 'one', 2 => 'two'])->randomValue(); // e.g. 'one'
     * </code>
     *
     * @return mixed
     *               <p>Get a random value or null if there wasn't a value.</p>
     *
     * @phpstan-return T|null
     */
    public function randomValue()
    {
        $result = $this->randomImmutable();

        if (!isset($result[0])) {
            $result[0] = null;
        }

        return $result[0];
    }

    /**
     * Pick a given number of random values out of this array.
     *
     * EXAMPLE: <code>
     * a([1 => 'one', 2 => 'two'])->randomValues(); // e.g. Arrayy['one', 'two']
     * </code>
     *
     * @param int $number
     *
     * @return static
     *                <p>(Mutable)</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function randomValues(int $number): self
    {
        return $this->randomMutable($number);
    }

    /**
     * Get a random value from an array, with the ability to skew the results.
     *
     * EXAMPLE: <code>
     * a([0 => 3, 1 => 4])->randomWeighted([1 => 4]); // e.g.: Arrayy[4] (has a 66% chance of returning 4)
     * </code>
     *
     * @param array    $array
     * @param int|null $number <p>How many values you will take?</p>
     *
     * @return static<int,mixed>
     *                           <p>(Immutable)</p>
     *
     * @phpstan-param  array<(int&T)|(string&T),int> $array
     * @phpstan-return static<array-key,T>
     */
    public function randomWeighted(array $array, int $number = null): self
    {
        // init
        $options = [];

        foreach ($array as $option => $weight) {
            /** @phpstan-var T $option - hack: we protect this method via (int&T)|(string&T) */
            if ($this->searchIndex($option) !== false) {
                for ($i = 0; $i < $weight; ++$i) {
                    $options[] = $option;
                }
            }
        }

        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
    }

    /**
     * Reduce the current array via callable e.g. anonymous-function and return the end result.
     *
     * EXAMPLE: <code>
     * a([1, 2, 3, 4])->reduce(
     *     function ($carry, $item) {
     *         return $carry * $item;
     *     },
     *     1
     * ); // Arrayy[24]
     * </code>
     *
     * @param callable $callable
     * @param mixed    $initial
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @template T2
     *              <p>The output value type.</p>
     *
     * @phpstan-param callable(T2, T, TKey): T2 $callable
     * @phpstan-param T2                        $initial
     *
     * @phpstan-return static<TKey,T2>
     * @psalm-mutation-free
     */
    public function reduce($callable, $initial = []): self
    {
        foreach ($this->getGenerator() as $key => $value) {
            $initial = $callable($initial, $value, $key);
        }

        /** @var static<TKey,T2> $return - help for phpstan */
        $return = static::create(
            $initial,
            $this->iteratorClass,
            false
        );

        return $return;
    }

    /**
     * @param bool $unique
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<int,mixed>
     * @psalm-mutation-free
     */
    public function reduce_dimension(bool $unique = true): self
    {
        // init
        $result = [];

        foreach ($this->getGenerator() as $val) {
            if (\is_array($val)) {
                $result[] = (new static($val))->reduce_dimension($unique)->toArray();
            } else {
                $result[] = [$val];
            }
        }

        $result = $result === [] ? [] : \array_merge(...$result);

        $resultArrayy = new static($result);

        /**
         * @psalm-suppress ImpureMethodCall - object is already re-created
         * @psalm-suppress InvalidReturnStatement - why?
         */
        return $unique ? $resultArrayy->unique() : $resultArrayy;
    }

    /**
     * Create a numerically re-indexed Arrayy object.
     *
     * EXAMPLE: <code>
     * a([2 => 1, 3 => 2])->reindex(); // Arrayy[0 => 1, 1 => 2]
     * </code>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function reindex(): self
    {
        $this->generatorToArray(false);

        $this->array = \array_values($this->array);

        return $this;
    }

    /**
     * Return all items that fail the truth test.
     *
     * EXAMPLE: <code>
     * $closure = function ($value) {
     *     return $value % 2 !== 0;
     * }
     * a([1, 2, 3, 4])->reject($closure); // Arrayy[1 => 2, 3 => 4]
     * </code>
     *
     * @param \Closure $closure
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param \Closure(T,TKey):bool  $closure
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function reject(\Closure $closure): self
    {
        // init
        $filtered = [];

        foreach ($this->getGenerator() as $key => $value) {
            if (!$closure($value, $key)) {
                $filtered[$key] = $value;
            }
        }

        return static::create(
            $filtered,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Remove a value from the current array (optional using dot-notation).
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->remove(1); // Arrayy['foo' => 'foo']
     * </code>
     *
     * @param mixed $key
     *
     * @return static
     *                <p>(Mutable)</p>
     *
     * @phpstan-param  TKey|TKey[] $key
     * @phpstan-return static<TKey,T>
     */
    public function remove($key)
    {
        // recursive call
        if (\is_array($key)) {
            foreach ($key as $k) {
                $this->internalRemove($k);
            }

            return static::create(
                $this->toArray(),
                $this->iteratorClass,
                false
            );
        }

        $this->internalRemove($key);

        return static::create(
            $this->toArray(),
            $this->iteratorClass,
            false
        );
    }

    /**
     * alias: for "Arrayy->removeValue()"
     *
     * @param mixed $element
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  T $element
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function removeElement($element)
    {
        return $this->removeValue($element);
    }

    /**
     * Remove the first value from the current array.
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->removeFirst(); // Arrayy['foo' => 'foo']
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function removeFirst(): self
    {
        $tmpArray = $this->toArray();

        \array_shift($tmpArray);

        return static::create(
            $tmpArray,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Remove the last value from the current array.
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->removeLast(); // Arrayy[1 => 'bar']
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function removeLast(): self
    {
        $tmpArray = $this->toArray();

        \array_pop($tmpArray);

        return static::create(
            $tmpArray,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Removes a particular value from an array (numeric or associative).
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->removeValue('foo'); // Arrayy[1 => 'bar']
     * </code>
     *
     * @param mixed $value
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  T $value
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function removeValue($value): self
    {
        $this->generatorToArray();

        // init
        $isSequentialArray = $this->isSequential();

        foreach ($this->array as $key => $item) {
            if ($item === $value) {
                unset($this->array[$key]);
            }
        }

        if ($isSequentialArray) {
            $this->array = \array_values($this->array);
        }

        return static::create(
            $this->array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Generate array of repeated arrays.
     *
     * @param int $times <p>How many times has to be repeated.</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function repeat($times): self
    {
        if ($times === 0) {
            return static::create([], $this->iteratorClass);
        }

        return static::create(
            \array_fill(0, (int) $times, $this->toArray()),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Replace a key with a new key/value pair.
     *
     * EXAMPLE: <code>
     * $arrayy = a([1 => 'foo', 2 => 'foo2', 3 => 'bar']);
     * $arrayy->replace(2, 'notfoo', 'notbar'); // Arrayy[1 => 'foo', 'notfoo' => 'notbar', 3 => 'bar']
     * </code>
     *
     * @param mixed $oldKey
     * @param mixed $newKey
     * @param mixed $newValue
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param TKey $oldKey
     * @phpstan-param TKey $newKey
     * @phpstan-param T $newValue
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replace($oldKey, $newKey, $newValue): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        return $that->remove($oldKey)
            ->set($newKey, $newValue);
    }

    /**
     * Create an array using the current array as values and the other array as keys.
     *
     * EXAMPLE: <code>
     * $firstArray = [
     *     1 => 'one',
     *     2 => 'two',
     *     3 => 'three',
     * ];
     * $secondArray = [
     *     'one' => 1,
     *     1     => 'one',
     *     2     => 2,
     * ];
     * $arrayy = a($firstArray);
     * $arrayy->replaceAllKeys($secondArray); // Arrayy[1 => "one", 'one' => "two", 2 => "three"]
     * </code>
     *
     * @param int[]|string[] $keys <p>An array of keys.</p>
     *
     * @return static
     *                <p>(Immutable) Arrayy object with keys from the other array, empty Arrayy object if the number of elements
     *                for each array isn't equal or if the arrays are empty.
     *                </p>
     *
     * @phpstan-param  array<TKey> $keys
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replaceAllKeys(array $keys): self
    {
        $data = \array_combine($keys, $this->toArray());
        /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */
        if ($data === false) {
            $data = [];
        }

        return static::create(
            $data,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Create an array using the current array as keys and the other array as values.
     *
     * EXAMPLE: <code>
     * $firstArray = [
     *     1 => 'one',
     *     2 => 'two',
     *     3 => 'three',
     * ];
     * $secondArray = [
     *     'one' => 1,
     *     1     => 'one',
     *     2     => 2,
     * ];
     * $arrayy = a($firstArray);
     * $arrayy->replaceAllValues($secondArray); // Arrayy['one' => 1, 'two' => 'one', 'three' => 2]
     * </code>
     *
     * @param array $array <p>An array of values.</p>
     *
     * @return static
     *                <p>(Immutable) Arrayy object with values from the other array, empty Arrayy object if the number of elements
     *                for each array isn't equal or if the arrays are empty.
     *                </p>
     *
     * @phpstan-param  array<T> $array
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replaceAllValues(array $array): self
    {
        $data = \array_combine($this->toArray(), $array);
        /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */
        if ($data === false) {
            $data = [];
        }

        return static::create(
            $data,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Replace the keys in an array with another set.
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->replaceKeys([1 => 2, 'foo' => 'replaced']); // Arrayy[2 => 'bar', 'replaced' => 'foo']
     * </code>
     *
     * @param array $keys <p>An array of keys matching the array's size.</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey> $keys
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replaceKeys(array $keys): self
    {
        $values = \array_values($this->toArray());
        $result = \array_combine($keys, $values);
        /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */
        if ($result === false) {
            $result = [];
        }

        return static::create(
            $result,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Replace the first matched value in an array.
     *
     * EXAMPLE: <code>
     * $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar'];
     * a($testArray)->replaceOneValue('foo', 'replaced'); // Arrayy['bar', 'foo' => 'replaced', 'foobar' => 'foobar']
     * </code>
     *
     * @param mixed $search      <p>The value to replace.</p>
     * @param mixed $replacement <p>The value to replace.</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param T $search
     * @phpstan-param T $replacement
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replaceOneValue($search, $replacement = ''): self
    {
        $array = $this->toArray();
        $key = \array_search($search, $array, true);

        if ($key !== false) {
            $array[$key] = $replacement;
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Replace values in the current array.
     *
     * EXAMPLE: <code>
     * $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar'];
     * a($testArray)->replaceValues('foo', 'replaced'); // Arrayy['bar', 'foo' => 'replaced', 'foobar' => 'replacedbar']
     * </code>
     *
     * @param string $search      <p>The value to replace.</p>
     * @param string $replacement <p>What to replace it with.</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function replaceValues($search, $replacement = ''): self
    {
        $callable = static function ($value) use ($search, $replacement) {
            return \str_replace($search, $replacement, $value);
        };

        /* @phpstan-ignore-next-line | ignore Closure with one or two parameters, is this a bug in phpstan? */
        return $this->each($callable);
    }

    /**
     * Get the last elements from index $from until the end of this array.
     *
     * EXAMPLE: <code>
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->rest(2); // Arrayy[0 => 'lall']
     * </code>
     *
     * @param int $from
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function rest(int $from = 1): self
    {
        $tmpArray = $this->toArray();

        return static::create(
            \array_splice($tmpArray, $from),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Return the array in the reverse order.
     *
     * EXAMPLE: <code>
     * a([1 => 1, 2 => 2, 3 => 3])->reverse(); // self[3, 2, 1]
     * </code>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function reverse(): self
    {
        $this->generatorToArray();

        $this->array = \array_reverse($this->array);

        return $this;
    }

    /**
     * Return the array with keys in the reverse order.
     *
     * EXAMPLE: <code>
     * a([1 => 1, 2 => 2, 3 => 3])->reverse(); // self[3 => 3, 2 => 2, 1 => 1]
     * </code>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function reverseKeepIndex(): self
    {
        $this->generatorToArray();

        $this->array = \array_reverse($this->array, true);

        return $this;
    }

    /**
     * Sort an array in reverse order.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function rsort(int $sort_flags = 0): self
    {
        $this->generatorToArray();

        \rsort($this->array, $sort_flags);

        return $this;
    }

    /**
     * Sort an array in reverse order.
     *
     * @param int $sort_flags [optional] <p>
     *                        You may modify the behavior of the sort using the optional
     *                        parameter sort_flags, for details
     *                        see sort.
     *                        </p>
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function rsortImmutable(int $sort_flags = 0): self
    {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->rsort($sort_flags);

        return $that;
    }

    /**
     * Search for the first index of the current array via $value.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř', 'lall' => 'bàř'])->searchIndex('bàř'); // Arrayy[0 => 'fòô']
     * </code>
     *
     * @param mixed $value
     *
     * @return false|int|string
     *                          <p>Will return <b>FALSE</b> if the value can't be found.</p>
     *
     * @phpstan-param T $value
     * @phpstan-return false|TKey
     *
     * @psalm-mutation-free
     */
    public function searchIndex($value)
    {
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
            if ($value === $valueFromArray) {
                return $keyFromArray;
            }
        }

        return false;
    }

    /**
     * Search for the value of the current array via $index.
     *
     * EXAMPLE: <code>
     * a(['fòô' => 'bàř'])->searchValue('fòô'); // Arrayy[0 => 'bàř']
     * </code>
     *
     * @param mixed $index
     *
     * @return static
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
     *
     * @phpstan-param TKey $index
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function searchValue($index): self
    {
        $this->generatorToArray();

        // init
        $return = [];

        if ($this->array === []) {
            return static::create(
                [],
                $this->iteratorClass,
                false
            );
        }

        // php cast "bool"-index into "int"-index
        /* @phpstan-ignore-next-line | array-key helper */
        if ((bool) $index === $index) {
            $index = (int) $index;
        }

        if ($this->offsetExists($index)) {
            $return = [$this->array[$index]];
        }

        return static::create(
            $return,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Set a value for the current array (optional using dot-notation).
     *
     * EXAMPLE: <code>
     * $arrayy = a(['Lars' => ['lastname' => 'Moelleken']]);
     * $arrayy->set('Lars.lastname', 'Müller'); // Arrayy['Lars', ['lastname' => 'Müller']]]
     * </code>
     *
     * @param string $key   <p>The key to set.</p>
     * @param mixed  $value <p>Its value.</p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  TKey $key
     * @phpstan-param  T $value
     * @phpstan-return static<TKey,T>
     */
    public function set($key, $value): self
    {
        $this->internalSet($key, $value);

        return $this;
    }

    /**
     * Get a value from a array and set it if it was not.
     *
     * WARNING: this method only set the value, if the $key is not already set
     *
     * EXAMPLE: <code>
     * $arrayy = a([1 => 1, 2 => 2, 3 => 3]);
     * $arrayy->setAndGet(1, 4); // 1
     * $arrayy->setAndGet(0, 4); // 4
     * </code>
     *
     * @param mixed $key      <p>The key</p>
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
     *
     * @return mixed
     *               <p>(Mutable)</p>
     *
     * @phpstan-param TKey $key
     * @phpstan-param T $fallback
     */
    public function setAndGet($key, $fallback = null)
    {
        $this->generatorToArray();

        // If the key doesn't exist, set it.
        if (!$this->has($key)) {
            $this->array = $this->set($key, $fallback)->toArray();
        }

        return $this->get($key);
    }

    /**
     * Shifts a specified value off the beginning of array.
     *
     * @return mixed|null
     *                    <p>(Mutable) A shifted element from the current array.</p>
     *
     * @phpstan-return T|null
     */
    public function shift()
    {
        $this->generatorToArray();

        return \array_shift($this->array);
    }

    /**
     * Shuffle the current array.
     *
     * EXAMPLE: <code>
     * a([1 => 'bar', 'foo' => 'foo'])->shuffle(); // e.g.: Arrayy[['foo' => 'foo', 1 => 'bar']]
     * </code>
     *
     * @param bool       $secure <p>using a CSPRNG | @see https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
     * @param array|null $array  [optional]
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<TKey,T> $array
     * @phpstan-return static<TKey,T>
     */
    public function shuffle(bool $secure = false, array $array = null): self
    {
        if ($array === null) {
            $array = $this->toArray(false);
        }

        if ($secure !== true) {
            \shuffle($array);
        } else {
            $size = \count($array, \COUNT_NORMAL);
            $keys = \array_keys($array);
            for ($i = $size - 1; $i > 0; --$i) {
                try {
                    $r = \random_int(0, $i);
                } catch (\Exception $e) {
                    /** @noinspection RandomApiMigrationInspection - "random_int" is already in use */
                    $r = \mt_rand(0, $i);
                }
                if ($r !== $i) {
                    $temp = $array[$keys[$r]];
                    $array[$keys[$r]] = $array[$keys[$i]];
                    $array[$keys[$i]] = $temp;
                }
            }
        }

        foreach ($array as $key => $value) {
            // check if recursive is needed
            if (\is_array($value)) {
                /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
                /** @phpstan-var array<TKey,T> $value */
                $value = $value;

                $array[$key] = $this->shuffle($secure, $value);
            }
        }

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Count the values from the current array.
     *
     * alias: for "Arrayy->count()"
     *
     * @param int $mode
     *
     * @return int
     */
    public function size(int $mode = \COUNT_NORMAL): int
    {
        return $this->count($mode);
    }

    /**
     * Checks whether array has exactly $size items.
     *
     * @param int $size
     *
     * @return bool
     */
    public function sizeIs(int $size): bool
    {
        // init
        $itemsTempCount = 0;

        /** @noinspection PhpUnusedLocalVariableInspection */
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
        foreach ($this->getGeneratorByReference() as &$value) {
            ++$itemsTempCount;
            if ($itemsTempCount > $size) {
                return false;
            }
        }

        return $itemsTempCount === $size;
    }

    /**
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
     * smaller than $fromSize.
     *
     * @param int $fromSize
     * @param int $toSize
     *
     * @return bool
     */
    public function sizeIsBetween(int $fromSize, int $toSize): bool
    {
        if ($fromSize > $toSize) {
            $tmp = $toSize;
            $toSize = $fromSize;
            $fromSize = $tmp;
        }

        // init
        $itemsTempCount = 0;

        /** @noinspection PhpUnusedLocalVariableInspection */
        foreach ($this->getGenerator() as $value) {
            ++$itemsTempCount;
            if ($itemsTempCount > $toSize) {
                return false;
            }
        }

        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
    }

    /**
     * Checks whether array has more than $size items.
     *
     * @param int $size
     *
     * @return bool
     */
    public function sizeIsGreaterThan(int $size): bool
    {
        // init
        $itemsTempCount = 0;

        /** @noinspection PhpUnusedLocalVariableInspection */
        foreach ($this->getGenerator() as $value) {
            ++$itemsTempCount;
            if ($itemsTempCount > $size) {
                return true;
            }
        }

        return $itemsTempCount > $size;
    }

    /**
     * Checks whether array has less than $size items.
     *
     * @param int $size
     *
     * @return bool
     */
    public function sizeIsLessThan(int $size): bool
    {
        // init
        $itemsTempCount = 0;

        /** @noinspection PhpUnusedLocalVariableInspection */
        foreach ($this->getGenerator() as $value) {
            ++$itemsTempCount;
            if ($itemsTempCount > $size) {
                return false;
            }
        }

        return $itemsTempCount < $size;
    }

    /**
     * Counts all elements in an array, or something in an object.
     *
     * <p>
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
     * implemented and used in PHP.
     * </p>
     *
     * @return int
     *             <p>
     *             The number of elements in var, which is
     *             typically an array, since anything else will have one
     *             element.
     *             </p>
     *             <p>
     *             If var is not an array or an object with
     *             implemented Countable interface,
     *             1 will be returned.
     *             There is one exception, if var is &null;,
     *             0 will be returned.
     *             </p>
     *             <p>
     *             Caution: count may return 0 for a variable that isn't set,
     *             but it may also return 0 for a variable that has been initialized with an
     *             empty array. Use isset to test if a variable is set.
     *             </p>
     */
    public function sizeRecursive(): int
    {
        return \count($this->toArray(), \COUNT_RECURSIVE);
    }

    /**
     * Extract a slice of the array.
     *
     * @param int      $offset       <p>Slice begin index.</p>
     * @param int|null $length       <p>Length of the slice.</p>
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
     *
     * @return static
     *                <p>(Immutable) A slice of the original array with length $length.</p>
     *
     * @phpstan-return static<array-key,T>
     * @psalm-mutation-free
     */
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
    {
        return static::create(
            \array_slice(
                $this->toArray(),
                $offset,
                $length,
                $preserveKeys
            ),
            $this->iteratorClass,
            false
        );
    }

    /**
     * Sort the current array and optional you can keep the keys.
     *
     * EXAMPLE: <code>
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sort(SORT_ASC, SORT_NATURAL, false); // Arrayy[0 => 'a', 1 => 'd', 2 => 'f']
     * </code>
     *
     * @param int|string $direction
     *                              <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy
     *                              <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     * @param bool       $keepKeys
     *
     * @return static
     *                <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<int|TKey,T>
     */
    public function sort(
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR,
        bool $keepKeys = false
    ): self {
        $this->generatorToArray();

        return $this->sorting(
            $this->array,
            $direction,
            $strategy,
            $keepKeys
        );
    }

    /**
     * Sort the current array and optional you can keep the keys.
     *
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     * @param bool       $keepKeys
     *
     * @return static
     *                <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<int|TKey,T>
     */
    public function sortImmutable(
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR,
        bool $keepKeys = false
    ): self {
        $that = clone $this;

        $that->generatorToArray();

        return $that->sorting(
            $that->array,
            $direction,
            $strategy,
            $keepKeys
        );
    }

    /**
     * Sort the current array by key.
     *
     * EXAMPLE: <code>
     * a([1 => 2, 0 => 1])->sortKeys(\SORT_ASC); // Arrayy[0 => 1, 1 => 2]
     * </code>
     *
     * @see http://php.net/manual/en/function.ksort.php
     * @see http://php.net/manual/en/function.krsort.php
     *
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function sortKeys(
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR
    ): self {
        $this->generatorToArray();

        $this->sorterKeys($this->array, $direction, $strategy);

        return $this;
    }

    /**
     * Sort the current array by key.
     *
     * @see          http://php.net/manual/en/function.ksort.php
     * @see          http://php.net/manual/en/function.krsort.php
     *
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     *
     * @return $this
     *               <p>(Immutable) Return this Arrayy object.</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function sortKeysImmutable(
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR
    ): self {
        $that = clone $this;

        /**
         * @psalm-suppress ImpureMethodCall - object is already cloned
         */
        $that->sortKeys($direction, $strategy);

        return $that;
    }

    /**
     * Sort the current array by value.
     *
     * EXAMPLE: <code>
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sortValueKeepIndex(SORT_ASC, SORT_REGULAR); // Arrayy[0 => 'a', 3 => 'd', 2 => 'f']
     * </code>
     *
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     *
     * @return static
     *                <p>(Mutable)</p>
     *
     * @phpstan-return static<int|TKey,T>
     */
    public function sortValueKeepIndex(
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR
    ): self {
        return $this->sort($direction, $strategy, true);
    }

    /**
     * Sort the current array by value.
     *
     * EXAMPLE: <code>
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sortValueNewIndex(SORT_ASC, SORT_NATURAL); // Arrayy[0 => 'a', 1 => 'd', 2 => 'f']
     * </code>
     *
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     *
     * @return static
     *                <p>(Mutable)</p>
     *
     * @phpstan-return static<int|TKey,T>
     */
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
    {
        return $this->sort($direction, $strategy, false);
    }

    /**
     * Sort a array by value or by a closure.
     *
     * - If the sorter is null, the array is sorted naturally.
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
     *
     * EXAMPLE: <code>
     * $testArray = range(1, 5);
     * $under = a($testArray)->sorter(
     *     function ($value) {
     *         return $value % 2 === 0;
     *     }
     * );
     * var_dump($under); // Arrayy[1, 3, 5, 2, 4]
     * </code>
     *
     * @param callable|mixed|null $sorter
     * @param int|string          $direction <p>use <strong>SORT_ASC</strong> (default) or
     *                                       <strong>SORT_DESC</strong></p>
     * @param int                 $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                                       <strong>SORT_NATURAL</strong></p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @pslam-param callable|T|null $sorter
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
    {
        $array = $this->toArray();
        $direction = $this->getDirection($direction);

        // Transform all values into their results.
        if ($sorter) {
            $arrayy = static::create(
                $array,
                $this->iteratorClass,
                false
            );

            /**
             * @psalm-suppress MissingClosureReturnType
             * @psalm-suppress MissingClosureParamType
             */
            $results = $arrayy->each(
                static function ($value) use ($sorter) {
                    if (\is_callable($sorter) === true) {
                        return $sorter($value);
                    }

                    return $sorter === $value;
                }
            );

            $results = $results->toArray();
        } else {
            $results = $array;
        }

        // Sort by the results and replace by original values
        \array_multisort($results, $direction, $strategy, $array);

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * @param int      $offset
     * @param int|null $length
     * @param array    $replacement
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-param  array<T> $replacement
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function splice(int $offset, int $length = null, $replacement = []): self
    {
        $tmpArray = $this->toArray();

        \array_splice(
            $tmpArray,
            $offset,
            $length ?? $this->count(),
            $replacement
        );

        return static::create(
            $tmpArray,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Split an array in the given amount of pieces.
     *
     * EXAMPLE: <code>
     * a(['a' => 1, 'b' => 2])->split(2, true); // Arrayy[['a' => 1], ['b' => 2]]
     * </code>
     *
     * @param int  $numberOfPieces
     * @param bool $keepKeys
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
    {
        if ($keepKeys) {
            $generator = function () use ($numberOfPieces) {
                $carry = [];
                $i = 1;
                foreach ($this->getGenerator() as $key => $value) {
                    $carry[$key] = $value;

                    if ($i % $numberOfPieces !== 0) {
                        ++$i;

                        continue;
                    }

                    yield $carry;

                    $carry = [];
                    $i = 1;
                }

                if ($carry !== []) {
                    yield $carry;
                }
            };
        } else {
            $generator = function () use ($numberOfPieces) {
                $carry = [];
                $i = 1;
                foreach ($this->getGenerator() as $value) {
                    $carry[] = $value;

                    if ($i % $numberOfPieces !== 0) {
                        ++$i;

                        continue;
                    }

                    yield $carry;

                    $carry = [];
                    $i = 1;
                }

                if ($carry !== []) {
                    yield $carry;
                }
            };
        }

        return static::create(
            $generator,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Strip all empty items from the current array.
     *
     * EXAMPLE: <code>
     * a(['a' => 1, 'b' => ''])->stripEmpty(); // Arrayy[['a' => 1]]
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function stripEmpty(): self
    {
        return $this->filter(
            static function ($item) {
                if ($item === null) {
                    return false;
                }

                return (bool) \trim((string) $item);
            }
        );
    }

    /**
     * Swap two values between positions by key.
     *
     * EXAMPLE: <code>
     * a(['a' => 1, 'b' => ''])->swap('a', 'b'); // Arrayy[['a' => '', 'b' => 1]]
     * </code>
     *
     * @param int|string $swapA <p>a key in the array</p>
     * @param int|string $swapB <p>a key in the array</p>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<TKey,T>
     * @psalm-mutation-free
     */
    public function swap($swapA, $swapB): self
    {
        $array = $this->toArray();

        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];

        return static::create(
            $array,
            $this->iteratorClass,
            false
        );
    }

    /**
     * Get the current array from the "Arrayy"-object.
     * alias for "getArray()"
     *
     * @param bool $convertAllArrayyElements <p>
     *                                       Convert all Child-"Arrayy" objects also to arrays.
     *                                       </p>
     * @param bool $preserveKeys             <p>
     *                                       e.g.: A generator maybe return the same key more than once,
     *                                       so maybe you will ignore the keys.
     *                                       </p>
     *
     * @return array
     *
     * @phpstan-return ($preserveKeys is true ? array<TKey,T> : T[])
     * @psalm-mutation-free
     */
    public function toArray(
        bool $convertAllArrayyElements = false,
        bool $preserveKeys = true
    ): array {
        if ($convertAllArrayyElements) {
            // init
            $array = [];

            foreach ($this->getGenerator() as $key => $value) {
                if ($value instanceof self) {
                    $value = $value->toArray(
                        $convertAllArrayyElements,
                        $preserveKeys
                    );
                }

                if ($preserveKeys) {
                    $array[$key] = $value;
                } else {
                    $array[] = $value;
                }
            }

            /* @phpstan-ignore-next-line - depends on the $convertAllArrayyElements parameter :/ */
            return $array;
        }

        return \iterator_to_array($this->getGenerator(), $preserveKeys);
    }

    /**
     * Get the current array from the "Arrayy"-object as list.
     *
     * @param bool $convertAllArrayyElements <p>
     *                                       Convert all Child-"Arrayy" objects also to arrays.
     *                                       </p>
     *
     * @return array
     *
     * @phpstan-return list<T>
     * @psalm-mutation-free
     */
    public function toList(bool $convertAllArrayyElements = false): array
    {
        /** @var list<T> - currently phpstan can't return different types depending on the phpdocs params */
        return $this->toArray(
            $convertAllArrayyElements,
            false
        );
    }

    /**
     * Convert the current array to JSON.
     *
     * EXAMPLE: <code>
     * a(['bar', ['foo']])->toJson(); // '["bar",{"1":"foo"}]'
     * </code>
     *
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
     *
     * @return string
     */
    public function toJson(int $options = 0, int $depth = 512): string
    {
        if ($depth < 1) {
            $depth = 1;
        }

        $return = \json_encode($this->toArray(), $options, $depth);
        if ($return === false) {
            return '';
        }

        return $return;
    }

    /**
     * @param string[]|null $items  [optional]
     * @param string[]      $helper [optional]
     *
     * @return static|static[]
     *
     * @phpstan-return static<int, static<TKey,T>>
     */
    public function toPermutation(array $items = null, array $helper = []): self
    {
        // init
        $return = [];

        if ($items === null) {
            $items = $this->toArray();
        }

        if (empty($items)) {
            $return[] = $helper;
        } else {
            for ($i = \count($items) - 1; $i >= 0; --$i) {
                $new_items = $items;
                $new_helper = $helper;
                list($tmp_helper) = \array_splice($new_items, $i, 1);
                /** @noinspection PhpSillyAssignmentInspection */
                /** @var string[] $new_items */
                $new_items = $new_items;
                \array_unshift($new_helper, $tmp_helper);
                $return = \array_merge(
                    $return,
                    $this->toPermutation($new_items, $new_helper)->toArray()
                );
            }
        }

        /** @var static<int, static<TKey,T>> $return  - help for phpstan */
        $return = static::create(
            $return,
            $this->iteratorClass,
            false
        );

        return $return;
    }

    /**
     * Implodes array to a string with specified separator.
     *
     * @param string $separator [optional] <p>The element's separator.</p>
     *
     * @return string
     *                <p>The string representation of array, separated by ",".</p>
     */
    public function toString(string $separator = ','): string
    {
        return $this->implode($separator);
    }

    /**
     * Return a duplicate free copy of the current array.
     *
     * EXAMPLE: <code>
     * a([2 => 1, 3 => 2, 4 => 2])->uniqueNewIndex(); // Arrayy[1, 2]
     * </code>
     *
     * @return $this
     *               <p>(Mutable)</p>
     *
     * @phpstan-return static<int,T>
     */
    public function uniqueNewIndex(): self
    {
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array

        $this->array = $this->reduce(
            static function ($resultArray, $value, $key) {
                if (!\in_array($value, $resultArray, true)) {
                    $resultArray[] = $value;
                }

                return $resultArray;
            },
            []
        )->toArray();
        $this->generator = null;

        return $this;
    }

    /**
     * Return a duplicate free copy of the current array. (with the old keys)
     *
     * EXAMPLE: <code>
     * a([2 => 1, 3 => 2, 4 => 2])->uniqueNewIndex(); // Arrayy[2 => 1, 3 => 2]
     * </code>
     *
     * @return $this
     *               <p>(Mutable)</p>
     *
     * @phpstan-return static<TKey,T>
     */
    public function uniqueKeepIndex(): self
    {
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array

        // init
        $array = $this->toArray();

        /**
         * @psalm-suppress MissingClosureReturnType
         * @psalm-suppress MissingClosureParamType
         */
        $this->array = \array_reduce(
            \array_keys($array),
            static function ($resultArray, $key) use ($array) {
                if (!\in_array($array[$key], $resultArray, true)) {
                    $resultArray[$key] = $array[$key];
                }

                return $resultArray;
            },
            []
        );
        $this->generator = null;

        return $this;
    }

    /**
     * alias: for "Arrayy->uniqueNewIndex()"
     *
     * @return static
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
     *
     * @see          Arrayy::unique()
     *
     * @phpstan-return static<int,T>
     */
    public function unique(): self
    {
        return $this->uniqueNewIndex();
    }

    /**
     * Prepends one or more values to the beginning of array at once.
     *
     * @param mixed ...$args
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
     *
     * @phpstan-param  array<TKey,T> ...$args
     * @phpstan-return static<TKey,T>
     */
    public function unshift(...$args): self
    {
        $this->generatorToArray();

        if (
            $this->checkPropertyTypes
            &&
            $this->properties !== []
        ) {
            foreach ($args as $key => $value) {
                $this->checkType($key, $value);
            }
        }

        \array_unshift($this->array, ...$args);

        return $this;
    }

    /**
     * Tests whether the given closure return something valid for all elements of this array.
     *
     * @param \Closure $closure the predicate
     *
     * @return bool
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function validate(\Closure $closure): bool
    {
        foreach ($this->getGenerator() as $key => $value) {
            if (!$closure($value, $key)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get all values from a array.
     *
     * EXAMPLE: <code>
     * $arrayy = a([1 => 'foo', 2 => 'foo2', 3 => 'bar']);
     * $arrayyTmp->values(); // Arrayy[0 => 'foo', 1 => 'foo2', 2 => 'bar']
     * </code>
     *
     * @return static
     *                <p>(Immutable)</p>
     *
     * @phpstan-return static<int,T>
     * @psalm-mutation-free
     */
    public function values(): self
    {
        return static::create(
            function () {
                foreach ($this->getGenerator() as $value) {
                    yield $value;
                }
            },
            $this->iteratorClass,
            false
        );
    }

    /**
     * Apply the given function to every element in the array, discarding the results.
     *
     * EXAMPLE: <code>
     * $callable = function (&$value, $key) {
     *     $value = $key;
     * };
     * $arrayy = a([1, 2, 3]);
     * $arrayy->walk($callable); // Arrayy[0, 1, 2]
     * </code>
     *
     * @param callable $callable
     * @param bool     $recursive
     *                            [optional] <p>Whether array will be walked recursively or no</p>
     * @param mixed    $userData
     *                            [optional] <p>
     *                            If the optional $userData parameter is supplied,
     *                            it will be passed as the third parameter to the $callable.
     *                            </p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object, with modified elements.</p>
     *
     * @template TExtra
     *              <p>The extra input value type.</p>
     *
     * @phostan-param TExtra $userData
     * @phpstan-param  callable(T,TKey,?TExtra):void $callable
     * @phpstan-return static<TKey,T>
     */
    public function walk(
        $callable,
        bool $recursive = false,
        $userData = self::ARRAYY_HELPER_WALK
    ): self {
        $this->generatorToArray();

        if ($this->array !== []) {
            if ($recursive === true) {
                if ($userData !== self::ARRAYY_HELPER_WALK) {
                    \array_walk_recursive($this->array, $callable, $userData);
                } else {
                    \array_walk_recursive($this->array, $callable);
                }
            } else {
                if ($userData !== self::ARRAYY_HELPER_WALK) {
                    \array_walk($this->array, $callable, $userData);
                } else {
                    /* @phpstan-ignore-next-line | callback with no arguments is ok here */
                    \array_walk($this->array, $callable);
                }
            }
        }

        return $this;
    }

    /**
     * Returns a collection of matching items.
     *
     * @param string $keyOrPropertyOrMethod
     *                                      <p>The property or method to evaluate.</p>
     * @param mixed  $value
     *                                      <p>The value to match.</p>
     *
     * @throws \InvalidArgumentException if property or method is not defined
     *
     * @return static
     *
     * @phpstan-return static<TKey,T>
     */
    public function where(string $keyOrPropertyOrMethod, $value): self
    {
        return $this->filter(
            function ($item) use ($keyOrPropertyOrMethod, $value) {
                $accessorValue = $this->extractValue(
                    $item,
                    $keyOrPropertyOrMethod
                );

                return $accessorValue === $value;
            }
        );
    }

    /**
     * Convert an array into an object.
     *
     * @param array $array
     *
     * @return \stdClass
     *
     * @phpstan-param array<int|string,mixed> $array
     */
    final protected static function arrayToObject(array $array = []): \stdClass
    {
        // init
        $object = new \stdClass();

        if (\count($array, \COUNT_NORMAL) <= 0) {
            return $object;
        }

        foreach ($array as $name => $value) {
            if (\is_array($value)) {
                $object->{$name} = static::arrayToObject($value);
            } else {
                $object->{$name} = $value;
            }
        }

        return $object;
    }

    /**
     * @param array|\Generator|null $input         <p>
     *                                             An array containing keys to return.
     *                                             </p>
     * @param mixed|null            $search_values [optional] <p>
     *                                             If specified, then only keys containing these values are returned.
     *                                             </p>
     * @param bool                  $strict        [optional] <p>
     *                                             Determines if strict comparison (===) should be used during the
     *                                             search.
     *                                             </p>
     *
     * @return array
     *               <p>An array of all the keys in input.</p>
     *
     * @template TInput
     *
     * @phpstan-param  array<array-key,TInput>|\Generator<array-key,TInput>|null $input
     * @phpstan-param T|T[]|null $search_values
     * @phpstan-return array<int, TKey>
     *
     * @psalm-mutation-free
     */
    protected function array_keys_recursive(
        $input = null,
        $search_values = null,
        bool $strict = true
    ): array {
        // init
        $keys = [];
        $keysTmp = [];

        if ($input === null) {
            $input = $this->getGenerator();
        }

        if ($search_values === null) {
            foreach ($input as $key => $value) {
                $keys[] = $key;

                // check if recursive is needed
                if (\is_array($value)) {
                    $keysTmp[] = $this->array_keys_recursive($value);
                }
            }
        } else {
            $is_array_tmp = \is_array($search_values);

            foreach ($input as $key => $value) {
                if (
                    (
                        $is_array_tmp === false
                        &&
                        $strict === true
                        &&
                        $search_values === $value
                    )
                    ||
                    (
                        $is_array_tmp === false
                        &&
                        $strict === false
                        &&
                        $search_values == $value
                    )
                    ||
                    (
                        $is_array_tmp === true
                        &&
                        \in_array($value, $search_values, $strict)
                    )
                ) {
                    $keys[] = $key;
                }

                // check if recursive is needed
                if (\is_array($value)) {
                    $keysTmp[] = $this->array_keys_recursive($value);
                }
            }
        }

        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
    }

    /**
     * @param string     $path
     * @param callable   $callable
     * @param array|null $currentOffset
     *
     * @return void
     *
     * @phpstan-param array<TKey,T>|null $currentOffset
     * @psalm-mutation-free
     */
    protected function callAtPath($path, $callable, &$currentOffset = null)
    {
        $this->generatorToArray();

        if ($currentOffset === null) {
            $currentOffset = &$this->array;
        }

        $explodedPath = \explode($this->pathSeparator, $path);
        /* @phpstan-ignore-next-line | change from PHP >= 8, but we still support old versions */
        if ($explodedPath === false) {
            return;
        }

        $nextPath = \array_shift($explodedPath);
        if (!isset($currentOffset[$nextPath])) {
            return;
        }

        if ($explodedPath !== []) {
            $this->callAtPath(
                \implode($this->pathSeparator, $explodedPath),
                $callable,
                $currentOffset[$nextPath]
            );
        } else {
            $callable($currentOffset[$nextPath]);
        }
    }

    /**
     * Extracts the value of the given property or method from the object.
     *
     * @param static<T> $object
     *                                         <p>The object to extract the value from.</p>
     * @param string    $keyOrPropertyOrMethod
     *                                         <p>The property or method for which the
     *                                         value should be extracted.</p>
     *
     * @throws \InvalidArgumentException if the method or property is not defined
     *
     * @return mixed
     *               <p>The value extracted from the specified property or method.</p>
     *
     * @phpstan-param self<TKey,T> $object
     */
    final protected function extractValue(self $object, string $keyOrPropertyOrMethod)
    {
        if (isset($object[$keyOrPropertyOrMethod])) {
            $return = $object->get($keyOrPropertyOrMethod);

            if ($return instanceof self) {
                return $return->toArray();
            }

            return $return;
        }

        if (\property_exists($object, $keyOrPropertyOrMethod)) {
            return $object->{$keyOrPropertyOrMethod};
        }

        if (\method_exists($object, $keyOrPropertyOrMethod)) {
            return $object->{$keyOrPropertyOrMethod}();
        }

        throw new \InvalidArgumentException(\sprintf('array-key & property & method "%s" not defined in %s', $keyOrPropertyOrMethod, \gettype($object)));
    }

    /**
     * create a fallback for array
     *
     * 1. use the current array, if it's a array
     * 2. fallback to empty array, if there is nothing
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
     * 5. call "__toArray()" on object, if the method exists
     * 6. cast a string or object with "__toString()" into an array
     * 7. throw a "InvalidArgumentException"-Exception
     *
     * @param mixed $data
     *
     * @throws \InvalidArgumentException
     *
     * @return array
     *
     * @phpstan-return array<mixed>|array<TKey,T>
     */
    protected function fallbackForArray(&$data): array
    {
        $data = $this->internalGetArray($data);

        if ($data === null) {
            throw new \InvalidArgumentException('Passed value should be a array');
        }

        return $data;
    }

    /**
     * @param bool $preserveKeys <p>
     *                           e.g.: A generator maybe return the same key more than once,
     *                           so maybe you will ignore the keys.
     *                           </p>
     *
     * @return bool
     *
     * @noinspection ReturnTypeCanBeDeclaredInspection
     * @psalm-mutation-free :/
     */
    protected function generatorToArray(bool $preserveKeys = true)
    {
        if ($this->generator) {
            $this->array = $this->toArray(false, $preserveKeys);
            $this->generator = null;

            return true;
        }

        return false;
    }

    /**
     * Get correct PHP constant for direction.
     *
     * @param int|string $direction
     *
     * @return int
     * @psalm-mutation-free
     */
    protected function getDirection($direction): int
    {
        if ((string) $direction === $direction) {
            $direction = \strtolower($direction);

            if ($direction === 'desc') {
                $direction = \SORT_DESC;
            } else {
                $direction = \SORT_ASC;
            }
        }

        if (
            $direction !== \SORT_DESC
            &&
            $direction !== \SORT_ASC
        ) {
            $direction = \SORT_ASC;
        }

        return $direction;
    }

    /**
     * @return TypeCheckInterface[]
     *
     * @noinspection ReturnTypeCanBeDeclaredInspection
     */
    protected function getPropertiesFromPhpDoc()
    {
        static $PROPERTY_CACHE = [];
        $cacheKey = 'Class::' . static::class;

        if (isset($PROPERTY_CACHE[$cacheKey])) {
            return $PROPERTY_CACHE[$cacheKey];
        }

        // init
        $properties = [];

        $reflector = new \ReflectionClass($this);
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
        $docComment = $reflector->getDocComment();
        if ($docComment) {
            $docblock = $factory->create($docComment);
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
            foreach ($docblock->getTagsByName('property') as $tag) {
                $typeName = $tag->getVariableName();
                /** @var string|null $typeName */
                if ($typeName !== null) {
                    $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName);
                    if ($typeCheckPhpDoc !== null) {
                        $properties[$typeName] = $typeCheckPhpDoc;
                    }
                }
            }
        }

        /** @noinspection PhpAssignmentInConditionInspection */
        while ($reflector = $reflector->getParentClass()) {
            $docComment = $reflector->getDocComment();
            if ($docComment) {
                $docblock = $factory->create($docComment);
                /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
                foreach ($docblock->getTagsByName('property') as $tag) {
                    $typeName = $tag->getVariableName();
                    /** @var string|null $typeName */
                    if ($typeName !== null) {
                        if (isset($properties[$typeName])) {
                            continue;
                        }

                        $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName);
                        if ($typeCheckPhpDoc !== null) {
                            $properties[$typeName] = $typeCheckPhpDoc;
                        }
                    }
                }
            }
        }

        return $PROPERTY_CACHE[$cacheKey] = $properties;
    }

    /**
     * @param string $glue
     * @param mixed  $pieces
     * @param bool   $useKeys
     *
     * @return string
     *
     * @phpstan-param scalar|object|self<TKey|T>|array<TKey,T>|array<T> $pieces
     * @psalm-mutation-free
     */
    protected function implode_recursive(
        $glue = '',
        $pieces = [],
        bool $useKeys = false
    ): string {
        if ($pieces instanceof self) {
            $pieces = $pieces->toArray();
        }

        if (\is_array($pieces)) {
            /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
            /** @phpstan-var array<TKey,T> $pieces */
            $pieces = $pieces;

            $pieces_count = \count($pieces, \COUNT_NORMAL);
            $pieces_count_not_zero = $pieces_count > 0;

            return \implode(
                $glue,
                \array_map(
                    [$this, 'implode_recursive'],
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
                )
            );
        }

        if (
            \is_scalar($pieces) === true
            ||
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
        ) {
            return (string) $pieces;
        }

        return '';
    }

    /**
     * @param mixed                 $needle   <p>
     *                                        The searched value.
     *                                        </p>
     *                                        <p>
     *                                        If needle is a string, the comparison is done
     *                                        in a case-sensitive manner.
     *                                        </p>
     * @param array|\Generator|null $haystack <p>
     *                                        The array.
     *                                        </p>
     * @param bool                  $strict   [optional] <p>
     *                                        If the third parameter strict is set to true
     *                                        then the in_array function will also check the
     *                                        types of the
     *                                        needle in the haystack.
     *                                        </p>
     *
     * @return bool
     *              <p>true if needle is found in the array, false otherwise</p>
     *
     * @phpstan-param (array&T)|array<TKey,T>|\Generator<TKey,T>|null $haystack
     *
     * @psalm-mutation-free
     */
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
    {
        if ($haystack === null) {
            $haystack = $this->getGenerator();
        }

        foreach ($haystack as $item) {
            if (\is_array($item)) {
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
            } else {
                /** @noinspection NestedPositiveIfStatementsInspection */
                if ($strict === true) {
                    $returnTmp = $item === $needle;
                } else {
                    $returnTmp = $item == $needle;
                }
            }

            if ($returnTmp === true) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param mixed $data
     *
     * @return array<mixed>|null
     */
    protected function internalGetArray(&$data)
    {
        if (\is_array($data)) {
            return $data;
        }

        if (!$data) {
            return [];
        }

        if (\is_object($data) === true) {
            if ($data instanceof \ArrayObject) {
                return $data->getArrayCopy();
            }

            if ($data instanceof \Generator) {
                return static::createFromGeneratorImmutable($data)->toArray();
            }

            if ($data instanceof \Traversable) {
                return static::createFromObject($data)->toArray();
            }

            if ($data instanceof \JsonSerializable) {
                return (array) $data->jsonSerialize();
            }

            if (\method_exists($data, '__toArray')) {
                return (array) $data->__toArray();
            }

            if (\method_exists($data, '__toString')) {
                return [(string) $data];
            }
        }

        if (\is_callable($data)) {
            /**
             * @psalm-suppress InvalidPropertyAssignmentValue - why?
             */
            $this->generator = new ArrayyRewindableGenerator($data);

            return [];
        }

        if (\is_scalar($data)) {
            return [$data];
        }

        return null;
    }

    /**
     * Internal mechanics of remove method.
     *
     * @param float|int|string $key
     *
     * @return bool
     */
    protected function internalRemove($key): bool
    {
        $this->generatorToArray();

        if (
            $this->pathSeparator
            &&
            (string) $key === $key
            &&
            \strpos($key, $this->pathSeparator) !== false
        ) {
            $path = \explode($this->pathSeparator, (string) $key);

            if ($path !== false) {
                // crawl though the keys
                while (\count($path, \COUNT_NORMAL) > 1) {
                    $key = \array_shift($path);

                    if (!$this->has($key)) {
                        return false;
                    }

                    $this->array = &$this->array[$key];
                }

                $key = \array_shift($path);
            }
        }

        unset($this->array[$key]);

        return true;
    }

    /**
     * Internal mechanic of set method.
     *
     * @param int|string|null $key
     * @param mixed           $value
     * @param bool            $checkProperties
     *
     * @return bool
     *
     * @phpstan-param TKey|null $key
     * @phpstan-param T $value
     */
    protected function internalSet(
        $key,
        &$value,
        bool $checkProperties = true
    ): bool {
        if (
            $checkProperties === true
            &&
            $this->properties !== []
        ) {
            $this->checkType($key, $value);
        }

        if ($key === null) {
            return false;
        }

        $this->generatorToArray();

        $array = &$this->array;

        /**
         * https://github.com/vimeo/psalm/issues/2536
         *
         * @psalm-suppress PossiblyInvalidArgument
         * @psalm-suppress InvalidScalarArgument
         */
        if (
            $this->pathSeparator
            &&
            (string) $key === $key
            &&
            \strpos($key, $this->pathSeparator) !== false
        ) {
            $path = \explode($this->pathSeparator, (string) $key);

            if ($path !== false) {
                // crawl through the keys
                while (\count($path, \COUNT_NORMAL) > 1) {
                    $key = \array_shift($path);

                    $array = &$array[$key];
                }

                $key = \array_shift($path);
            }
        }

        if ($array === null) {
            $array = [];
        } elseif (!\is_array($array)) {
            throw new \RuntimeException('Can not set value at this path "' . $key . '" because (' . \gettype($array) . ')"' . \print_r($array, true) . '" is not an array.');
        }

        $array[$key] = $value;

        return true;
    }

    /**
     * Convert a object into an array.
     *
     * @param mixed|object $object
     *
     * @return array|mixed
     *
     * @psalm-mutation-free
     */
    protected static function objectToArray($object)
    {
        if (!\is_object($object)) {
            return $object;
        }

        $object = \get_object_vars($object);

        /**
         * @psalm-suppress PossiblyInvalidArgument - the parameter is always some kind of array - false-positive from psalm?
         */
        return \array_map(['static', 'objectToArray'], $object);
    }

    /**
     * @param array $data
     * @param bool  $checkPropertiesInConstructor
     *
     * @return void
     *
     * @phpstan-param array<mixed,T> $data
     */
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
    {
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
                                        &&
                                        $checkPropertiesInConstructor === true;

        if ($this->properties === []) {
            if (
                $this->checkPropertyTypes === true
                ||
                $checkPropertiesInConstructor === true
            ) {
                $this->properties = $this->getPropertiesFromPhpDoc();
            }

            /** @var TypeCheckInterface[] $properties */
            $properties = $this->properties;

            if (
                $this->checkPropertiesMismatchInConstructor === true
                &&
                \count($data) !== 0
                &&
                \count(\array_diff_key($properties, $data)) > 0
            ) {
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($properties), true));
            }
        }

        foreach ($data as $key => &$valueInner) {
            $this->internalSet(
                $key,
                $valueInner,
                $checkPropertiesInConstructor
            );
        }
    }

    /**
     * sorting keys
     *
     * @param array      $elements
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param  array<mixed|TKey,T> $elements
     * @phpstan-return static<TKey,T>
     */
    protected function sorterKeys(
        array &$elements,
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR
    ): self {
        $direction = $this->getDirection($direction);

        switch ($direction) {
            case 'desc':
            case \SORT_DESC:
                \krsort($elements, $strategy);

                break;
            case 'asc':
            case \SORT_ASC:
            default:
                \ksort($elements, $strategy);
        }

        return $this;
    }

    /**
     * @param array      $elements  <p>Warning: used as reference</p>
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
     *                              <strong>SORT_NATURAL</strong></p>
     * @param bool       $keepKeys
     *
     * @return $this
     *               <p>(Mutable) Return this Arrayy object.</p>
     *
     * @phpstan-param array<mixed|TKey,T> $elements
     * @phpstan-return static<int|TKey,T>
     */
    protected function sorting(
        array &$elements,
        $direction = \SORT_ASC,
        int $strategy = \SORT_REGULAR,
        bool $keepKeys = false
    ): self {
        $direction = $this->getDirection($direction);

        if (!$strategy) {
            $strategy = \SORT_REGULAR;
        }

        switch ($direction) {
            case 'desc':
            case \SORT_DESC:
                if ($keepKeys) {
                    \arsort($elements, $strategy);
                } else {
                    \rsort($elements, $strategy);
                }

                break;
            case 'asc':
            case \SORT_ASC:
            default:
                if ($keepKeys) {
                    \asort($elements, $strategy);
                } else {
                    \sort($elements, $strategy);
                }
        }

        return $this;
    }

    /**
     * @param array $array
     *
     * @return array
     *
     * @psalm-mutation-free
     */
    private function getArrayRecursiveHelperArrayy(array $array)
    {
        if ($array === []) {
            return [];
        }

        \array_walk_recursive(
            $array,
            /**
             * @param array|self $item
             *
             * @return void
             */
            static function (&$item) {
                if ($item instanceof self) {
                    $item = $item->getArray();
                }
            }
        );

        return $array;
    }

    /**
     * @param int|string|null $key
     * @param mixed           $value
     *
     * @return void
     */
    private function checkType($key, $value)
    {
        if (
            $key !== null
            &&
            isset($this->properties[$key]) === false
            &&
            $this->checkPropertiesMismatch === true
        ) {
            throw new \TypeError('The key "' . $key . '" does not exists as "@property" phpdoc. (' . \get_class($this) . ').');
        }

        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
        } elseif ($key !== null && isset($this->properties[$key])) {
            $this->properties[$key]->checkType($value);
        }
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

/**
 * @template TKey of array-key
 * @template T
 * @extends \ArrayIterator<TKey,T>
 */
class ArrayyIterator extends \ArrayIterator
{
    /**
     * @var string
     *
     * @phpstan-var string|class-string<\Arrayy\Arrayy<TKey,T>>
     */
    private $class;

    /**
     * @param array<int|string,mixed> $array
     * @param int                     $flags
     * @param string                  $class
     *
     * @phpstan-param array<TKey,T> $array
     */
    public function __construct(array $array = [], int $flags = 0, string $class = '')
    {
        $this->class = $class;

        parent::__construct($array, $flags);
    }

    /**
     * @return Arrayy|mixed will return a "Arrayy"-object instead of an array
     */
    #[\ReturnTypeWillChange]
    public function current()
    {
        $value = parent::current();

        if (\is_array($value)) {
            $value = \call_user_func([$this->class, 'create'], $value, static::class, false);
        }

        return $value;
    }

    /**
     * @param string $offset
     *
     * @return Arrayy|mixed
     *                      <p>Will return a "Arrayy"-object instead of an array.</p>
     *
     * @phpstan-param TKey $offset
     * @param-return Arrayy<TKey,T>|mixed
     */
    #[\ReturnTypeWillChange]
    public function offsetGet($offset)
    {
        $value = parent::offsetGet($offset);

        if (\is_array($value)) {
            $value = \call_user_func([$this->class, 'create'], $value, static::class, false);
        }

        return $value;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

final class ArrayyMeta
{

    /** @noinspection MagicMethodsValidityInspection */

    /**
     * @param string $name
     *
     * @return string
     */
    public function __get($name): string
    {
        return '';
    }

    /**
     * @param string $className
     *
     * @return $this
     *
     * @phpstan-param class-string<\Arrayy\Arrayy<int|string,mixed>> $className
     */
    public function getMetaObject(string $className): self
    {
        static $STATIC_CACHE = [];

        $cacheKey = $className;
        if (!empty($STATIC_CACHE[$cacheKey])) {
            return $STATIC_CACHE[$cacheKey];
        }

        $reflector = new \ReflectionClass($className);
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
        $docComment = $reflector->getDocComment();
        if ($docComment) {
            $docblock = $factory->create($docComment);
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
            foreach ($docblock->getTagsByName('property') as $tag) {
                $PropertyName = $tag->getVariableName();
                $this->{$PropertyName} = $PropertyName;
            }
        }

        /** @noinspection PhpAssignmentInConditionInspection */
        while ($reflector = $reflector->getParentClass()) {
            $docComment = $reflector->getDocComment();
            if ($docComment) {
                $docblock = $factory->create($docComment);
                /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
                foreach ($docblock->getTagsByName('property') as $tag) {
                    $PropertyName = $tag->getVariableName();
                    $this->{$PropertyName} = $PropertyName;
                }
            }
        }

        $STATIC_CACHE[$cacheKey] = $this;

        return $this;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

/**
 * @template   XKey of array-key
 * @template   X
 * @extends    ArrayyRewindableGenerator<XKey,X>
 *
 * @internal
 */
class ArrayyRewindableExtendedGenerator extends ArrayyRewindableGenerator
{
    public function __construct(
        callable $generatorConstructionFunction,
        callable $onRewind = null,
        string $class = ''
    ) {
        parent::__construct(
            $generatorConstructionFunction,
            $onRewind,
            $class
        );
    }

    /**
     * Return the current element.
     *
     * @return mixed
     *
     * @see  http://php.net/manual/en/iterator.current.php
     * @see  Iterator::current
     *
     * @phpstan-return X
     */
    #[\ReturnTypeWillChange]
    public function current()
    {
        $value = $this->generator->current();

        if (\is_array($value)) {
            $value = \call_user_func([$this->class, 'create'], $value, static::class, false);
        }

        return $value;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

/**
 * @template   XKey as array-key
 * @template   X
 * @extends  \ArrayIterator<XKey,X>
 *
 * @internal
 */
class ArrayyRewindableGenerator extends \ArrayIterator
{
    /**
     * @var string
     *
     * @phpstan-var string|class-string<\Arrayy\Arrayy<XKey,X>>
     */
    protected $class;

    /**
     * @var callable
     */
    protected $generatorFunction;

    /**
     * @var \Generator
     *
     * @phpstan-var \Generator<XKey,X>
     */
    protected $generator;

    /**
     * @var callable|null
     */
    protected $onRewind;

    /**
     * @param callable      $generatorConstructionFunction
     *                                                     <p>A callable that should return a Generator.</p>
     * @param callable|null $onRewind
     *                                                     <p>Callable that gets invoked with 0 arguments after the iterator
     *                                                     was rewinded.</p>
     * @param string        $class
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(
        callable $generatorConstructionFunction,
        callable $onRewind = null,
        string $class = ''
    ) {
        $this->class = $class;
        $this->generatorFunction = $generatorConstructionFunction;
        $this->onRewind = $onRewind;
        $this->generateGenerator();
    }

    /**
     * Return the current element.
     *
     * @return mixed
     *
     * @see  http://php.net/manual/en/iterator.current.php
     * @see  Iterator::current
     *
     * @phpstan-return X
     */
    #[\ReturnTypeWillChange]
    public function current()
    {
        return $this->generator->current();
    }

    /**
     * Return the key of the current element.
     *
     * @return mixed scalar on success, or null on failure
     *
     * @see  http://php.net/manual/en/iterator.key.php
     * @see  Iterator::key
     *
     * @phpstan-return XKey
     */
    #[\ReturnTypeWillChange]
    public function key()
    {
        return $this->generator->key();
    }

    /**
     * Move forward to next element.
     *
     * @return void
     *
     * @see  http://php.net/manual/en/iterator.next.php
     * @see  Iterator::next
     */
    #[\ReturnTypeWillChange]
    public function next()
    {
        $this->generator->next();
    }

    /**
     * Rewind the Iterator to the first element.
     *
     * @return void
     *
     * @see  http://php.net/manual/en/iterator.rewind.php
     * @see  Iterator::rewind
     */
    #[\ReturnTypeWillChange]
    public function rewind()
    {
        $this->generateGenerator();

        if (\is_callable($this->onRewind)) {
            \call_user_func($this->onRewind);
        }
    }

    /**
     * Checks if current position is valid.
     *
     * @return bool
     *
     * @see  http://php.net/manual/en/iterator.valid.php
     * @see  Iterator::rewind
     */
    public function valid(): bool
    {
        return $this->generator->valid();
    }

    /**
     * @return void
     */
    private function generateGenerator()
    {
        $this->generator = \call_user_func($this->generatorFunction);

        if (!($this->generator instanceof \Generator)) {
            throw new \InvalidArgumentException('The callable needs to return a Generator');
        }
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

/**
 * Methods to manage strict arrays.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @template TKey of array-key
 * @template T
 * @extends  \Arrayy\Arrayy<TKey,T>
 */
class ArrayyStrict extends Arrayy implements \Arrayy\Type\TypeInterface
{
    /**
     * @var bool
     */
    protected $checkPropertyTypes = true;

    /**
     * @var bool
     */
    protected $checkPropertiesMismatch = false;

    /**
     * @var bool
     */
    protected $checkForMissingPropertiesInConstructor = true;

    /**
     * @var bool
     */
    protected $checkPropertiesMismatchInConstructor = false;
}
<?php

/** @noinspection ClassOverridesFieldOfSuperClassInspection */
/** @noinspection PropertyInitializationFlawsInspection */
/** @noinspection PhpSuperClassIncompatibleWithInterfaceInspection */

declare(strict_types=1);

namespace Arrayy\Collection;

use Arrayy\Arrayy;
use Arrayy\ArrayyIterator;
use Arrayy\Type\TypeInterface;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckInterface;
use Arrayy\TypeCheck\TypeCheckSimple;

/**
 * This class provides a full implementation of `CollectionInterface`, to
 * minimize the effort required to implement this interface.
 *
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
 *
 * @template   TKey of array-key
 * @template   T
 * @extends    Arrayy<TKey,T>
 * @implements CollectionInterface<TKey,T>
 */
abstract class AbstractCollection extends Arrayy implements CollectionInterface
{
    /**
     * @var bool
     */
    protected $checkPropertyTypes = true;

    /**
     * @var bool
     */
    protected $checkPropertiesMismatch = false;

    /**
     * @var bool
     */
    protected $checkForMissingPropertiesInConstructor = true;

    /**
     * Constructs a collection object of the specified type, optionally with the
     * specified data.
     *
     * @param mixed  $data
     *                                             <p>
     *                                             The initial items to store in the collection.
     *                                             </p>
     * @param string $iteratorClass                optional <p>
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
     *                                             need this option.
     *                                             </p>
     * @param bool   $checkPropertiesInConstructor optional <p>
     *                                             You need to extend the "Arrayy"-class and you need to set
     *                                             the $checkPropertiesMismatchInConstructor class property
     *                                             to
     *                                             true, otherwise this option didn't not work anyway.
     *                                             </p>
     *
     * @phpstan-param array<TKey,T>|\Arrayy\Arrayy<TKey,T>|\Closure():array<TKey,T>|mixed $data
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    public function __construct(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        $type = $this->getType();

        $type = self::convertIntoTypeCheckArray($type);

        $this->properties = $type;

        // cast into array, if needed
        if (
            !\is_array($data)
            &&
            !($data instanceof \Traversable)
            &&
            !($data instanceof \Closure)
        ) {
            $data = [$data];
        }

        parent::__construct(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    /**
     * Append a (key) + value to the current array.
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
     *
     * @phpstan-param T|static $value
     * @phpstan-param TKey|null $key
     * @phpstan-return static<TKey,T>
     */
    public function append($value, $key = null): Arrayy
    {
        if (
            $value instanceof self
            &&
            !$value instanceof TypeInterface
        ) {
            foreach ($value as $valueTmp) {
                parent::append($valueTmp, $key);
            }

            return $this;
        }

        /* @phpstan-ignore-next-line | special? */
        $return = parent::append($value, $key);
        $this->array = $return->array;
        $this->generator = null;

        return $this;
    }

    /**
     * Assigns a value to the specified offset + check the type.
     *
     * @param int|string|null $offset
     * @param mixed           $value
     *
     * @return void
     *
     * @phpstan-param T $value
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($offset, $value)
    {
        if (
            $value instanceof self
            &&
            !$value instanceof TypeInterface
        ) {
            foreach ($value as $valueTmp) {
                parent::offsetSet($offset, $valueTmp);
            }

            return;
        }

        parent::offsetSet($offset, $value);
    }

    /**
     * Prepend a (key) + value to the current array.
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return $this
     *               <p>(Mutable) Return this CollectionInterface object, with the prepended value.</p>
     *
     * @phpstan-param T|static $value
     * @phpstan-param TKey|null $key
     * @phpstan-return static<TKey,T>
     */
    public function prepend($value, $key = null): Arrayy
    {
        if (
            $value instanceof self
            &&
            !$value instanceof TypeInterface
        ) {
            foreach ($value as $valueTmp) {
                parent::prepend($valueTmp, $key);
            }

            return $this;
        }

        /* @phpstan-ignore-next-line | special? */
        $return = parent::prepend($value, $key);
        $this->array = $return->array;
        $this->generator = null;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function column(string $keyOrPropertyOrMethod): array
    {
        // init
        $temp = [];

        foreach ($this->getGenerator() as $item) {
            $temp[] = $this->extractValue($item, $keyOrPropertyOrMethod);
        }

        return $temp;
    }

    /**
     * @return array
     *
     * @phpstan-return array<T>
     */
    public function getCollection(): array
    {
        return $this->getArray();
    }

    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string|string[]|TypeCheckArray|TypeCheckInterface[]
     *
     * @phpstan-return string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|TypeCheckInterface[]
     */
    abstract public function getType();

    /**
     * Merge current items and items of given collections into a new one.
     *
     * @param CollectionInterface|static ...$collections
     *                                                   <p>The collections to merge.</p>
     *
     *@throws \InvalidArgumentException if any of the given collections are not of the same type
     *
     * @return $this
     *
     * @phpstan-param CollectionInterface<TKey,T> ...$collections
     * @phpstan-return static<TKey,T>
     */
    public function merge(CollectionInterface ...$collections): self
    {
        foreach ($collections as $collection) {
            foreach ($collection as $item) {
                $this->append($item);
            }
        }

        return $this;
    }

    /**
     * Creates an CollectionInterface object.
     *
     * @param mixed  $data
     * @param string $iteratorClass
     * @param bool   $checkPropertiesInConstructor
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
     *
     * @template TKeyCreate as TKey
     * @template TCreate as T
     * @phpstan-param array<TKeyCreate,TCreate> $data
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
     * @phpstan-return static<TKeyCreate,TCreate>
     *
     * @psalm-mutation-free
     */
    public static function create(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        return new static(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    /**
     * @param string $json
     *
     * @return static
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
     *
     * @phpstan-return static<int,T>
     *
     * @psalm-mutation-free
     */
    public static function createFromJsonMapper(string $json)
    {
        // init
        $return = static::create();

        $jsonObject = \json_decode($json, false);

        $mapper = new \Arrayy\Mapper\Json();
        $mapper->undefinedPropertyHandler = static function ($object, $key, $jsonValue) use ($return) {
            if ($return->checkForMissingPropertiesInConstructor) {
                throw new \TypeError('Property mismatch - input: ' . \print_r(['key' => $key, 'jsonValue' => $jsonValue], true) . ' for object: ' . \get_class($object));
            }
        };

        $type = $return->getType();

        if (
            \is_string($type)
            &&
            \class_exists($type)
        ) {
            if (\is_array($jsonObject)) {
                foreach ($jsonObject as $jsonObjectSingle) {
                    $collectionData = $mapper->map($jsonObjectSingle, $type);
                    $return->add($collectionData);
                }
            } else {
                $collectionData = $mapper->map($jsonObject, $type);
                $return->add($collectionData);
            }
        } else {
            foreach ($jsonObject as $key => $jsonValue) {
                $return->add($jsonValue, $key);
            }
        }

        /** @phpstan-var static<int,T> */
        return $return;
    }

    /**
     * Internal mechanic of set method.
     *
     * @param int|string|null $key
     * @param mixed           $value
     * @param bool            $checkProperties
     *
     * @return bool
     */
    protected function internalSet(
        $key,
        &$value,
        bool $checkProperties = true
    ): bool {
        if (
            $value instanceof self
            &&
            !$value instanceof TypeInterface
        ) {
            foreach ($value as $valueTmp) {
                parent::internalSet(
                    $key,
                    $valueTmp,
                    $checkProperties
                );
            }

            return true;
        }

        return parent::internalSet(
            $key,
            $value,
            $checkProperties
        );
    }

    /**
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
     *
     * @return TypeCheckArray
     *
     * @phpstan-param null|string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|array<array-key,TypeCheckInterface>|mixed $type
     * @phpstan-return TypeCheckArray<array-key,TypeCheckInterface>
     */
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
    {
        $is_array = false;
        if (
            \is_scalar($type)
            ||
            $is_array = \is_array($type)
        ) {
            $type = TypeCheckArray::create(
                [
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
                ]
            );
        }

        return $type;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Collection;

use Arrayy\ArrayyIterator;
use Arrayy\Type\TypeInterface;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckInterface;

/**
 * A collection represents a group of objects.
 *
 * Each object in the collection is of a specific, defined type.
 *
 * This is a direct implementation of `CollectionSetTypeInterface`,
 * which provides a simple api for your collections.
 *
 * Example usage:
 *
 * ``` php
 * $collection = new \Arrayy\Collection\Collection(\My\FooInterface::class);
 * $collection->add(new \My\Foo());
 * $collection->add(new \My\Foo());
 *
 * foreach ($collection as $foo) {
 *     if ($foo instanceof \My\FooInterface) {
 *         // Do something with $foo
 *     }
 * }
 * ```
 *
 * It is preferable to subclass `AbstractCollection` to create your own typed
 * collections. For example:
 *
 * ``` php
 * namespace My;
 * /**
 *  * @extends \Arrayy\Collection\AbstractCollection<array-key,FooInterface>
 *  *\/
 * class FooCollection extends \Arrayy\Collection\AbstractCollection
 * {
 *     public function getType()
 *     {
 *         return FooInterface::class;
 *     }
 * }
 * ```
 *
 * And then use it similarly to the earlier example:
 *
 * ``` php
 * namespace My;
 *
 * $fooCollection = new \My\FooCollection();
 * $fooCollection->add(new \My\Foo());
 * $fooCollection->add(new \My\Foo());
 *
 * foreach ($fooCollection as $foo) {
 *     if ($foo instanceof \My\FooInterface) {
 *         // Do something with $foo
 *     }
 * }
 * ```
 *
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
 *
 * @template TKey of array-key
 * @template T
 * @extends  AbstractCollection<TKey,T>
 */
class Collection extends AbstractCollection
{
    /**
     * Constructs a collection object of the specified type, optionally with the
     * specified data.
     *
     * @param mixed              $data
     *                                                         <p>
     *                                                         The initial items to store in the
     *                                                         collection.
     *                                                         </p>
     * @param string|null        $iteratorClass                optional <p>
     *                                                         You can overwrite the
     *                                                         ArrayyIterator, but mostly you
     *                                                         don't need this option.
     *                                                         </p>
     * @param bool               $checkPropertiesInConstructor optional <p>
     *                                                         You need to extend the
     *                                                         "Arrayy"-class and you need to set
     *                                                         the
     *                                                         $checkPropertiesMismatchInConstructor
     *                                                         class property to true, otherwise
     *                                                         this option didn't not work
     *                                                         anyway.
     *                                                         </p>
     * @param TypeInterface|null $type
     *
     * @phpstan-param array<array-key,T>|array<TKey,T>|\Arrayy\Arrayy<TKey,T> $data
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    public function __construct(
        $data = [],
        string $iteratorClass = null,
        bool $checkPropertiesInConstructor = null,
        TypeInterface $type = null
    ) {
        // fallback
        if ($iteratorClass === null) {
            $iteratorClass = ArrayyIterator::class;
        }
        if ($checkPropertiesInConstructor === null) {
            $checkPropertiesInConstructor = true;
        }

        if ($type !== null) {
            /* @phpstan-ignore-next-line - we use the "TypeInterface" only as base */
            $this->properties = $type;
        }

        parent::__construct(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    /**
     * @param string|TypeCheckArray|TypeCheckInterface[] $type
     * @param array<mixed>                               $data
     * @param bool                                       $checkPropertiesInConstructorAndType
     *
     * @return static
     *
     * @template       TConstruct
     * @phpstan-param  string|class-string|class-string<TConstruct>|TypeInterface|TypeCheckArray<array-key,TypeCheckInterface>|array<TypeCheckInterface> $type
     * @phpstan-param  array<array-key,TConstruct> $data
     * @phpstan-return static<array-key,TConstruct>
     */
    public static function construct(
        $type,
        $data = [],
        bool $checkPropertiesInConstructorAndType = true
    ): self {
        $type = self::convertIntoTypeCheckArray($type);

        return new static(
            $data,
            ArrayyIterator::class,
            $checkPropertiesInConstructorAndType,
            $type
        );
    }

    /**
     * Returns a new iterator, thus implementing the \Iterator interface.
     *
     * @return \Iterator
     *                   <p>An iterator for the values in the array.</p>
     *
     * @phpstan-return \Iterator<T>
     *
     * @noinspection SenselessProxyMethodInspection
     */
    public function getIterator(): \Iterator
    {
        return parent::getIterator();
    }

    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string|TypeCheckArray|TypeCheckInterface[]
     *
     * @phpstan-return string|class-string|class-string<T>|TypeInterface|TypeCheckArray<TKey,T>|TypeCheckArray<int|string,mixed>|array<TypeCheckInterface>|array<array-key,TypeCheckInterface>
     */
    public function getType()
    {
        return $this->properties;
    }

    /**
     * Get a base Collection instance from this Collection.
     *
     * @return self
     *
     * @phpstan-return self<array-key,mixed>
     */
    public function toBase(): self
    {
        return self::construct(
            $this->getType(),
            $this->getArray()
        );
    }
}
<?php

namespace Arrayy\Collection;

use Arrayy\ArrayyIterator;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckInterface;

/**
 * A collection represents a group of objects, known as its elements.
 *
 * Some collections allow duplicate elements and others do not. Some are ordered
 * and others unordered.
 *
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
 *
 * @template TKey of array-key
 * @template T
 * @extends \IteratorAggregate<TKey,T>
 * @extends \ArrayAccess<TKey,T>
 */
interface CollectionInterface extends \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
{
    /**
     * Assigns a value to the specified element.
     *
     * @param mixed $key
     * @param mixed $value
     *
     * @return void
     *
     * @phpstan-param TKey $key
     * @phpstan-param T $value
     */
    public function __set($key, $value);

    /**
     * alias: for "CollectionInterface->append()"
     *
     * @param mixed $value
     *
     * @return CollectionInterface
     *                             <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
     *
     * @see          CollectionInterface::append()
     *
     * @phpstan-param  T $value
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function add($value);

    /**
     * Append a (key) + value to the current array.
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return CollectionInterface
     *                             <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey|null $key
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function append($value, $key = null);

    /**
     * Append a (key) + values to the current array.
     *
     * @param array $values
     * @param mixed $key
     *
     * @return CollectionInterface
     *                             <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
     *
     * @phpstan-param array<T> $values
     * @phpstan-param TKey $key
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function appendArrayValues(array $values, $key = null);

    /**
     * Clears the current collection, by removing all elements.
     *
     * @return void
     */
    public function clear();

    /**
     * Returns the values from given property or method.
     *
     * @param string $keyOrPropertyOrMethod the property or method name to filter by
     *
     * @throws \InvalidArgumentException if property or method is not defined
     *
     * @return array<mixed>
     */
    public function column(string $keyOrPropertyOrMethod): array;

    /**
     * Check if an item is in the current array.
     *
     * @param float|int|string $value
     * @param bool             $recursive
     * @param bool             $strict
     *
     * @return bool
     *
     * @phpstan-param T $value
     */
    public function contains($value, bool $recursive = false, bool $strict = true): bool;

    /**
     * Checks whether the collection contains an element with the specified key/index.
     *
     * @param int|string $key
     *                        <p>The key/index to check for.</p>
     *
     * @return bool
     *              <p>TRUE if the collection contains an element with the specified key/index,
     *              FALSE otherwise.</p>
     *
     * @phpstan-param TKey $key
     */
    public function containsKey($key): bool;

    /**
     * alias: for "CollectionInterface->contains()"
     *
     * @param float|int|string $value
     *
     * @return bool
     *
     * @see         CollectionInterface::contains()
     *
     * @phpstan-param T $value
     */
    public function containsValue($value): bool;

    /**
     * alias: for "CollectionInterface->contains($value, true)"
     *
     * @param float|int|string $value
     *
     * @return bool
     *
     * @see         CollectionInterface::contains()
     *
     * @phpstan-param T $value
     */
    public function containsValueRecursive($value): bool;

    /**
     * Creates an CollectionInterface object.
     *
     * @param mixed  $data
     * @param string $iteratorClass
     * @param bool   $checkPropertiesInConstructor
     *
     * @return CollectionInterface
     *                             <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
     *
     * @template TKeyCreate as TKey
     * @template TCreate as T
     * @phpstan-param array<TKeyCreate,TCreate> $data
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
     * @phpstan-return static<TKeyCreate,TCreate>
     *
     * @psalm-mutation-free
     */
    public static function create(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    );

    /**
     * Gets the element of the collection at the current iterator position.
     *
     * @return false|mixed
     *
     * @phpstan-return T|false
     */
    public function current();

    /**
     * Tests for the existence of an element that satisfies the given predicate.
     *
     * @param \Closure $closure the predicate
     *
     * @return bool
     *              <p>TRUE if the predicate is TRUE for at least one element, FALSE otherwise.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function exists(\Closure $closure): bool;

    /**
     * Returns all the elements of this collection that satisfy the predicate p.
     * The order of the elements is preserved.
     *
     * @param \Closure $closure the predicate used for filtering
     * @param int      $flag    [optional]
     *
     * @return CollectionInterface
     *                             <p>A collection with the results of the filter operation.</p>
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH);

    /**
     * Sets the internal iterator to the first element in the collection and returns this element.
     *
     * @return mixed
     *
     * @phpstan-return T|false
     */
    public function first();

    /**
     * Tests whether the given closure retrun something valid for all elements of this array.
     *
     * @param \Closure $closure the predicate
     *
     * @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise
     *
     * @phpstan-param \Closure(T,TKey):bool $closure
     */
    public function validate(\Closure $closure): bool;

    /**
     * Gets the element at the specified key/index.
     *
     * @param int|string $key
     *                        <p>The key/index of the element to retrieve.</p>
     *
     * @return mixed
     *
     * @phpstan-param TKey $key
     * @phpstan-return T|null
     */
    public function get($key);

    /**
     * Creates a copy of the CollectionInterface.
     *
     * @return array
     *
     * @phpstan-return array<T>
     */
    public function getArrayCopy(): array;

    /**
     * @return array
     *
     * @phpstan-return array<T>
     */
    public function getCollection(): array;

    /**
     * Gets all keys/indices of the collection.
     *
     * @return CollectionInterface
     *
     * @phpstan-return TKey[]
     */
    public function getKeys();

    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string|string[]|TypeCheckArray|TypeCheckInterface[]
     *
     * @phpstan-return string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|TypeCheckInterface[]
     */
    public function getType();

    /**
     * Gets all values of the collection.
     *
     * @return CollectionInterface
     *
     * @phpstan-return T[]
     */
    public function getValues();

    /**
     * Check if an array has a given value.
     *
     * INFO: if you need to search recursive please use ```contains()```
     *
     * @param mixed $value
     *
     * @return bool
     *
     * @phpstan-param T $value
     */
    public function hasValue($value): bool;

    /**
     * Gets the index/key of a given element. The comparison of two elements is strict,
     * that means not only the value but also the type must match.
     * For objects this means reference equality.
     *
     * @param mixed $element the element to search for
     *
     * @return false|mixed the key/index of the element or FALSE if the element was not found
     *
     * @phpstan-param T $element
     * @phpstan-return TKey|false
     */
    public function indexOf($element);

    /**
     * Checks whether the collection is empty (contains no elements).
     *
     * @param int|int[]|string|string[]|null $keys
     *
     * @return bool
     *              <p>TRUE if the collection is empty, FALSE otherwise.</p>
     *
     * @phpstan-param TKey|TKey[]|null $keys
     */
    public function isEmpty($keys = null): bool;

    /**
     * Gets the key/index of the element at the current iterator position.
     *
     * @return int|string|null
     *
     * @phpstan-return TKey|null
     */
    public function key();

    /**
     * Sets the internal iterator to the last element in the collection and returns this element.
     *
     * @return mixed
     *
     * @phpstan-return T|false
     */
    public function last();

    /**
     * Applies the given function to each element in the collection and returns
     * a new collection with the elements returned by the function.
     *
     * @param callable $callable
     * @param bool     $useKeyAsSecondParameter
     * @param mixed    ...$arguments
     *
     * @return CollectionInterface
     *
     * @phpstan-param callable(T,TKey,mixed):mixed $callable
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments);

    /**
     * Merge current items and items of given collections into a new one.
     *
     * @param CollectionInterface ...$collections The collections to merge.
     *
     * @throws \InvalidArgumentException if any of the given collections are not of the same type
     *
     * @return CollectionInterface
     *
     * @phpstan-param CollectionInterface<TKey,T> ...$collections
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function merge(self ...$collections);

    /**
     * Moves the internal iterator position to the next element and returns this element.
     *
     * @return mixed
     *
     * @phpstan-return T|false
     */
    public function next();

    /**
     * Assigns a value to the specified offset + check the type.
     *
     * @param int|string|null $offset
     * @param mixed           $value
     *
     * @return void
     *
     * @phpstan-param TKey $offset
     * @phpstan-param T $value
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($offset, $value);

    /**
     * Partitions this collection in two collections according to a predicate.
     * Keys are preserved in the resulting collections.
     *
     * @param \Closure $p the predicate on which to partition
     *
     * @return array<int, CollectionInterface> An array with two elements. The first element contains the collection
     *                    of elements where the predicate returned TRUE, the second element
     *                    contains the collection of elements where the predicate returned FALSE.
     *
     * @phpstan-param \Closure(T,TKey):bool $p
     * @phpstan-return array{0: CollectionInterface<TKey,T>, 1: CollectionInterface<TKey,T>}
     */
    public function partition(\Closure $p): array;

    /**
     * Prepend a (key) + value to the current array.
     *
     * @param mixed $value
     * @param mixed $key
     *
     * @return CollectionInterface
     *                             <p>(Mutable) Return this CollectionInterface object, with the prepended value.</p>
     *
     * @phpstan-param T $value
     * @phpstan-param TKey|null $key
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function prepend($value, $key = null);

    /**
     * Removes the element at the specified index from the collection.
     *
     * Remove a value from the current array (optional using dot-notation).
     *
     * @param mixed $key
     *
     * @return CollectionInterface
     *
     * @phpstan-param TKey $key
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function remove($key);

    /**
     * Removes the specified element from the collection, if it is found.
     *
     * @param mixed $element
     *                       <p>The element to remove.</p>
     *
     * @return CollectionInterface
     *
     * @phpstan-param  T $element
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function removeElement($element);

    /**
     * Removes a particular value from an array (numeric or associative).
     *
     * @param mixed $value
     *
     * @return CollectionInterface
     *                             <p>(Immutable)</p>
     *
     * @phpstan-param T $value
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function removeValue($value);

    /**
     * Sets an element in the collection at the specified key/index.
     *
     * @param int|string $key
     *                          <p>The key/index of the element to set.</p>
     * @param mixed      $value
     *                          <p>The element to set.<p>
     *
     * @return CollectionInterface
     *
     * @phpstan-param TKey $key
     * @phpstan-param T $value
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function set($key, $value);

    /**
     * Extracts a slice of $length elements starting at position $offset from the Collection.
     *
     * If $length is null it returns all elements from $offset to the end of the Collection.
     * Keys have to be preserved by this method. Calling this method will only return the
     * selected slice and NOT change the elements contained in the collection slice is called on.
     *
     * @param int      $offset       the offset to start from
     * @param int|null $length       the maximum number of elements to return, or null for no limit
     * @param bool     $preserveKeys
     *
     * @return CollectionInterface
     *
     * @phpstan-return CollectionInterface<array-key|TKey,T>
     */
    public function slice(int $offset, int $length = null, bool $preserveKeys = false);

    /**
     * Gets a native PHP array representation of the collection.
     *
     * @return array
     *
     * @phpstan-return array<TKey,T>
     */
    public function toArray(): array;

    /**
     * Returns a collection of matching items.
     *
     * @param string $keyOrPropertyOrMethod the property or method to evaluate
     * @param mixed  $value                 the value to match
     *
     * @throws \InvalidArgumentException if property or method is not defined
     *
     * @return CollectionInterface
     *
     * @phpstan-return CollectionInterface<TKey,T>
     */
    public function where(string $keyOrPropertyOrMethod, $value);
}
<?php

declare(strict_types=1);

namespace {

    if (\PHP_VERSION_ID < 70300) {
        if (!\function_exists('is_countable')) {
            /**
             * @param mixed $var
             *
             * @return bool
             */
            function is_countable($var)
            {
                return \is_array($var)
                       ||
                       $var instanceof SimpleXMLElement
                       ||
                       $var instanceof Countable
                       ||
                       $var instanceof ResourceBundle;
            }
        }

        if (!\function_exists('array_key_first')) {
            /**
             * @param array<mixed> $array
             *
             * @return int|string|null
             */
            function array_key_first(array $array)
            {
                foreach ($array as $key => $value) {
                    return $key;
                }

                return null;
            }
        }

        if (!\function_exists('array_key_last')) {
            /**
             * @param array<mixed> $array
             *
             * @return int|string|null
             */
            function array_key_last(array $array)
            {
                if (\count($array) === 0) {
                    return null;
                }

                return \array_keys(
                    \array_slice($array, -1, 1, true)
                )[0];
            }
        }
    }

}

namespace Arrayy {

    use Arrayy\Collection\Collection;
    use Arrayy\TypeCheck\TypeCheckArray;
    use Arrayy\TypeCheck\TypeCheckInterface;

    if (!\function_exists('Arrayy\create')) {
        /**
         * Creates a Arrayy object.
         *
         * @param mixed $data
         *
         * @return Arrayy<int|string,mixed>
         */
        function create($data): Arrayy
        {
            return new Arrayy($data);
        }
    }

    if (!\function_exists('Arrayy\collection')) {
        /**
         * Creates a Collection object.
         *
         * @param string|TypeCheckArray|TypeCheckInterface[] $type
         * @param array<mixed>                               $data
         *
         * @return Collection
         *
         * @template T
         * @phpstan-param T $type
         * @phpstan-return Collection<array-key,T>
         */
        function collection($type, $data = []): Collection
        {
            /** @phpstan-var Collection<array-key,T> */
            return Collection::construct($type, $data);
        }
    }

    /**
     * @param array<mixed> $array
     * @param mixed        $fallback <p>This fallback will be used, if the array is empty.</p>
     *
     * @return mixed|null
     *
     * @template TLast
     * @template TLastFallback
     * @phpstan-param TLast[] $array
     * @phpstan-param TLastFallback $fallback
     * @phpstan-return TLast|TLastFallback
     */
    function array_last(array $array, $fallback = null)
    {
        $key_last = \array_key_last($array);
        if ($key_last === null) {
            return $fallback;
        }

        return $array[$key_last];
    }

    /**
     * @param array<mixed> $array
     * @param mixed        $fallback <p>This fallback will be used, if the array is empty.</p>
     *
     * @return mixed|null
     *
     * @template TFirst
     * @template TFirstFallback
     * @phpstan-param TFirst[] $array
     * @phpstan-param TFirstFallback $fallback
     * @phpstan-return TFirst|TFirstFallback
     */
    function array_first(array $array, $fallback = null)
    {
        $key_first = \array_key_first($array);
        if ($key_first === null) {
            return $fallback;
        }

        return $array[$key_first];
    }

}
<?php

namespace Arrayy\Mapper;

/**
 * @category Netresearch
 *
 * @license  OSL-3.0 http://opensource.org/licenses/osl-3.0
 *
 * @see     http://cweiske.de/
 *
 * INFO: this json-mapper is mostly a copy of https://github.com/cweiske/jsonmapper/
 *
 * @internal
 */
final class Json
{
    /**
     * Override class names that JsonMapper uses to create objects.
     * Useful when your setter methods accept abstract classes or interfaces.
     *
     * @var array
     */
    public $classMap = [];

    /**
     * Callback used when an undefined property is found.
     *
     * Works only when $bExceptionOnUndefinedProperty is disabled.
     *
     * Parameters to this function are:
     * 1. Object that is being filled
     * 2. Name of the unknown JSON property
     * 3. JSON value of the property
     *
     * @var callable
     */
    public $undefinedPropertyHandler;

    /**
     * Runtime cache for inspected classes. This is particularly effective if
     * mapArray() is called with a large number of objects
     *
     * @var array property inspection result cache
     */
    private $arInspectedClasses = [];

    /**
     * Map data all data in $json into the given $object instance.
     *
     * @param object|iterable $json
     *                                                      <p>JSON object structure from json_decode()</p>
     * @param object|string $object
     *                                                      <p>Object to map $json data into</p>
     *
     * @return mixed
     *               <p>mapped object is returned</p>
     *
     * @see mapArray()
     *
     * @template TObject
     * @phpstan-param TObject|class-string<TObject> $object
     *                                                      <p>Object to map $json data into.</p>
     * @phpstan-return TObject
     *
     */
    public function map($json, $object)
    {
        if (\is_string($object) && \class_exists($object)) {
            $object = self::createInstance($object);
        }

        if (!\is_object($object)) {
            throw new \InvalidArgumentException(
                'JsonMapper::map() requires second argument to be an object, ' . \gettype($object) . ' given.'
            );
        }

        $strClassName = \get_class($object);
        $rc = new \ReflectionClass($object);
        $strNs = $rc->getNamespaceName();
        foreach ($json as $key => $jsonValue) {
            $key = $this->getSafeName($key);

            // Store the property inspection results, so we don't have to do it
            // again for subsequent objects of the same type.
            if (!isset($this->arInspectedClasses[$strClassName][$key])) {
                $this->arInspectedClasses[$strClassName][$key] = $this->inspectProperty($rc, $key);
            }

            list(
                $hasProperty,
                $accessor,
                $type
            ) = $this->arInspectedClasses[$strClassName][$key];

            if (!$hasProperty) {
                if (\is_callable($this->undefinedPropertyHandler)) {
                    \call_user_func(
                        $this->undefinedPropertyHandler,
                        $object,
                        $key,
                        $jsonValue
                    );
                }

                continue;
            }

            if ($accessor === null) {
                continue;
            }

            if ($this->isNullable($type)) {
                if ($jsonValue === null) {
                    $this->setProperty($object, $accessor, null);

                    continue;
                }

                $type = $this->removeNullable($type);
            } elseif ($jsonValue === null) {
                throw new \InvalidArgumentException(
                    'JSON property "' . $key . '" in class "' . $strClassName . '" must not be NULL'
                );
            }

            $type = $this->getFullNamespace($type, $strNs);
            $type = $this->getMappedType($type, $jsonValue);

            if (
                $type === null
                ||
                $type === 'mixed'
            ) {
                // no given type - simply set the json data
                $this->setProperty($object, $accessor, $jsonValue);

                continue;
            }

            if ($this->isObjectOfSameType($type, $jsonValue)) {
                $this->setProperty($object, $accessor, $jsonValue);

                continue;
            }

            if ($this->isSimpleType($type)) {
                if ($type === 'string' && \is_object($jsonValue)) {
                    throw new \InvalidArgumentException(
                        'JSON property "' . $key . '" in class "' . $strClassName . '" is an object and cannot be converted to a string'
                    );
                }

                if (\strpos($type, '|') !== false) {
                    foreach (\explode('|', $type) as $tmpType) {
                        if (\gettype($jsonValue) === $tmpType) {
                            \settype($jsonValue, $tmpType);
                        }
                    }
                } else {
                    \settype($jsonValue, $type);
                }

                $this->setProperty($object, $accessor, $jsonValue);

                continue;
            }

            if ($type === '') {
                throw new \InvalidArgumentException(
                    'Empty type at property "' . $strClassName . '::$' . $key . '"'
                );
            }

            $array = null;
            $subtype = null;
            if ($this->isArrayOfType($type)) {
                $array = [];
                $subtype = \substr($type, 0, -2);
            } elseif (\substr($type, -1) == ']') {
                list($proptype, $subtype) = \explode('[', \substr($type, 0, -1));
                if ($proptype == 'array') {
                    $array = [];
                } else {
                    /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                    /** @phpstan-var class-string $proptype */
                    $proptype = $proptype;
                    $array = self::createInstance($proptype, false, $jsonValue);
                }
            } elseif (\is_a($type, \ArrayObject::class, true)) {
                /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                /** @phpstan-var \ArrayObject<array-key, mixed> $type */
                $type = $type;
                $array = self::createInstance($type, false, $jsonValue);
            }

            if ($array !== null) {
                /** @noinspection NotOptimalIfConditionsInspection */
                if (
                    !\is_array($jsonValue)
                    &&
                    $this->isScalarType(\gettype($jsonValue))
                ) {
                    throw new \InvalidArgumentException(
                        'JSON property "' . $key . '" must be an array, ' . \gettype($jsonValue) . ' given'
                    );
                }

                $cleanSubtype = $this->removeNullable($subtype);
                $subtype = $this->getFullNamespace($cleanSubtype, $strNs);
                $child = $this->mapArray($jsonValue, $array, $subtype, $key);
            } elseif ($this->isScalarType(\gettype($jsonValue))) {
                // use constructor parameter if we have a class, but only a flat type (i.e. string, int)
                /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                /** @phpstan-var object $type */
                $type = $type;
                $child = self::createInstance($type, true, $jsonValue);
            } else {
                /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                /** @phpstan-var object $type */
                $type = $type;
                $child = self::createInstance($type, false, $jsonValue);
                $this->map($jsonValue, $child);
            }

            $this->setProperty($object, $accessor, $child);
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @phpstan-var TObject $object */
        $object = $object;

        return $object;
    }

    /**
     * Map an array
     *
     * @param array       $json       JSON array structure from json_decode()
     * @param mixed       $array      Array or ArrayObject that gets filled with
     *                                data from $json
     * @param string|null $class      Class name for children objects.
     *                                All children will get mapped onto this type.
     *                                Supports class names and simple types
     *                                like "string" and nullability "string|null".
     *                                Pass "null" to not convert any values
     * @param string      $parent_key defines the key this array belongs to
     *                                in order to aid debugging
     *
     * @pslam-param null|class-string $class
     *
     * @return mixed Mapped $array is returned
     */
    public function mapArray($json, $array, $class = null, $parent_key = '')
    {
        $originalClass = $class;
        foreach ($json as $key => $jsonValue) {
            $class = $this->getMappedType($originalClass, $jsonValue);
            if ($class === null) {
                $foundArrayy = false;

                if ($array instanceof \Arrayy\Arrayy && $jsonValue instanceof \stdClass) {
                    foreach ($array->getPhpDocPropertiesFromClass() as $typesKey => $typesTmp) {
                        if (
                            (
                                $typesKey === $key
                                ||
                                $typesKey === \Arrayy\Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES
                            )
                            &&
                            \count($typesTmp->getTypes()) === 1
                            &&
                            \is_subclass_of($typesTmp->getTypes()[0], \Arrayy\Arrayy::class)
                        ) {
                            $array[$key] = $typesTmp->getTypes()[0]::createFromObjectVars($jsonValue);
                            $foundArrayy = true;

                            break;
                        }
                    }
                }
                if ($foundArrayy === false) {
                    if ($array instanceof \Arrayy\Arrayy && $jsonValue instanceof \stdClass) {
                        foreach ($array->getPhpDocPropertiesFromClass() as $typesKey => $typesTmp) {
                            if (
                                (
                                    $typesKey === $key
                                    ||
                                    $typesKey === \Arrayy\Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES
                                )
                                &&
                                \count($typesTmp->getTypes()) === 1
                            ) {
                                $array[$key] = $this->map($jsonValue, $typesTmp->getTypes()[0]);
                                $foundArrayy = true;

                                break;
                            }
                        }
                    }
                    if ($foundArrayy === false) {
                        $array[$key] = $jsonValue;
                    }
                }
            } elseif ($this->isArrayOfType($class)) {
                $array[$key] = $this->mapArray(
                    $jsonValue,
                    [],
                    \substr($class, 0, -2)
                );
            } elseif ($this->isScalarType(\gettype($jsonValue))) {
                // Use constructor parameter if we have a class, but only a flat type (i.e. string, int).
                if ($jsonValue === null) {
                    $array[$key] = null;
                } elseif ($this->isSimpleType($class)) {
                    \settype($jsonValue, $class);
                    $array[$key] = $jsonValue;
                } else {
                    /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                    /** @phpstan-var class-string $class */
                    $class = $class;
                    $array[$key] = self::createInstance(
                        $class,
                        true,
                        $jsonValue
                    );
                }
            } elseif ($this->isScalarType($class)) {
                throw new \InvalidArgumentException(
                    'JSON property "' . ($parent_key ?: '?') . '" is an array of type "' . $class . '" but contained a value of type "' . \gettype($jsonValue) . '"'
                );
            } elseif (\is_a($class, \ArrayObject::class, true)) {
                /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                /** @phpstan-var \ArrayObject<array-key, mixed> $class */
                $class = $class;
                $array[$key] = $this->mapArray(
                    $jsonValue,
                    self::createInstance($class)
                );
            } else {
                /** @noinspection PhpSillyAssignmentInspection - phpstan helper */
                /** @phpstan-var class-string $class */
                $class = $class;
                $array[$key] = $this->map(
                    $jsonValue,
                    self::createInstance($class, false, $jsonValue)
                );
            }
        }

        return $array;
    }

    /**
     * Convert a type name to a fully namespaced type name.
     *
     * @param string|null $type  Type name (simple type or class name)
     * @param string      $strNs Base namespace that gets prepended to the type name
     *
     * @return string|null Fully-qualified type name with namespace
     */
    private function getFullNamespace($type, $strNs)
    {
        if (
            $type === null
            ||
            $type === ''
            ||
            $type[0] == '\\'
            ||
            $strNs == ''
        ) {
            return $type;
        }

        list($first) = \explode('[', $type, 2);
        if (
            $first === 'mixed'
            ||
            $this->isSimpleType($first)
        ) {
            return $type;
        }

        //create a full qualified namespace
        return '\\' . $strNs . '\\' . $type;
    }

    /**
     * Try to find out if a property exists in a given class.
     * Checks property first, falls back to setter method.
     *
     * @param \ReflectionClass<object> $rc   Reflection class to check
     * @param string                   $name Property name
     *
     * @return array First value: if the property exists
     *               Second value: the accessor to use (
     *               Array-Key-String or ReflectionMethod or ReflectionProperty, or null)
     *               Third value: type of the property
     */
    private function inspectProperty(\ReflectionClass $rc, $name): array
    {
        // now try to set the property directly, we have to look it up in the class hierarchy
        $class = $rc;
        $accessor = null;

        /** @var \Arrayy\Arrayy[] $ARRAYY_CACHE */
        /** @phpstan-var array<string, \Arrayy\Arrayy<array-key, mixed>> $ARRAYY_CACHE */
        static $ARRAYY_CACHE = [];

        if (\is_subclass_of($class->name, \Arrayy\Arrayy::class)) {
            if (!isset($ARRAYY_CACHE[$class->name])) {
                $ARRAYY_CACHE[$class->name] = new $class->name();
            }

            $tmpProps = $ARRAYY_CACHE[$class->name]->getPhpDocPropertiesFromClass();
            if ($tmpProps === []) {
                return [true, $name, 'mixed'];
            }

            foreach ($tmpProps as $tmpName => $tmpProp) {
                if ($tmpName === $name) {
                    return [true, $name, \implode('|', $tmpProp->getTypes())];
                }
            }
        }

        do {
            if ($class->hasProperty($name)) {
                $accessor = $class->getProperty($name);
            }
        } while ($accessor === null && $class = $class->getParentClass());

        if ($accessor === null) {
            // case-insensitive property matching
            foreach ($rc->getProperties() as $p) {
                if ((\strcasecmp($p->name, $name) === 0)) {
                    $accessor = $p;

                    break;
                }
            }
        }

        if ($accessor !== null) {
            if ($accessor->isPublic()) {
                $docblock = $accessor->getDocComment();
                if ($docblock === false) {
                    return [true, null, null];
                }

                $annotations = self::parseAnnotations($docblock);

                if (!isset($annotations['var'][0])) {
                    return [true, $accessor, null];
                }

                // support "@var type description"
                list($type) = \explode(' ', $annotations['var'][0]);

                return [true, $accessor, $type];
            }

            // no private property
            return [true, null, null];
        }

        // no setter, no property
        return [false, null, null];
    }

    /**
     * Copied from PHPUnit 3.7.29, Util/Test.php
     *
     * @param string $docblock Full method docblock
     *
     * @return array
     */
    private static function parseAnnotations($docblock): array
    {
        // init
        $annotations = [];

        // Strip away the docblock header and footer
        // to ease parsing of one line annotations
        $docblock = \substr($docblock, 3, -2);

        $re = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m';
        if (\preg_match_all($re, $docblock, $matches)) {
            $numMatches = \count($matches[0]);

            for ($i = 0; $i < $numMatches; ++$i) {
                $annotations[$matches['name'][$i]][] = $matches['value'][$i];
            }
        }

        return $annotations;
    }

    /**
     * Removes - and _ and makes the next letter uppercase
     *
     * @param string $name Property name
     *
     * @return string CamelCasedVariableName
     */
    private function getCamelCaseName($name): string
    {
        return \str_replace(
            ' ',
            '',
            \ucwords(\str_replace(['_', '-'], ' ', $name))
        );
    }

    /**
     * Since hyphens cannot be used in variables we have to uppercase them.
     *
     * Technically you may use them, but they are awkward to access.
     *
     * @param string $name Property name
     *
     * @return string Name without hyphen
     */
    private function getSafeName($name): string
    {
        $convertHyphens = \strpos($name, '-') !== false;
        $convertSnake = \strpos($name, '_') !== false;

        if ($convertHyphens || $convertSnake) {
            $name = $this->getCamelCaseName($name);
        }

        return $name;
    }

    /**
     * Set a property on a given object to a given value.
     *
     * Checks if the setter or the property are public are made before
     * calling this method.
     *
     * @param \Arrayy\Arrayy|object                        $object   Object to set property on
     * @param \ReflectionMethod|\ReflectionProperty|string $accessor Array-Key-String or ReflectionMethod or ReflectionProperty
     * @param mixed                                        $value    Value of property
     *
     * @return void
     */
    private function setProperty(
        $object,
        $accessor,
        $value
    ) {
        if (\is_string($accessor) && $object instanceof \Arrayy\Arrayy) {
            $object[$accessor] = $value;
        } elseif ($accessor instanceof \ReflectionProperty) {
            $accessor->setValue($object, $value);
        } elseif ($accessor instanceof \ReflectionMethod) {
            // setter method
            $accessor->invoke($object, $value);
        }
    }

    /**
     * Get the mapped class/type name for this class.
     * Returns the incoming classname if not mapped.
     *
     * @param string|null $type      Type name to map
     * @param mixed       $jsonValue Constructor parameter (the json value)
     *
     * @return string|null The mapped type/class name
     *
     * @phpstan-return class-string|string|null
     */
    private function getMappedType($type, $jsonValue = null)
    {
        if (isset($this->classMap[$type])) {
            $target = $this->classMap[$type];
        } elseif (
            \is_string($type)
            &&
            $type !== ''
            &&
            $type[0] == '\\'
            &&
            isset($this->classMap[\substr($type, 1)])
        ) {
            $target = $this->classMap[\substr($type, 1)];
        } else {
            $target = null;
        }

        if ($target) {
            if (\is_callable($target)) {
                $type = $target($type, $jsonValue);
            } else {
                $type = $target;
            }
        }

        return $type;
    }

    /**
     * Checks if the given type is a "simple type"
     *
     * @param string $type type name from gettype()
     *
     * @return bool True if it is a simple PHP type
     *
     * @see isScalarType()
     */
    private function isSimpleType($type): bool
    {
        if (\strpos($type, '|') !== false) {
            foreach (\explode('|', $type) as $tmpType) {
                if ($this->isSimpleType($tmpType)) {
                    return true;
                }
            }
        }

        /** @noinspection InArrayCanBeUsedInspection */
        return $type == 'string'
               || $type == 'boolean' || $type == 'bool'
               || $type == 'integer' || $type == 'int' || $type == 'int'
               || $type == 'double' || $type == 'float'
               || $type == 'array' || $type == 'object';
    }

    /**
     * Checks if the object is of this type or has this type as one of its parents
     *
     * @param string $type  class name of type being required
     * @param mixed  $value Some PHP value to be tested
     *
     * @return bool True if $object has type of $type
     */
    private function isObjectOfSameType($type, $value): bool
    {
        if (\is_object($value) === false) {
            return false;
        }

        return \is_a($value, $type);
    }

    /**
     * Checks if the given type is a type that is not nested
     * (simple type except array and object)
     *
     * @param string $type type name from gettype()
     *
     * @return bool True if it is a non-nested PHP type
     *
     * @see isSimpleType()
     */
    private function isScalarType($type): bool
    {
        /** @noinspection InArrayCanBeUsedInspection */
        return $type == 'NULL'
               || $type == 'string'
               || $type == 'boolean' || $type == 'bool'
               || $type == 'integer' || $type == 'int'
               || $type == 'double' || $type == 'float';
    }

    /**
     * Returns true if type is an array of elements
     * (bracket notation)
     *
     * @param string $strType type to be matched
     *
     * @return bool
     */
    private function isArrayOfType($strType): bool
    {
        return \substr($strType, -2) === '[]';
    }

    /**
     * Checks if the given type is nullable
     *
     * @param string $type type name from the phpdoc param
     *
     * @return bool True if it is nullable
     */
    private function isNullable($type): bool
    {
        return \stripos('|' . $type . '|', '|null|') !== false;
    }

    /**
     * Remove the 'null' section of a type
     *
     * @param false|string|null $type type name from the phpdoc param
     *
     * @return string|null The new type value
     */
    private function removeNullable($type)
    {
        if ($type === null || $type === false) {
            return null;
        }

        return \substr(
            \str_ireplace('|null|', '|', '|' . $type . '|'),
            1,
            -1
        );
    }

    /**
     * Create a new object of the given type.
     *
     * This method exists to be overwritten in child classes,
     * so you can do dependency injection or so.
     *
     * @param object|string $class
     *                            <p>Class name to instantiate</p>
     * @param bool $useParameter
     *                            <p>Pass $parameter to the constructor or not</p>
     * @param mixed $jsonValue
     *                            <p>Constructor parameter (the json value)</p>
     *
     * @return object
     *               <p>Freshly created object</p>
     *
     * @internal
     *
     * @template TClass
     * @phpstan-param TClass|class-string<TClass> $class
     * @phpstan-return TClass
     */
    private static function createInstance(
        $class,
        bool $useParameter = false,
        $jsonValue = null
    ) {
        if ($useParameter) {
            /** @phpstan-var TClass $return */
            $return = new $class($jsonValue);

            return $return;
        }

        $reflectClass = new \ReflectionClass($class);
        $constructor = $reflectClass->getConstructor();
        if (
            $constructor === null
            ||
            $constructor->getNumberOfRequiredParameters() > 0
        ) {
            /** @phpstan-var TClass $return */
            $return =  $reflectClass->newInstanceWithoutConstructor();
        } else {
            /** @phpstan-var TClass $return */
            $return = $reflectClass->newInstance();
        }

        return $return;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy;

/**
 * INFO: "Method Parameter Information" via PhpStorm |
 * https://www.jetbrains.com/phpstorm/help/viewing-method-parameter-information.html
 *
 * @deprecated please use e.g. "\Arrayy\create()"
 */
class StaticArrayy
{
    /**
     * A mapping of method names to the numbers of arguments it accepts. Each
     * should be two more than the equivalent Arrayy method. Necessary as
     * static methods place the optional $encoding as the last parameter.
     *
     * @var int[]|string[]
     */
    protected static $methodArgs;

    /**
     * Creates an instance of Arrayy and invokes the given method
     *
     * @param string  $name
     * @param mixed[] $arguments
     *
     * @return mixed
     */
    public static function __callStatic(string $name, $arguments)
    {
        if (!static::$methodArgs) {
            $arrayyClass = new \ReflectionClass(Arrayy::class);
            $methods = $arrayyClass->getMethods(\ReflectionMethod::IS_PUBLIC);

            foreach ($methods as $method) {
                $params = $method->getNumberOfParameters() + 2;
                static::$methodArgs[$method->name] = $params;
            }
        }

        if (!isset(static::$methodArgs[$name])) {
            throw new \BadMethodCallException($name . ' is not a valid method');
        }

        $numArgs = \count($arguments);
        $array = $numArgs ? $arguments[0] : '';

        if ($numArgs === static::$methodArgs[$name]) {
            $args = \array_slice($arguments, 1, -1);
        } else {
            $args = \array_slice($arguments, 1);
        }

        $arrayy = Arrayy::create($array);

        return \call_user_func_array([$arrayy, $name], $args);
    }

    ////////////////////////////////////////////////////////////////////
    ///////////////////////////// GENERATE /////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Generate an array from a range.
     *
     * @param int      $base The base number
     * @param int|null $stop The stopping point
     * @param int      $step How many to increment of
     *
     * @return Arrayy<int,int>
     *
     * @psalm-suppress InvalidReturnStatement - why?
     * @psalm-suppress InvalidReturnType - why?
     */
    public static function range(int $base, int $stop = null, int $step = 1): Arrayy
    {
        if ($stop !== null) {
            $start = $base;
        } else {
            $start = 1;
            $stop = $base;
        }

        return Arrayy::create(\range($start, $stop, $step));
    }

    /**
     * Fill an array with $times times some $data.
     *
     * @param float|int|string|null $data
     * @param int                   $times
     *
     * @return Arrayy<int,float|int|string|null>
     *
     * @psalm-suppress InvalidReturnStatement - why?
     * @psalm-suppress InvalidReturnType - why?
     */
    public static function repeat($data, int $times): Arrayy
    {
        if ($times === 0 || empty($data)) {
            return Arrayy::create();
        }

        return Arrayy::create(\array_fill(0, $times, $data));
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,array>
 */
final class ArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'array';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,bool[]>
 */
final class BoolArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'bool[]';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,bool>
 */
final class BoolCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'bool';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,callable>
 */
final class CallableCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'callable';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use function Arrayy\array_first;
use Arrayy\Arrayy;
use Arrayy\ArrayyIterator;
use Arrayy\Collection\Collection;

/**
 * @template TKey of array-key
 * @template T
 * @extends Collection<TKey,T>
 */
final class DetectFirstValueTypeCollection extends Collection implements TypeInterface
{
    /**
     * @var string
     */
    private $getTypeHelper;

    /**
     * @param array|Arrayy|mixed $data
     * @param string             $iteratorClass
     * @param bool               $checkPropertiesInConstructor
     *
     * @phpstan-param array<TKey,T>|Arrayy<TKey,T> $data
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    public function __construct(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        /**
         * @psalm-suppress RedundantConditionGivenDocblockType - We also allow other types here,
         * but I don't know how to tell psalm about that. :/
         */
        if ($data instanceof Arrayy) {
            $firstValue = $data->first();
        } elseif (\is_array($data)) {
            $firstValue = array_first($data);
        } else {
            $firstValue = $data;
            $data = [$data];
        }

        $this->getTypeHelper = $this->getTypeFromFirstValue($firstValue);

        parent::__construct(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor
        );
    }

    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return $this->getTypeHelper;
    }

    /**
     * @param mixed $value
     *
     * @return string
     */
    private function getTypeFromFirstValue($value): string
    {
        return \is_object($value) ? \get_class($value) : \gettype($value);
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,array<array-key,float>>
 */
final class FloatArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'float[]';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,float>
 */
final class FloatCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'float';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,array<array-key,float|int>>
 */
final class FloatIntArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'float[]|int[]';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,float|int>
 */
final class FloatIntCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'float|int';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\ArrayyIterator;
use Arrayy\Collection\Collection;

/**
 * @template TKey of array-key
 * @template T of object
 * @extends Collection<TKey,T>
 */
final class InstanceCollection extends Collection implements TypeInterface
{
    /**
     * @param array<object> $data
     * @param string|null   $iteratorClass
     * @param bool|null     $checkPropertiesInConstructor
     * @param string|null   $className
     *
     * @phpstan-param array<TKey,T> $data
     * @phpstan-param class-string<\Arrayy\ArrayyIterator>|null $iteratorClass
     * @phpstan-param class-string<T>|null $className
     */
    public function __construct(
        array $data = [],
        string $iteratorClass = null,
        bool $checkPropertiesInConstructor = null,
        $className = null
    ) {
        // fallback
        if ($iteratorClass === null) {
            $iteratorClass = ArrayyIterator::class;
        }
        if ($checkPropertiesInConstructor === null) {
            $checkPropertiesInConstructor = true;
        }

        parent::__construct(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor,
            self::convertIntoTypeCheckArray($className)
        );
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\ArrayyIterator;
use Arrayy\Collection\Collection;

/**
 * @template TKey of array-key
 * @template T of object
 * @extends Collection<TKey,T>
 */
final class InstancesCollection extends Collection implements TypeInterface
{
    /**
     * @param array<object> $data
     * @param string|null   $iteratorClass
     * @param bool|null     $checkPropertiesInConstructor
     * @param string[]|null $classNames
     *
     * @phpstan-param array<TKey,T> $data
     * @phpstan-param class-string<\Arrayy\ArrayyIterator>|null $iteratorClass
     * @phpstan-param array<class-string<T>>|null $classNames
     */
    public function __construct(
        array $data = [],
        string $iteratorClass = null,
        bool $checkPropertiesInConstructor = null,
        array $classNames = null
    ) {
        // fallback
        if ($iteratorClass === null) {
            $iteratorClass = ArrayyIterator::class;
        }
        if ($checkPropertiesInConstructor === null) {
            $checkPropertiesInConstructor = true;
        }

        parent::__construct(
            $data,
            $iteratorClass,
            $checkPropertiesInConstructor,
            self::convertIntoTypeCheckArray($classNames)
        );
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,int[]>
 */
final class IntArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'int[]';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,int>
 */
final class IntCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'int';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @template T of \JsonSerializable
 * @extends Collection<array-key,T>
 */
class JsonSerializableCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     *
     * @phpstan-return class-string<\JsonSerializable>
     */
    public function getType()
    {
        return \JsonSerializable::class;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,mixed>
 */
final class MixedCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'mixed';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Arrayy;
use Arrayy\Collection\Collection;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckCallback;
use Arrayy\TypeCheck\TypeCheckInterface;

/**
 * @extends Collection<array-key,non-empty-string>
 */
final class NonEmptyStringCollection extends Collection implements TypeInterface
{
    /**
     * @return TypeCheckArray<array-key, TypeCheckInterface>
     */
    public function getType()
    {
        /** @phpstan-var TypeCheckArray<array-key, TypeCheckInterface> $return */
        $return = TypeCheckArray::create(
            [
                Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckCallback(
                    static function ($value) {
                        return \is_string($value) && $value !== '';
                    }
                ),
            ]
        );

        return $return;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Arrayy;
use Arrayy\Collection\Collection;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckCallback;
use Arrayy\TypeCheck\TypeCheckInterface;

/**
 * @extends Collection<array-key,numeric>
 */
final class NumericCollection extends Collection implements TypeInterface
{
    /**
     * @return TypeCheckArray<array-key, TypeCheckInterface>
     */
    public function getType()
    {
        /** @phpstan-var TypeCheckArray<array-key, TypeCheckInterface> $return */
        $return = TypeCheckArray::create(
            [
                Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckCallback(
                    static function ($value) {
                        return \is_numeric($value);
                    }
                ),
            ]
        );

        return $return;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Arrayy;
use Arrayy\Collection\Collection;
use Arrayy\TypeCheck\TypeCheckArray;
use Arrayy\TypeCheck\TypeCheckCallback;
use Arrayy\TypeCheck\TypeCheckInterface;

/**
 * @extends Collection<array-key,numeric-string>
 */
final class NumericStringCollection extends Collection implements TypeInterface
{
    /**
     * @return TypeCheckArray<array-key, TypeCheckInterface>
     */
    public function getType()
    {
        /** @phpstan-var TypeCheckArray<array-key, TypeCheckInterface> $return */
        $return = TypeCheckArray::create(
            [
                Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckCallback(
                    static function ($value) {
                        return \is_string($value) && \is_numeric($value);
                    }
                ),
            ]
        );

        return $return;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,object>
 */
final class ObjectCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'object';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,resource>
 */
final class ResourceCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'resource';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,scalar>
 */
final class ScalarCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'scalar';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @template T of \stdClass
 * @extends Collection<array-key,T>
 */
class StdClassCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     *
     * @phpstan-return class-string<\stdClass>
     */
    public function getType()
    {
        return \stdClass::class;
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,string[]>
 */
final class StringArrayCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'string[]';
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\Type;

use Arrayy\Collection\Collection;

/**
 * @extends Collection<array-key,string>
 */
class StringCollection extends Collection implements TypeInterface
{
    /**
     * The type (FQCN) associated with this collection.
     *
     * @return string
     */
    public function getType()
    {
        return 'string';
    }
}
<?php

namespace Arrayy\Type;

interface TypeInterface
{
}
<?php

declare(strict_types=1);

namespace Arrayy\TypeCheck;

abstract class AbstractTypeCheck implements TypeCheckInterface
{
    /**
     * @var bool
     */
    protected $isNullable = false;

    /**
     * @var string[]
     */
    protected $types = [];

    /**
     * @var array<string, string>
     */
    private static $typeMapping = [
        'int'   => 'integer',
        'bool'  => 'boolean',
        'float' => 'double',
    ];

    /**
     * @return string[]
     */
    public function getTypes(): array
    {
        return $this->types;
    }

    /**
     * @param mixed $value
     *
     * @return bool
     */
    public function checkType(&$value): bool
    {
        if ($this->isNullable && $value === null) {
            return true;
        }

        foreach ($this->types as $currentType) {
            $isValidType = $this->assertTypeEquals($currentType, $value);

            if ($isValidType) {
                return true;
            }
        }

        $type = \gettype($value);

        $expectedTypes = \implode('|', $this->types);

        $this->throwException($expectedTypes, $value, $type);

        return false;
    }

    /**
     * @param string $type
     * @param mixed  $value
     *
     * @return bool
     */
    protected function assertTypeEquals(string $type, &$value): bool
    {
        if (\strpos($type, '[]') !== false) {
            return $this->isValidGenericCollection($type, $value);
        }

        if ($type === 'mixed' && $value !== null) {
            return true;
        }

        return $value instanceof $type
               ||
               \gettype($value) === (self::$typeMapping[$type] ?? $type)
               ||
               (
                   $type === 'scalar'
                    &&
                    \is_scalar($value)
               )
               ||
               (
                   $type === 'callable'
                   &&
                   \is_callable($value)
               )
               ||
               (
                   $type === 'numeric'
                   &&
                   (
                       \is_float($value)
                       ||
                       \is_int($value)
                   )
               )
               ||
               (
                   $type === 'resource'
                   &&
                   \is_resource($value)
               );
    }

    /**
     * @param mixed $value
     *
     * @return string
     */
    protected function valueToString($value): string
    {
        // null
        if ($value === null) {
            return 'NULL';
        }

        // bool
        if (\is_bool($value)) {
            return $value ? 'TRUE' : 'FALSE';
        }

        // array
        if (\is_array($value)) {
            return 'Array';
        }

        // scalar types (integer, float, string)
        if (\is_scalar($value)) {
            return (string) $value;
        }

        // resource
        if (\is_resource($value)) {
            return \get_resource_type($value) . ' resource #' . (int) $value;
        }

        if (\is_object($value)) {
            return \get_class($value) . ' Object';
        }

        return '';
    }

    /**
     * @param string $type
     * @param mixed  $collection
     *
     * @return bool
     */
    private function isValidGenericCollection(string $type, &$collection): bool
    {
        if (!\is_array($collection)) {
            return false;
        }

        $valueType = \str_replace('[]', '', $type);

        foreach ($collection as $value) {
            if ($this->assertTypeEquals($valueType, $value)) {
                return true;
            }
        }

        return false;
    }
}
<?php

namespace Arrayy\TypeCheck;

use Arrayy\Arrayy;
use Arrayy\ArrayyIterator;

/**
 * @template TKey of array-key
 * @template T
 * @extends  \Arrayy\ArrayyStrict<TKey,T>
 */
class TypeCheckArray extends \Arrayy\ArrayyStrict
{
    /**
     * Initializes
     *
     * @param mixed  $data                         <p>
     *                                             Should be an array or a generator, otherwise it will try
     *                                             to convert it into an array.
     *                                             </p>
     * @param string $iteratorClass                optional <p>
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
     *                                             need this option.
     *                                             </p>
     * @param bool   $checkPropertiesInConstructor optional <p>
     *                                             You need to extend the "Arrayy"-class and you need to set
     *                                             the $checkPropertiesMismatchInConstructor class property
     *                                             to
     *                                             true, otherwise this option didn't not work anyway.
     *                                             </p>
     *
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
     */
    public function __construct(
        $data = [],
        string $iteratorClass = ArrayyIterator::class,
        bool $checkPropertiesInConstructor = true
    ) {
        $this->properties[Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES] = new TypeCheckSimple(TypeCheckInterface::class);

        parent::__construct($data, $iteratorClass, $checkPropertiesInConstructor);
    }
}
<?php

declare(strict_types=1);

namespace Arrayy\TypeCheck;

class TypeCheckCallback implements TypeCheckInterface
{
    /**
     * @var callable
     *
     * @phpstan-var callable(mixed): bool
     */
    protected $callable;
    /**
     * @var bool
     */
    protected $isNullable = false;

    /**
     * @param callable                       $callable
     * @param bool                           $isNullable
     *
     * @phpstan-param  callable(mixed): bool $callable
     */
    public function __construct(callable $callable, bool $isNullable = false)
    {
        $this->callable = $callable;

        $this->isNullable = $isNullable;
    }

    /**
     * @param mixed $value
     *
     * @return bool
     */
    public function checkType(&$value): bool
    {
        if ($this->isNullable && $value === null) {
            return true;
        }

        if (\call_user_func($this->callable, $value)) {
            return true;
        }

        $this->throwException('', $value, \gettype($value));

        return false;
    }

    /**
     * @return array
     */
    public function getTypes(): array
    {
        return [];
    }

    /**
     * @param string $expectedTypes
     * @param mixed  $value
     * @param string $type
     *
     * @return \TypeError
     */
    public function throwException($expectedTypes, $value, $type): \Throwable
    {
        throw new \TypeError('Invalid type: callable failed, got value `' . \print_r($value, true) . "` with type {{$type}}.");
    }
}
<?php

namespace Arrayy\TypeCheck;

/**
 * inspired by https://github.com/spatie/value-object
 *
 * @internal
 */
interface TypeCheckInterface
{
    /**
     * @param mixed $value
     *
     * @return bool
     */
    public function checkType(&$value): bool;

    /**
     * @return string[]
     */
    public function getTypes(): array;

    /**
     * @param string $expectedTypes
     * @param mixed  $value
     * @param string $type
     *
     * @return \Throwable
     */
    public function throwException($expectedTypes, $value, $type): \Throwable;
}
<?php

/** @noinspection TransitiveDependenciesUsageInspection */
/** @noinspection ClassReImplementsParentInterfaceInspection */

declare(strict_types=1);

namespace Arrayy\TypeCheck;

use phpDocumentor\Reflection\Type;

/**
 * inspired by https://github.com/spatie/value-object
 *
 * @internal
 */
final class TypeCheckPhpDoc extends AbstractTypeCheck implements TypeCheckInterface
{
    /**
     * @var bool
     */
    private $hasTypeDeclaration = false;

    /**
     * @var string
     */
    private $property_name;

    /**
     * @param string $reflectionPropertyName
     */
    public function __construct($reflectionPropertyName)
    {
        $this->property_name = $reflectionPropertyName;
    }

    /**
     * @param \phpDocumentor\Reflection\DocBlock\Tags\Property $phpDocumentorReflectionProperty
     * @param string                                           $property
     *
     * @return self|null
     */
    public static function fromPhpDocumentorProperty(\phpDocumentor\Reflection\DocBlock\Tags\Property $phpDocumentorReflectionProperty, string $property = '')
    {
        if (!$property) {
            /** @var string|null $propertyTmp */
            $propertyTmp = $phpDocumentorReflectionProperty->getVariableName();
            if ($propertyTmp === null) {
                return null;
            }

            $property = $propertyTmp;
        }

        $tmpObject = new \stdClass();
        $tmpObject->{$property} = null;

        $tmpReflection = new self((new \ReflectionProperty($tmpObject, $property))->getName());

        $type = $phpDocumentorReflectionProperty->getType();

        /** @noinspection PhpSillyAssignmentInspection */
        /** @var Type|null $type */
        $type = $type;

        if ($type) {
            $tmpReflection->hasTypeDeclaration = true;

            $docTypes = self::parseDocTypeObject($type);
            if (\is_array($docTypes) === true) {
                foreach ($docTypes as $docType) {
                    $tmpReflection->types[] = $docType;
                }
            } else {
                $tmpReflection->types[] = $docTypes;
            }

            if (\in_array('null', $tmpReflection->types, true)) {
                $tmpReflection->isNullable = true;
            }
        }

        return $tmpReflection;
    }

    /**
     * @param \phpDocumentor\Reflection\Type $type
     *
     * @return string|string[]
     */
    public static function parseDocTypeObject($type)
    {
        if ($type instanceof \phpDocumentor\Reflection\Types\Object_) {
            $tmpObject = (string) $type->getFqsen();
            if ($tmpObject) {
                return $tmpObject;
            }

            return 'object';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Compound) {
            $types = [];
            foreach ($type as $subType) {
                $typeTmp = self::parseDocTypeObject($subType);

                /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
                /** @var string $typeTmp */
                $typeTmp = $typeTmp;

                $types[] = $typeTmp;
            }

            return $types;
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Array_) {
            $valueTypeTmp = $type->getValueType()->__toString();
            if ($valueTypeTmp !== 'mixed') {
                return $valueTypeTmp . '[]';
            }

            return 'array';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Null_) {
            return 'null';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Mixed_) {
            return 'mixed';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Scalar) {
            return 'string|int|float|bool';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Boolean) {
            return 'bool';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Callable_) {
            return 'callable';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Float_) {
            return 'float';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\String_) {
            return 'string';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Integer) {
            return 'int';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Void_) {
            return 'void';
        }

        if ($type instanceof \phpDocumentor\Reflection\Types\Resource_) {
            return 'resource';
        }

        return $type->__toString();
    }

    /**
     * @param string $expectedTypes
     * @param mixed  $value
     * @param string $type
     *
     * @return \TypeError
     */
    public function throwException($expectedTypes, $value, $type): \Throwable
    {
        throw new \TypeError("Invalid type: expected \"{$this->property_name}\" to be of type {{$expectedTypes}}, instead got value \"" . $this->valueToString($value) . '" (' . \print_r($value, true) . ") with type {{$type}}.");
    }
}
<?php

/** @noinspection ClassReImplementsParentInterfaceInspection */

declare(strict_types=1);

namespace Arrayy\TypeCheck;

class TypeCheckSimple extends AbstractTypeCheck implements TypeCheckInterface
{
    /**
     * @param string|string[] $type
     * @param bool            $isNullable
     */
    public function __construct($type, bool $isNullable = false)
    {
        $this->getTypesHelper($type);

        $this->isNullable = $isNullable;
    }

    /**
     * @param string $expectedTypes
     * @param mixed  $value
     * @param string $type
     *
     * @return \TypeError
     */
    public function throwException($expectedTypes, $value, $type): \Throwable
    {
        throw new \TypeError("Invalid type: expected to be of type {{$expectedTypes}}, instead got value `" . \print_r($value, true) . "` with type {{$type}}.");
    }

    /**
     * @param string|string[] $type
     *
     * @return void
     */
    protected function getTypesHelper($type)
    {
        if (\is_array($type)) {
            foreach ($type as $typeTmp) {
                $this->getTypesHelper($typeTmp);
            }

            return;
        }

        if (\strpos($type, '|') !== false) {
            $typesTmp = \explode('|', $type);

            foreach ($typesTmp as $typeTmp) {
                $this->types[] = $typeTmp;
            }
        } else {
            $this->types[] = $type;
        }
    }
}
<?php

return [
    'test.de',
    'test.com',
    'test.net',
    'test.org',
    'example.de',
    'example.com',
    'example.net',
    'example.org',
];
<?php

/**
 * ... here you can find more domains:
 *
 * - https://github.com/vboctor/disposable_email_checker
 * - https://github.com/andreis/disposable
 * - https://gist.github.com/michenriksen/8710649
 */

/*
 * ... skip all this domain ...
 *
 * *.tk
 * *.ml
 * *.ga
 * *.cf
 * *.gq
 */

return [
    '0-00.usa.cc',
    '0-mail.com',
    '001.igg.biz',
    '027168.com',
    '0815.ru',
    '0815.ry',
    '0815.su',
    '0845.ru',
    '0box.eu',
    '0celot.com',
    '0clickemail.com',
    '0clock.net',
    '0clock.org',
    '0hboy.com',
    '0hdear.com',
    '0hio.net',
    '0hio.org',
    '0hio0ak.com',
    '0hiolce.com',
    '0hioln.com',
    '0ils.net',
    '0ils.org',
    '0ioi.net',
    '0kok.net',
    '0kok.org',
    '0ld0ak.com',
    '0ld0x.com',
    '0live.org',
    '0mel.com',
    '0mixmail.info',
    '0nce.net',
    '0ne0ak.com',
    '0nes.net',
    '0nes.org',
    '0nly.org',
    '0regon.net',
    '0regon.org',
    '0sg.net',
    '0u.ro',
    '0utln.com',
    '0v.ro',
    '0w.ro',
    '0wnd.net',
    '0wnd.org',
    '0x00.name',
    '0x207.info',
    '1-8.biz',
    '1000rebates.stream',
    '100kti.xyz',
    '100likers.com',
    '101price.co',
    '10host.top',
    '10launcheds.com',
    '10mail.com',
    '10mail.org',
    '10minut.com.pl',
    '10minut.xyz',
    '10minutemail.be',
    '10minutemail.co.uk',
    '10minutemail.co.za',
    '10minutemail.com',
    '10minutemail.de',
    '10minutemail.info',
    '10minutemail.net',
    '10minutemail.nl',
    '10minutemail.org',
    '10minutemail.pro',
    '10minutemail.ru',
    '10minutemail.us',
    '10minutemailbox.com',
    '10minutemails.in',
    '10minutenemail.de',
    '10minutesmail.com',
    '10minutesmail.fr',
    '10minutesmail.net',
    '10minutesmail.ru',
    '10minutetempemail.com',
    '10minutmail.pl',
    '10vpn.info',
    '10x.es',
    '10x9.com',
    '11163.com',
    '117.yyolf.net',
    '11top.xyz',
    '123-m.com',
    '1236456.com',
    '12ab.info',
    '12hosting.net',
    '12houremail.com',
    '12minutemail.com',
    '12minutemail.net',
    '12storage.com',
    '1337.email',
    '140unichars.com',
    '147.cl',
    '14n.co.uk',
    '15qm-mail.red',
    '15qm.com',
    '1aolmail.com',
    '1blackmoon.com',
    '1ce.us',
    '1chuan.com',
    '1clck2.com',
    '1dmedical.com',
    '1googlemail.com',
    '1lv.in',
    '1mail.uk.to',
    '1mail.x24hr.com',
    '1pad.de',
    '1rentcar.top',
    '1s.fr',
    '1shivom.com',
    '1ss.noip.me',
    '1st-forms.com',
    '1thecity.biz',
    '1to1mail.org',
    '1usemail.com',
    '1webmail.info',
    '1website.net',
    '1zhuan.com',
    '2-ch.space',
    '2.0-00.usa.cc',
    '2.sexymail.ooo',
    '2.tebwinsoi.ooo',
    '2000rebates.stream',
    '200555.com',
    '2012-2016.ru',
    '2014mail.ru',
    '20boxme.org',
    '20email.eu',
    '20email.it',
    '20mail.eu',
    '20mail.in',
    '20mail.it',
    '20minute.email',
    '20minutemail.com',
    '20minutemail.it',
    '20mm.eu',
    '2120001.net',
    '21cn.com',
    '24facet.com',
    '24hinbox.com',
    '24hourmail.com',
    '24hourmail.net',
    '24mail.top',
    '24mail.xyz',
    '291.usa.cc',
    '2anom.com',
    '2ch.coms.hk',
    '2ch.daemon.asia',
    '2ch.orgs.hk',
    '2ether.net',
    '2k18.mailr.eu',
    '2nd-mail.xyz',
    '2odem.com',
    '2prong.com',
    '2sea.org',
    '2sea.xyz',
    '2viewerl.com',
    '2wc.info',
    '300book.info',
    '30mail.ir',
    '30minutemail.com',
    '30minutenmail.eu',
    '30wave.com',
    '31k.it',
    '3202.com',
    '333.igg.biz',
    '33m.co',
    '33mail.com',
    '3675.mooo.com',
    '36ru.com',
    '3d-painting.com',
    '3ew.usa.cc',
    '3l6.com',
    '4-n.us',
    '4057.com',
    '4059.com',
    '418.dk',
    '41v1relaxn.com',
    '420blaze.it',
    '42o.org',
    '44556677.igg.biz',
    '45kti.xyz',
    '466453.usa.cc',
    '487.nut.cc',
    '4nmv.ru',
    '4orty.com',
    '4pet.ro',
    '4tb.host',
    '4w.io',
    '4warding.com',
    '4warding.net',
    '4warding.org',
    '510520.org',
    '54np.club',
    '555gmail.com',
    '55hosting.net',
    '5dsmartstore.com',
    '5gramos.com',
    '5july.org',
    '5mail.xyz',
    '5music.info',
    '5music.top',
    '5oz.ru',
    '5x25.com',
    '5ymail.com',
    '6-6-6.flu.cc',
    '6-6-6.igg.biz',
    '6-6-6.nut.cc',
    '6-6-6.usa.cc',
    '60-minuten-mail.de',
    '60minutemail.com',
    '666-evil.com',
    '672643.net',
    '675hosting.com',
    '675hosting.net',
    '675hosting.org',
    '68mail.com',
    '69postix.info',
    '6ceqs4enix.co19.kr',
    '6ip.us',
    '6paq.com',
    '6url.com',
    '71compete.com',
    '75hosting.com',
    '75hosting.net',
    '75hosting.org',
    '79mail.com',
    '7days-printing.com',
    '7ddf32e.info',
    '7mail.xyz',
    '7mail7.com',
    '7rent.top',
    '7tags.com',
    '806.flu.cc',
    '80665.com',
    '8127ep.com',
    '8191.at',
    '8290.com',
    '82c8.com',
    '88clean.pro',
    '8chan.co',
    '900k.es',
    '91000.com',
    '99.com',
    '99experts.com',
    '99hacks.us',
    '99price.co',
    '99pubblicita.com',
    '9me.site',
    '9ox.net',
    '9q.ro',
    '9toplay.com',
    '9xmail.xyz',
    '9ya.de',
    'a-b.co.za',
    'a-bc.net',
    'a.a.fbmail.usa.cc',
    'a.betr.co',
    'a.sach.ir',
    'a.wxnw.net',
    'a0.igg.biz',
    'a0f7ukc.com',
    'a1.usa.cc',
    'a1aemail.win',
    'a2.flu.cc',
    'a41odgz7jh.com',
    'a41odgz7jh.com.com',
    'a45.in',
    'a54pd15op.com',
    'a7996.com',
    'a84doctor.com',
    'aa5zy64.com',
    'aaathats3as.com',
    'aaaw45e.com',
    'aalna.org',
    'aamail.co',
    'ab0.igg.biz',
    'abacuswe.us',
    'abakiss.com',
    'abanksat.us',
    'abcmail.email',
    'abcmail.men',
    'abcz.info.tm',
    'abigail69.sexy',
    'abilityskillup.info',
    'abilitywe.us',
    'abnamro.usa.cc',
    'abogadanotariapr.com',
    'abovewe.us',
    'absolutesuccess.win',
    'absolutewe.us',
    'abundantwe.us',
    'abusemail.de',
    'abuser.eu',
    'abv.bg',
    'abyssemail.com',
    'abyssmail.com',
    'ac20mail.in',
    'academiccommunity.com',
    'academywe.us',
    'acceleratewe.us',
    'accentwe.us',
    'acceptwe.us',
    'accesorii.info',
    'acclaimwe.us',
    'accordwe.us',
    'accreditedwe.us',
    'acentri.com',
    'acgapp.hk',
    'achievementwe.us',
    'achievewe.us  ',
    'achievewe.us',
    'acornwe.us',
    'acres.asia',
    'acrylicwe.us',
    'activatewe.us',
    'activitywe.us',
    'acucre.com',
    'acuitywe.us',
    'acumenwe.us',
    'adamastore.co',
    'adaptivewe.us',
    'adaptwe.us',
    'adbet.co',
    'add3000.pp.ua',
    'addictingtrailers.com',
    'adel.asia',
    'adelaide.bike',
    'adeptwe.us',
    'adesktop.com',
    'adipex7z.com',
    'adiq.eu',
    'aditus.info',
    'admiralwe.us',
    'ado888.biz',
    'adobeccepdm.com',
    'adoniswe.us',
    'adpugh.org',
    'adresseemailtemporaire.com',
    'adroit.asia',
    'adsd.org',
    'adubiz.info',
    'advantagewe.us',
    'advantimal.com',
    'advantimals.com',
    'advantimo.com',
    'adventurewe.us',
    'adventwe.us',
    'advisorwe.us',
    'advocatewe.us',
    'adwaterandstir.com',
    'adx-telecom.com',
    'ae.pureskn.com',
    'aegde.com',
    'aegia.net',
    'aegiscorp.net',
    'aegiswe.us',
    'aelo.es',
    'aeonpsi.com',
    'aesopsfables.net',
    'affiliate-nebenjob.info',
    'affiliatedwe.us',
    'affilikingz.de',
    'affinitywe.us',
    'affluentwe.us',
    'affordablewe.us',
    'affricca.com',
    'afmail.com',
    'afrobacon.com',
    'afterhourswe.us',
    'ag.us.to',
    'agedmail.com',
    'agendawe.us',
    'agger.ro',
    'agilewe.us',
    'agistore.co',
    'agorawe.us',
    'agristyleapparel.us',
    'agtx.net',
    'agustusmp3.xyz',
    'aheadwe.us',
    'ahk.jp',
    'air2token.com',
    'airknox.com',
    'airmail.cc',
    'airmail.tech',
    'airmailhub.com',
    'airsi.de',
    'airsoftshooters.com',
    'airwayy.us',
    'aistis.xyz',
    'ajaxapp.net',
    'aji.kr',
    'aju.onlysext.com',
    'akademiyauspexa.xyz',
    'akapost.com',
    'akerd.com',
    'akgq701.com',
    'akhost.trade',
    'akorde.al',
    'aktiefmail.nl',
    'al-qaeda.us',
    'albionwe.us',
    'alchemywe.us',
    'aldeyaa.ae',
    'alessia1818.site',
    'alfamailr.org',
    'alfaromeo.igg.biz',
    'aliaswe.us',
    'alienware13.com',
    'aligamel.com',
    'alimunjaya.xyz',
    'alisongamel.com',
    'alivance.com',
    'alivewe.us',
    'allaccesswe.us',
    'allamericanwe.us',
    'allaroundwe.us',
    'alldirectbuy.com',
    'allegiancewe.us',
    'allegrowe.us',
    'allen.nom.za',
    'allfamus.com',
    'allgoodwe.us',
    'alliancewe.us',
    'allinonewe.us',
    'allofthem.net',
    'alloutwe.us',
    'allowed.org',
    'alloywe.us',
    'allprowe.us',
    'allseasonswe.us',
    'allstarwe.us',
    'allthegoodnamesaretaken.org',
    'allurewe.us',
    'almondwe.us',
    'alph.wtf',
    'alphaomegawe.us',
    'alpinewe.us',
    'alsheim.no-ip.org',
    'altairwe.us',
    'altitudewe.us',
    'altuswe.us',
    'alumnimp3.xyz',
    'ama-trade.de',
    'ama-trans.de',
    'amadamus.com',
    'amadeuswe.us',
    'amail.club',
    'amail.com',
    'amail.men',
    'amail4.me',
    'amav.ro',
    'amazon-aws.org',
    'amazon.coms.hk',
    'ambassadorwe.us',
    'amberwe.us',
    'ambiancewe.us',
    'ambitiouswe.us',
    'amelabs.com',
    'americanawe.us',
    'americasbestwe.us',
    'americaswe.us',
    'amhar.asia',
    'amicuswe.us',
    'amigowe.us',
    'amilegit.com',
    'amiri.net',
    'amiriindustries.com',
    'amitywe.us',
    'amoksystems.com',
    'amplewe.us',
    'amplifiedwe.us',
    'amplifywe.us',
    'ampsylike.com',
    'amyxrolest.com',
    'an.id.au',
    'anal.accesscam.org',
    'analogwe.us',
    'analysiswe.us',
    'analyticalwe.us',
    'analyticswe.us',
    'analyticwe.us',
    'anappfor.com',
    'anappthat.com',
    'ancientart.co',
    'andetne.win',
    'andreabello.it',
    'andreihusanu.ro',
    'andthen.us',
    'anhthu.org',
    'animesos.com',
    'anit.ro',
    'ankoninc.pw',
    'ano-mail.net',
    'anon-mail.de',
    'anon.leemail.me',
    'anonbox.net',
    'anonmail.top',
    'anonmail.xyz',
    'anonmails.de',
    'anonymail.dk',
    'anonymbox.com',
    'anonymize.com',
    'anonymized.org',
    'anonymous-email.net',
    'anonymousfeedback.net',
    'anonymousmail.org',
    'anonymousness.com',
    'anonymousspeech.com',
    'ansibleemail.com',
    'anthony-junkmail.com',
    'anthropologycommunity.com',
    'antichef.com',
    'antichef.net',
    'antichef.org',
    'antireg.com',
    'antireg.ru',
    'antispam.de',
    'antispam24.de',
    'antispammail.de',
    'antonietta1818.site',
    'anyalias.com',
    'anyett.com',
    'anypen.accountant',
    'anywhere.pw',
    'ao4ffqty.com',
    'aoeuhtns.com',
    'apegarden.agency',
    'apfelkorps.de',
    'aphlog.com',
    'apkmd.com',
    'apotekerid.com',
    'apown.com',
    'appc.se',
    'appdev.science',
    'appdollars.com',
    'appinventor.nl',
    'appixie.com',
    'applynow0.com',
    'apps.dj',
    'aprice.co',
    'aptcha.com',
    'arakcarpet.ir',
    'arcticside.com',
    'arduino.hk',
    'area-thinking.de',
    'argand.nl',
    'ariaz.jetzt',
    'armyspy.com',
    'arno.fi',
    'arockee.com',
    'aron.us',
    'arroisijewellery.com',
    'art-en-ligne.pro',
    'artdrip.com',
    'artlover.shop',
    'artman-conception.com',
    'arvato-community.de',
    'as.onlysext.com',
    'asana.biz',
    'aschenbrandt.net',
    'asdasd.nl',
    'asdasd.ru',
    'asdf.pl',
    'asdfasdfmail.net',
    'asdfghmail.com',
    'asdfmail.net',
    'asdhgsad.com',
    'asfdasd.com',
    'ashik2in.com',
    'ashleyandrew.com',
    'asiarap.usa.cc',
    'asik2in.biz',
    'asik2in.com',
    'asiki2in.com',
    'asm.snapwet.com',
    'asooemail.net',
    'asorent.com',
    'ass.pp.ua',
    'asspoo.com',
    'assurancespourmoi.eu',
    'astroempires.info',
    'astropink.com',
    'asu.mx',
    'asu.su',
    'at.hm',
    'at0mik.org',
    'athens5.com',
    'atlanticyu.com',
    'attnetwork.com',
    'atvclub.msk.ru',
    'audi.igg.biz',
    'audiobrush.com',
    'augmentationtechnology.com',
    'auoie.com',
    'ausgefallen.info',
    'auti.st',
    'autorobotica.com',
    'autotwollow.com',
    'aver.com',
    'averdov.com',
    'avia-tonic.fr',
    'aviani.com',
    'avls.pt',
    'avr.ze.cx',
    'aw.kikwet.com',
    'awatum.de',
    'awiki.org',
    'aws910.com',
    'awsoo.com',
    'ax80mail.com',
    'axeprim.eu',
    'axiz.org',
    'axon7zte.com',
    'axsup.net',
    'ay33rs.flu.cc',
    'ayuh.myvnc.com',
    'azcomputerworks.com',
    'azjuggalos.com',
    'b.reed.to',
    'b0.nut.cc',
    'b1of96u.com',
    'b2bx.net',
    'b2cmail.de',
    'b2email.win',
    'b5safaria.com',
    'b6vscarmen.com',
    'b9x45v1m.com',
    'b9x45v1m.com.com',
    'babe-store.com',
    'babesstore.com',
    'babylonize.com',
    'backalleybowling.info',
    'baconporker.com',
    'badamm.us',
    'badgerland.eu',
    'badhus.org',
    'badoo.live',
    'badoop.com',
    'bakar.bid',
    'balanc3r.com',
    'ballsofsteel.net',
    'bandai.nom.co',
    'bangsat.in',
    'banhbeovodich.vn',
    'banit.club',
    'banit.me',
    'baomoi.site',
    'barbarrianking.com',
    'bareck.net',
    'bareed.ws',
    'barrabravaz.com',
    'barryogorman.com',
    'barrypov.com',
    'barryspov.com',
    'bartdevos.be',
    'bartoparcadecabinet.com',
    'basketball2in.com',
    'basscode.org',
    'basssi.today',
    'bastore.co',
    'batpeer.site',
    'battricks.com',
    'bauwerke-online.com',
    'baxomale.ht.cx',
    'bazaaboom.com',
    'bbbbyyzz.info',
    'bbhost.us',
    'bbmail.win',
    'bcast.ws',
    'bcb.ro',
    'bccto.me',
    'bcdmail.date',
    'bcompiled3.com',
    'bdmuzic.pw',
    'bearsarefuzzy.com',
    'beck-it.net',
    'beddly.com',
    'beefmilk.com',
    'beerolympics.se',
    'begoz.com',
    'bei.kr',
    'bel.kr',
    'belamail.org',
    'belastingdienst.pw',
    'belediyeevleri2noluasm.com',
    'belljonestax.com',
    'benipaula.org',
    'beo.kr',
    'best-day.pw',
    'bestchoiceusedcar.com',
    'bestday.pw',
    'bestfuture.pw',
    'bestlucky.pw',
    'bestofprice.co',
    'bestoption25.club',
    'bestvpn.top',
    'bestwishes.pw',
    'betaprice.co',
    'betr.co',
    'beupmore.win',
    'beverlytx.com',
    'bfo.kr',
    'bgi-sfr-i.pw',
    'bgisfri.pw',
    'bgtmail.com',
    'bgx.ro',
    'bhadoomail.com',
    'bho.hu',
    'bho.kr',
    'bidourlnks.com',
    'big1.us',
    'bigcrop.pro',
    'biglive.asia',
    'bigmack.33mail.com',
    'bigprofessor.so',
    'bigstring.com',
    'bigwhoop.co.za',
    'bigwiki.xyz',
    'bij.pl',
    'bin.8191.at',
    'binka.me',
    'binkmail.com',
    'binnary.com',
    'bio-muesli.info',
    'bio-muesli.net',
    'biometicsliquidvitamins.com',
    'bione.co',
    'birbakmobilya.com',
    'birdsfly.press',
    'biscutt.us',
    'bit-degree.com',
    'bit2tube.com',
    'bitwerke.com',
    'bitwhites.top',
    'bitymails.us',
    'biz.st',
    'bizimalem-support.de',
    'bki7rt6yufyiguio.ze.am',
    'bko.kr',
    'blackhole.djurby.se',
    'blackhole.targeter.nl',
    'blackmarket.to',
    'bladesmail.net',
    'blinkmatrix.com',
    'blip.ch',
    'blnkt.net',
    'bloatbox.com',
    'blockdigichain.com',
    'bloggersxmi.com',
    'blogmyway.org',
    'blogos.com',
    'blogos.net',
    'blogspam.ro',
    'bloq.ro',
    'blow-job.nut.cc',
    'bloxter.cu.cc',
    'bluebottle.com',
    'bluedumpling.info',
    'bluewerks.com',
    'blutig.me',
    'bmpk.org',
    'bnuis.com',
    'boastfusion.com',
    'boatmail.us',
    'bobablast.com',
    'bobmail.info',
    'bobmurchison.com',
    'bodhi.lawlita.com',
    'bofthew.com',
    'bogotadc.info',
    'boimail.com',
    'bonobo.email',
    'bookthemmore.com',
    'booktoplady.com',
    'bookyah.com',
    'bootybay.de',
    'bopunkten.se',
    'borged.com',
    'borged.net',
    'borged.org',
    'borgish.com',
    'bossmail.de',
    'bot.nu',
    'botz.online',
    'boun.cr',
    'bouncr.com',
    'box.yadavnaresh.com.np',
    'boxformail.in',
    'boximail.com',
    'boxmail.co',
    'boxtemp.com.br',
    'bqm2dyl.com',
    'brainonfire.net',
    'brandallday.net',
    'brasx.org',
    'breadtimes.press',
    'breakthru.com',
    'brefmail.com',
    'brennendesreich.de',
    'briefkasten2go.de',
    'briggsmarcus.com',
    'bring-luck.pw',
    'bringluck.pw',
    'britishintelligence.co.uk',
    'broadbandninja.com',
    'broilone.com',
    'browniesgoreng.com',
    'brownieslumer.com',
    'bsnow.net',
    'bspamfree.org',
    'bspooky.com',
    'bst-72.com',
    'bt3019k.com',
    'btb-notes.com',
    'btc.email',
    'btcmail.pw',
    'btizet.pl',
    'buchhandlung24.com',
    'budaya-tionghoa.com',
    'budayationghoa.com',
    'budin.men',
    'buffemail.com',
    'bugmenever.com',
    'bugmenot.com',
    'bulrushpress.com',
    'bum.net',
    'bumppack.com',
    'bumpymail.com',
    'bunchofidiots.com',
    'bund.us',
    'bunsenhoneydew.com',
    'burgercentral.us',
    'burner-email.com',
    'burnmail.ca',
    'burnthespam.info',
    'burstmail.info',
    'businessbackend.com',
    'businesscredit.xyz',
    'businesssuccessislifesuccess.com',
    'buspad.org',
    'bussitussi.com',
    'butter9x.com',
    'buxap.com',
    'buy003.com',
    'buygapfashion.com',
    'buymoreplays.com',
    'buyordie.info',
    'buyprice.co',
    'buyusedlibrarybooks.org',
    'buzzcluby.com',
    'buzzcompact.com',
    'bwa33.net',
    'by8006l.com',
    'byebyemail.com',
    'byespm.com',
    'byom.de',
    'c.andreihusanu.ro',
    'c.hcac.net',
    'c.kadag.ir',
    'c.nut.emailfake.nut.cc',
    'c.theplug.org',
    'c.wlist.ro',
    'c1oramn.com',
    'c2.hu',
    'c3email.win',
    'c51vsgq.com',
    'c7fk799.com',
    'cabekeriting99.com',
    'cachedot.net',
    'cafecar.xyz',
    'cakk.us',
    'californiafitnessdeals.com',
    'cam4you.cc',
    'campano.cl',
    'camping-grill.info',
    'candymail.de',
    'cane.pw',
    'cannoncrew.com',
    'cano.cl',
    'car101.pro',
    'caramail.pro',
    'carbtc.net',
    'card.zp.ua',
    'careless-whisper.com',
    'carins.io',
    'carrnelpartners.com',
    'cars2.club',
    'carsencyclopedia.com',
    'cart332.club',
    'cartelera.org',
    'caspianfan.ir',
    'casualdx.com',
    'catch.everton.com',
    'catchonline.ooo',
    'caugiay.tech',
    'cavi.mx',
    'cbair.com',
    'cbes.net',
    'cbgh.ddns.me',
    'cc-cc.usa.cc',
    'cc.liamria',
    'ccmail.men',
    'cd.mintemail.com',
    'cd2in.com',
    'cdcmail.date',
    'cdnqa.com',
    'cdpa.cc',
    'ce.mintemail.com',
    'ceed.se',
    'cek.pm',
    'cellurl.com',
    'cem.net',
    'centermail.com',
    'centermail.net',
    'centol.us',
    'central-servers.xyz',
    'cetpass.com',
    'cfo2go.ro',
    'ch.tc',
    'chacuo.net',
    'chaichuang.com',
    'chalupaurybnicku.cz',
    'chammy.info',
    'champmails.com',
    'changingemail.com',
    'chaonamdinh.com',
    'chaosi0t.com',
    'cheap3ddigitalcameras.com',
    'cheaphorde.com',
    'cheaphub.net',
    'cheatmail.de',
    'chechnya.conf.work',
    'checknew.pw',
    'chef.asana.biz',
    'chewcow.com',
    'chewiemail.com',
    'chickenkiller.com',
    'chielo.com',
    'childsavetrust.org',
    'chilelinks.cl',
    'chilkat.com',
    'chinatov.com',
    'chipkolik.com',
    'chithinh.com',
    'chocklet.us',
    'choco.la',
    'chogmail.com',
    'choicemail1.com',
    'chokiwnl.men',
    'chong-mail.com',
    'chong-mail.net',
    'chong-mail.org',
    'choqr6r4.com',
    'chris.burgercentral.us',
    'christopherfretz.com',
    'chumpstakingdumps.com',
    'cid.kr',
    'cigar-auctions.com',
    'civilizationdesign.xyz',
    'civvic.ro',
    'civx.org',
    'cjpeg.com',
    'ckiso.com',
    'cko.kr',
    'ckoie.com',
    'cl-cl.org',
    'cl.gl',
    'cl0ne.net',
    'clandest.in',
    'clarkgriswald.net',
    'clashatclintonemail.com',
    'clay.xyz',
    'clean.pro',
    'clearwatermail.info',
    'clendere.asia',
    'clickanerd.net',
    'clickdeal.co',
    'clinicatbf.com',
    'clintonemailhearing.com',
    'clipmail.eu',
    'clixser.com',
    'clonefbtmc1.club',
    'cloneviptmc1.club',
    'cloud99.pro',
    'cloud99.top',
    'cloudemail.xyz',
    'cloudns.cc',
    'cloudns.cx',
    'cloudstreaming.info',
    'clrmail.com',
    'cls-audio.club',
    'clubfier.com',
    'clubstt.com',
    'clue-1.com',
    'cmail.club',
    'cmail.com',
    'cmail.net',
    'cmail.org',
    'cnamed.com',
    'cnew.ir',
    'cnmsg.net',
    'cnn.coms.hk',
    'cnsds.de',
    'co.cc',
    'cobin2hood.com',
    'cocaine.ninja',
    'cock.email',
    'cock.li',
    'cock.lu',
    'cocovpn.com',
    'codeandscotch.com',
    'codivide.com',
    'codupmyspace.com',
    'codyting.com',
    'cognitiveways.xyz',
    'coieo.com',
    'coldemail.info',
    'collapse3b.com',
    'com.ar',
    'combustore.co',
    'come-on-day.pw',
    'comeonday.pw',
    'comilzilla.org',
    'comm.craigslist.org',
    'comments2g.com',
    'communitybuildingworks.xyz',
    'compareshippingrates.org',
    'completegolfswing.com',
    'coms.hk',
    'comsafe-mail.net',
    'comwest.de',
    'concealed.company',
    'conf.work',
    'confidential.life',
    'config.work',
    'confirm.live',
    'consumerriot.com',
    'contbay.com',
    'contentwanted.com',
    'contractor.net',
    'contrasto.cu.cc',
    'conventionstrategy.win',
    'cookiecooker.de',
    'cool-your.pw',
    'cool.fr.nf',
    'coolandwacky.us',
    'coolimpool.org',
    'coolmail.ooo',
    'coolyour.pw',
    'copastore.co',
    'coreclip.com',
    'correo.blogos.net',
    'cortex.kicks-ass.net',
    'cosmorph.com',
    'courriel.fr.nf',
    'courrieltemporaire.com',
    'courtrf.com',
    'cousinit.mooo.com',
    'coza.ro',
    'cpsystems.ru',
    'cr219.com',
    'cr97mt49.com',
    'crankhole.com',
    'crankmails.com',
    'crap.kakadua.net',
    'crapmail.org',
    'crastination.de',
    'crazespaces.pw',
    'crazydoll.us',
    'crazymailing.com',
    'cream.pink',
    'creazionisa.com',
    'crossroadsmail.com',
    'crowity.com',
    'crusthost.com',
    'crydeck.com',
    'crymail2.com',
    'cryp.email',
    'crypemail.info',
    'crypstats.top',
    'csh.ro',
    'csoftmail.cn',
    'cszbl.com',
    'ctmailing.us',
    'ctos.ch',
    'cu.cc',
    'cubiclink.com',
    'cucummail.com',
    'cuirushi.org',
    'cultmovie.com',
    'cumallover.me',
    'cumangeblog.net',
    'cumanuallyo.com',
    'curryworld.de',
    'curso.tech',
    'cursodemicropigmentacao.us',
    'cust.in',
    'customs2g3.com',
    'cutout.club',
    'cuvox.de',
    'cx.de-a.org',
    'cyber-innovation.club',
    'cyber-phone.eu',
    'cybersex.com',
    'cylab.org',
    'czqjii8.com',
    'd.megafon.org.ua',
    'd1yun.com',
    'd3p.dk',
    'd58pb91.com',
    'd8u.us',
    'dab.ro',
    'dacha-24.ru',
    'dacoolest.com',
    'dadd.kikwet.com',
    'daemsteam.com',
    'dahongying.net',
    'daibond.info',
    'daintly.com',
    'damai.webcam',
    'dammexe.net',
    'damnthespam.com',
    'dancemanual.com',
    'danceml.win',
    'dandikmail.com',
    'daphnee1818.site',
    'dark-tempmail.zapto.org',
    'darkharvestfilms.com',
    'darknode.org',
    'daryxfox.net',
    'dash-pads.com',
    'dashoffer.com',
    'dataarca.com',
    'datab.info',
    'datarca.com',
    'datazo.ca',
    'datum2.com',
    'davidkoh.net',
    'davidlcreative.com',
    'dawin.com',
    'day-one.pw',
    'dayone.pw',
    'dayrep.com',
    'dbo.kr',
    'dbunker.com',
    'dbz5mchild.com',
    'dcemail.com',
    'dcemail.men',
    'ddcrew.com',
    'ddmail.win',
    'ddnsfree.com',
    'ddosed.us',
    'de-a.org',
    'de.sytes.net',
    'dea.soon.it',
    'deadaddress.com',
    'deadchildren.org',
    'deadspam.com',
    'deagot.com',
    'dealja.com',
    'dealrek.com',
    'decoymail.mx',
    'deekayen.us',
    'definingjtl.com',
    'defomail.com',
    'degradedfun.net',
    'delayload.com',
    'delayload.net',
    'delikkt.de',
    'demandfull.date',
    'demandsxz.com',
    'demesmaeker.fr',
    'dennmail.win',
    'density2v.com',
    'der-kombi.de',
    'der.madhuratri.com',
    'derder.net',
    'derkombi.de',
    'derluxuswagen.de',
    'designersadda.com',
    'despam.it',
    'despammed.com',
    'deucemail.com',
    'devnullmail.com',
    'dextm.ro',
    'deyom.com',
    'dff55.dynu.net',
    'dfg6.kozow.com',
    'dfgggg.org',
    'dfgh.net',
    'dgd.mail-temp.com',
    'dharmatel.net',
    'dhm.ro',
    'dhy.cc',
    'dialogus.com',
    'diapaulpainting.com',
    'dicksinhisan.us',
    'dicksinmyan.us',
    'diennuocnghiahue.com',
    'digdown.xyz',
    'digiprice.co',
    'digitalesbusiness.info',
    'digitalmariachis.com',
    'digitalsanctuary.com',
    'dildosfromspace.com',
    'dim-coin.com',
    'dingbone.com',
    'dinkmail.com',
    'directmonitor.nl',
    'dirtymax.com',
    'dirtysex.top',
    'disaq.com',
    'disario.info',
    'disbox.net',
    'disbox.org',
    'discard.email',
    'discardmail.com',
    'discardmail.de',
    'discordmail.com',
    'discos4.com',
    'discoverwatch.com',
    'discreetfuck.top',
    'disign-concept.eu',
    'disign-revelation.com',
    'dispo.in',
    'dispomail.eu',
    'dispomail.xyz',
    'disposable-mail.com',
    'disposable.dhc-app.com',
    'disposableaddress.com',
    'disposableemail.org',
    'disposableemailaddresses.com',
    'disposableemailaddresses.emailmiser.com',
    'disposableinbox.com',
    'disposablemail.space',
    'disposablemails.com',
    'dispose.it',
    'disposeamail.com',
    'disposemail.com',
    'dispostable.com',
    'divermail.com',
    'dividendxk.com',
    'divismail.ru',
    'diwaq.com',
    'dko.kr',
    'dlemail.ru',
    'dm.j7.cloudns.cx',
    'dm.w3internet.co.uk',
    'dm.w3internet.co.ukexample.com',
    'dma.in-ulm.de',
    'dmail.kyty.net',
    'dmail.unrivaledtechnologies.com',
    'dmarc.ro',
    'dmslovakiat.com',
    'dmtc.edu.pl',
    'dndent.com',
    'dnsdeer.com',
    'dnses.ro',
    'doanart.com',
    'doatre.com',
    'dob.jp',
    'docmail.com',
    'docmail.cz',
    'docs.coms.hk',
    'doctordieu.xyz',
    'docu.me',
    'dodgeit.com',
    'dodgemail.de',
    'dodgit.com',
    'dodgit.org',
    'dodsi.com',
    'doiea.com',
    'dolnaa.asia',
    'dolphinnet.net',
    'domain1dolar.com',
    'domozmail.com',
    'donemail.ru',
    'dongqing365.com',
    'donot-reply.com',
    'dontreg.com',
    'dontsendmespam.de',
    'dooboop.com',
    'dotman.de',
    'dotmsg.com',
    'dotslashrage.com',
    'douchelounge.com',
    'doughmaine.xyz',
    'downloadeguide.mywire.org',
    'doxcity.net',
    'doy.kr',
    'dozvon-spb.ru',
    'dp76.com',
    'dqkerui.com',
    'dqnwara.com',
    'dr69.site',
    'dragons-spirit.org',
    'drama.tw',
    'drdrb.com',
    'drdrb.net',
    'dred.ru',
    'dremixd.com',
    'dress9x.com',
    'drevo.si',
    'drf.email',
    'drid1gs.com',
    'drivecompanies.com',
    'drivesotp7.com',
    'drivetagdev.com',
    'drmail.pw',
    'droolingfanboy.de',
    'drop.ekholm.org',
    'dropcake.de',
    'droplar.com',
    'droplister.com',
    'dropmail.me',
    'drynic.com',
    'dsiay.com',
    'dsleeping09.com',
    'dspwebservices.com',
    'dt.com',
    'dtools.info',
    'duam.net',
    'duck2.club',
    'dudmail.com',
    'duk33.com',
    'dukedish.com',
    'dumoac.net',
    'dump-email.info',
    'dumpandjunk.com',
    'dumpmail.de',
    'dumpyemail.com',
    'durandinterstellar.com',
    'duskmail.com',
    'dutiesu0.com',
    'dvdxpress.biz',
    'dw.now.im',
    'dweezlemail.crabdance.com',
    'dwse.edu.pl',
    'dx.abuser.eu',
    'dx.allowed.org',
    'dx.awiki.org',
    'dx.ez.lv',
    'dx.sly.io',
    'dyceroprojects.com',
    'dynu.net',
    'dz-geek.org',
    'dz17.net',
    'e-mail.com',
    'e-mail.igg.biz',
    'e-mail.net',
    'e-mail.org',
    'e-postkasten.com',
    'e-postkasten.de',
    'e-postkasten.eu',
    'e-postkasten.info',
    'e-tomarigi.com',
    'e.4pet.ro',
    'e.amav.ro',
    'e.arno.fi',
    'e.benlotus.com',
    'e.blogspam.ro',
    'e.l5.ca',
    'e.milavitsaromania.ro',
    'e.nodie.cc',
    'e.shapoo.ch',
    'e.wupics.com',
    'e3b.org',
    'e3z.de',
    'e4ivstampk.com',
    'e4ward.com',
    'e7n06wz.com',
    'e8g93s9zfo.com',
    'earth.doesntexist.org',
    'eastwan.net',
    'easy-trash-mail.com',
    'easynetwork.info',
    'easytrashmail.com',
    'eatlogs.com',
    'eatme69.top',
    'eatmea2z.club',
    'eatmea2z.top',
    'eatrnet.com',
    'eay.jp',
    'eb609s25w.com',
    'ebano.campano.cl',
    'ebeschlussbuch.de',
    'eboise.com',
    'ebs.com.ar',
    'ecallheandi.com',
    'echt-mail.de',
    'echtzeit.website',
    'eco.ilmale.it',
    'ecolo-online.fr',
    'edgex.ru',
    'edinburgh-airporthotels.com',
    'edrishn.xyz',
    'edu.auction',
    'edv.to',
    'ee1.pl',
    'ee2.pl',
    'eeemail.win',
    'eelmail.com',
    'efo.kr',
    'efxs.ca',
    'eggnova.com',
    'ehldeventer.nl',
    'eho.kr',
    'einfach.to',
    'einmalmail.de',
    'einrot.com',
    'einrot.de',
    'eintagsmail.de',
    'elearningjournal.org',
    'electriccarvehicle.com',
    'electro.mn',
    'elinore1818.site',
    'elitevipatlantamodels.com',
    'ely.kr',
    'email-fake.com',
    'email-jetable.fr',
    'email-sms.com',
    'email-sms.net',
    'email-temp.com',
    'email.cbes.net',
    'email.freecrypt.org',
    'email.net',
    'email.wassusf.online',
    'email60.com',
    'emailappp.com',
    'emaildienst.de',
    'emailfake.com',
    'emailfake.nut.cc',
    'emailfake.usa.cc',
    'emailfowarding.com',
    'emailgenerator.de',
    'emailgo.de',
    'emailhearing.com',
    'emailias.com',
    'emailigo.de',
    'emailinfive.com',
    'emailisvalid.com',
    'emaillime.com',
    'emailll.org',
    'emailmenow.info',
    'emailmiser.com',
    'emailna.co',
    'emailna.life',
    'emailnope.com',
    'emailo.pro',
    'emailondeck.com',
    'emailproxsy.com',
    'emailr.win',
    'emailresort.com',
    'emailsecurer.com',
    'emailsensei.com',
    'emailsingularity.net',
    'emailsy.info',
    'emailtea.com',
    'emailtech.info',
    'emailtemporanea.com',
    'emailtemporanea.net',
    'emailtemporar.ro',
    'emailtemporario.com.br',
    'emailthe.net',
    'emailtmp.com',
    'emailto.de',
    'emailure.net',
    'emailwarden.com',
    'emailx.at.hm',
    'emailxfer.com',
    'emeil.in',
    'emeil.ir',
    'emeraldwebmail.com',
    'emeyle.com',
    'emil.com',
    'eml.pp.ua',
    'emlhub.com',
    'emlpro.com',
    'emltmp.com',
    'empiremail.de',
    'empowering.zapto.org',
    'empresagloriasamotderoman.com',
    'emy.kr',
    'emz.net',
    'endrix.org',
    'enterto.com',
    'entregandobiblia.com.br',
    'enu.kr',
    'envy17.com',
    'eny.kr',
    'eonmech.com',
    'eorbs.com',
    'eos2mail.com',
    'epb.ro',
    'ephemail.net',
    'ephemeral.email',
    'equiapp.men',
    'equiemail.com',
    'erasf.com',
    'ero-tube.org',
    'esc.la',
    'escanor99.com',
    'escapehatchapp.com',
    'ese.kr',
    'esemay.com',
    'esgeneri.com',
    'esmuse.me',
    'esprity.com',
    'essaouira.xyz',
    'esseriod.com',
    'est.une.victime.ninja',
    'estate-invest.fr',
    'esy.es',
    'etgdev.de',
    'eth2btc.info',
    'ether123.net',
    'ethereal.email',
    'ethereum1.top',
    'ethersports.org',
    'ethersportz.info',
    'etlgr.com',
    'etoic.com',
    'etranquil.com',
    'etranquil.net',
    'etranquil.org',
    'etzdnetx.com',
    'eu6genetic.com',
    'euaqa.com',
    'evanfox.info',
    'evilbruce.com',
    'evilcomputer.com',
    'evliyaogluotel.com',
    'evopo.com',
    'evyush.com',
    'ewa.kr',
    'ewroteed.com',
    'eww.ro',
    'example.com',
    'excitedchat.com',
    'exi.kr',
    'existiert.net',
    'exitstageleft.net',
    'explodemail.com',
    'express.net.ua',
    'extra.oscarr.nl',
    'extraam.loan',
    'extremail.ru',
    'eyepaste.com',
    'ez.lv',
    'ezehe.com',
    'ezfill.club',
    'ezfill.com',
    'ezlo.co',
    'ezprice.co',
    'ezstest.com',
    'ezz.bid',
    'f.moza.pl',
    'f4k.es',
    'f5.si',
    'f5foster.com',
    'f7scene.com',
    'facialboook.site',
    'fadingemail.com',
    'faecesmail.me',
    'fag.wf',
    'failbone.com',
    'failinga.nl',
    'faithkills.com',
    'faithkills.org',
    'fake-box.com',
    'fake-email.pp.ua',
    'fakedemail.com',
    'fakeinbox.com',
    'fakeinbox.info',
    'fakeinformation.com',
    'fakemail.fr',
    'fakemail.intimsex.de',
    'fakemailgenerator.com',
    'fakemailz.com',
    'faketemp.email',
    'famail.win',
    'familytoday.us',
    'fammix.com',
    'fangoh.com',
    'fansworldwide.de',
    'fantasymail.de',
    'farmerlife.us',
    'farmtoday.us',
    'farrse.co.uk',
    'fartwallet.com',
    'fashionfwd.net',
    'fast-mail.fr',
    'fastacura.com',
    'fastchevy.com',
    'fastchrysler.com',
    'fastemails.us',
    'fastermail.com',
    'fasternet.biz',
    'fastkawasaki.com',
    'fastmailforyou.net',
    'fastmazda.com',
    'fastmitsubishi.com',
    'fastnissan.com',
    'fastsubaru.com',
    'fastsuzuki.com',
    'fasttoyota.com',
    'fastyamaha.com',
    'fatflap.com',
    'fax.dix.asia',
    'faze.biz',
    'fbi.coms.hk',
    'fbmail.usa.cc',
    'fc66998.com',
    'fdfdsfds.com',
    'feamail.com',
    'fellow-me.pw',
    'fellowme.pw',
    'fer-gabon.org',
    'fetchnet.co.uk',
    'fettometern.com',
    'fewminor.men',
    'fghmail.net',
    'ficken.de',
    'fictionsite.com',
    'fidelium10.com',
    'fido.be',
    'fightallspam.com',
    'figjs.com',
    'figmail.me',
    'figshot.com',
    'fiifke.de',
    'filbert4u.com',
    'filberts4u.com',
    'film-blog.biz',
    'filzmail.com',
    'findu.pl',
    'fingermouse.org',
    'finnahappen.com',
    'fir.hk',
    'firemail.cc',
    'fish.skytale.net',
    'fishfortomorrow.xyz',
    'fivemail.de',
    'fizmail.com',
    'fizmail.win',
    'flash-mail.pro',
    'flash-mail.xyz',
    'flashbox.5july.org',
    'flashmail.pro',
    'fleckens.hu',
    'flemail.com',
    'flemail.ru',
    'flirtey.pw',
    'flitafir.de',
    'floodbrother.com',
    'flowerss.website',
    'flowu.com',
    'fls4.gleeze.com',
    'flu-cc.flu.cc',
    'flu.cc',
    'flucc.flu.cc',
    'fluidsoft.us',
    'flurre.com',
    'flurred.com',
    'fly-ts.de',
    'flyinggeek.net',
    'flypicks.com',
    'flyspam.com',
    'flyxnet.pw',
    'fmail.ooo',
    'fmail.pw',
    'fnord.me',
    'fnzm.net',
    'foobarbot.net',
    'foodbooto.com',
    'footard.com',
    'foquita.com',
    'forecastertests.com',
    'foresthope.com',
    'forgetmail.com',
    'fornow.eu',
    'forotenis.com',
    'forprice.co',
    'forspam.net',
    'forward.cat',
    'fouristic.us',
    'foxja.com',
    'foxtrotter.info',
    'foy.kr',
    'fq1my2c.com',
    'fr.nf',
    'fr33mail.info',
    'francanet.com.br',
    'frapmail.com',
    'freealtgen.com',
    'freebabysittercam.com',
    'freeblackbootytube.com',
    'freebullets.net',
    'freecat.net',
    'freechristianbookstore.com',
    'freedom4you.info',
    'freedompop.us',
    'freefattymovies.com',
    'freehosting.men',
    'freeinbox.email',
    'freelance-france.eu',
    'freeletter.me',
    'freemail.ms',
    'freemail.tweakly.net',
    'freemommyvids.com',
    'freemymail.org',
    'freeplumpervideos.com',
    'freeprice.co',
    'freeroid.com',
    'freeschoolgirlvids.com',
    'freeshemaledvds.com',
    'freesistercam.com',
    'freesistervids.com',
    'freeteenbums.com',
    'freetubearchive.com',
    'freezzzm.site',
    'fressmind.us',
    'freunde.ru',
    'freundin.ru',
    'friendlymail.co.uk',
    'from.onmypc.info',
    'front14.org',
    'fsagc.xyz',
    'fsfsdf.org',
    'fsociety.org',
    'ftp.sh',
    'ftpinc.ca',
    'fuckedupload.com',
    'fuckingduh.com',
    'fuckme69.club',
    'fucknloveme.top',
    'fuckxxme.top',
    'fudgerub.com',
    'fuhoy.com',
    'fuirio.com',
    'fulvie.com',
    'fun2.biz',
    'fun2night.club',
    'fun64.com',
    'fun64.net',
    'funnycodesnippets.com',
    'funnymail.de',
    'fuqus.com',
    'furusato.tokyo',
    'furzauflunge.de',
    'futuregood.pw',
    'fuwa.be',
    'fuwamofu.com',
    'fux0ringduh.com',
    'fw.moza.pl',
    'fw2.me',
    'fw6m0bd.com',
    'fxnxs.com',
    'fxprix.com',
    'fyii.de',
    'g-mailix.com',
    'g-meil.com',
    'g.hmail.us',
    'g.ycn.ro',
    'g05zeg9i.com',
    'g14l71lb.com',
    'g1xmail.top',
    'g212dnk5.com',
    'g2xmail.top',
    'g3xmail.top',
    'g4hdrop.us',
    'gaf.oseanografi.id',
    'gafy.net',
    'gaggle.net',
    'galaxy.tv',
    'galaxyarmy.tech',
    'galaxys8giveaway.us',
    'galerielarochelle.com',
    'gally.jp',
    'gamail.top',
    'game.com',
    'gamegregious.com',
    'gameme.men',
    'games4free.flu.cc',
    'gamgling.com',
    'gamno.config.work',
    'garage46.com',
    'garasikita.pw',
    'garbagecollector.org',
    'garbagemail.org',
    'gardenscape.ca',
    'garizo.com',
    'garliclife.com',
    'garnettmailer.com',
    'garrymccooey.com',
    'gasssboss.club',
    'gav0.com',
    'gawab.com',
    'gbcmail.win',
    'gbmail.top',
    'gcmail.top',
    'gdkdevelopers.xyz',
    'gdmail.top',
    'geartower.com',
    'gedmail.win',
    'geekforex.com',
    'geew.ru',
    'gehensiemirnichtaufdensack.de',
    'geldwaschmaschine.de',
    'gelitik.in',
    'gen.uu.gl',
    'genderfuck.net',
    'generator.email',
    'geomail.win',
    'germanmails.biz',
    'gero.us',
    'geronra.com',
    'geschent.biz',
    'get.pp.ua',
    'get1mail.com',
    'get2mail.fr',
    'get365.pw',
    'getairmail.com',
    'getapet.net',
    'getbackinthe.kitchen',
    'geteit.com',
    'getfun.men',
    'getjulia.com',
    'getmails.eu',
    'getnada.com',
    'getocity.com',
    'getonemail.com',
    'getonemail.net',
    'gfcom.com',
    'ggmail.guru',
    'ghoochani.info',
    'ghosttexter.de',
    'ghtreihfgh.xyz',
    'giacmosuaviet.info',
    'giaiphapmuasam.com',
    'giantmail.de',
    'gibit.us',
    'gicua.com',
    'gifto12.com',
    'gigs.craigslist.org',
    'gilray.net',
    'gimesson.pe.hu',
    'ginzi.be',
    'ginzi.co.uk',
    'ginzi.es',
    'ginzi.eu',
    'ginzi.net',
    'ginzy.co.uk',
    'ginzy.eu',
    'girlmail.win',
    'girlsindetention.com',
    'girlsundertheinfluence.com',
    'gishpuppy.com',
    'giuras.club',
    'giuypaiw8.com',
    'giveh2o.info',
    'givmail.com',
    'givmy.com',
    'giyam.com',
    'glassaas.site',
    'gleeze.com',
    'glitch.sx',
    'globaltouron.com',
    'glubex.com',
    'glucosegrin.com',
    'gmail.ax',
    'gmail.gr.com',
    'gmaildottrick.com',
    'gmailssdf.com',
    'gmal.com',
    'gmatch.org',
    'gmeil.me',
    'gmial.com',
    'gmx.fr.nf',
    'gmx.net',
    'gmx1mail.top',
    'gmxmail.top',
    'gmxmail.win',
    'gnajuk.me',
    'gnctr-calgary.com',
    'gnetnagiwd.xyz',
    'go.irc.so',
    'go1.site',
    'go2usa.info',
    'go2vpn.net',
    'goat.si',
    'godataflow.xyz',
    'godut.com',
    'goemailgo.com',
    'gofuckporn.com',
    'gok.kr',
    'goldinbox.net',
    'golemico.com',
    'golfilla.info',
    'golidi.net',
    'gomail.in',
    'gomail.pgojual.com',
    'gooday.pw',
    'goodjab.club',
    'goodluckforu.cn.com',
    'goodseller.co',
    'goodsmart.pw',
    'google-mail.me',
    'google-mail.ooo',
    'googledottrick.com',
    'goooomail.com',
    'gorillaswithdirtyarmpits.com',
    'goround.info',
    'gosearchcity.us',
    'gothere.biz',
    'gotimes.xyz',
    'gotmail.com',
    'gotmail.net',
    'gotmail.org',
    'gotti.otherinbox.com',
    'govnomail.xyz',
    'gowikibooks.com',
    'gowikicampus.com',
    'gowikicars.com',
    'gowikifilms.com',
    'gowikigames.com',
    'gowikimusic.com',
    'gowikimusic.great-host.in',
    'gowikinetwork.com',
    'gowikitravel.com',
    'gowikitv.com',
    'gpcharlie.com',
    'gqlsryi.xyz',
    'grabitfast.co',
    'grandmamail.com',
    'grandmasmail.com',
    'gratislose.de',
    'gratisneuke.be',
    'gratosmail.fr.nf',
    'great-host.in',
    'greenhousemail.com',
    'greensloth.com',
    'greenst.info',
    'greggamel.com',
    'greggamel.net',
    'gregoria1818.site',
    'gregorsky.zone',
    'gregorygamel.com',
    'gregorygamel.net',
    'greyjack.com',
    'grish.de',
    'griuc.schule',
    'grn.cc',
    'growlcombine.com',
    'grr.la',
    'gs-arc.org',
    'gspam.mooo.com',
    'gsredcross.org',
    'gsrv.co.uk',
    'gudanglowongan.com',
    'guerillamail.biz',
    'guerillamail.com',
    'guerillamail.de',
    'guerillamail.info',
    'guerillamail.net',
    'guerillamail.org',
    'guerillamailblock.com',
    'guerrillamail.biz',
    'guerrillamail.com',
    'guerrillamail.de',
    'guerrillamail.info',
    'guerrillamail.net',
    'guerrillamail.org',
    'guerrillamailblock.com',
    'guqoo.com',
    'gustidharya.com',
    'gustore.co',
    'gustr.com',
    'gwspt71.com',
    'gxemail.men',
    'gynzi.co.uk',
    'gynzi.com',
    'gynzi.es',
    'gynzi.nl',
    'gynzy.at',
    'gynzy.es',
    'gynzy.eu',
    'gynzy.gr',
    'gynzy.info',
    'gynzy.lt',
    'gynzy.mobi',
    'gynzy.pl',
    'gynzy.ro',
    'gynzy.ru',
    'gynzy.sk',
    'gzb.ro',
    'h.mintemail.com',
    'h.thc.lv',
    'h1z8ckvz.com',
    'h2-yy.nut.cc',
    'h8s.org',
    'h9js8y6.com',
    'habitue.net',
    'habrew.de',
    'hacccc.com',
    'hacked.jp',
    'hackrz.xyz',
    'hackthatbit.ch',
    'haddo.eu',
    'hafnia.biz',
    'hahawrong.com',
    'haiapoteker.com',
    'haida-edu.cn',
    'halfvaped.net',
    'halofarmasi.com',
    'haltospam.com',
    'haniv.ignorelist.com',
    'hanmama.zz.am',
    'hantem.bid',
    'happygoluckyclub.com',
    'happykorea.club',
    'happykoreas.xyz',
    'happymail.guru',
    'happysinner.co.uk',
    'happyyou.pw',
    'haqed.com',
    'harakirimail.com',
    'hargaku.org',
    'haribu.com',
    'haribu.net',
    'harmonyst.xyz',
    'hartbot.de',
    'hash.pp.ua',
    'hat-geld.de',
    'hatespam.org',
    'hawrong.com',
    'haydoo.com',
    'hazelnut4u.com',
    'hazelnuts4u.com',
    'hazmatshipping.org',
    'hcac.net',
    'hccmail.win',
    'hcoupledp.com',
    'hdfshsh.stream',
    'hdmoviestore.us',
    'hdprice.co',
    'headset5pl.com',
    'headstrong.de',
    'healyourself.xyz',
    'heathenhammer.com',
    'heathenhero.com',
    'hecat.es',
    'heeco.me',
    'hellodream.mobi',
    'helloricky.com',
    'hellow-man.pw',
    'hellowman.pw',
    'hellowperson.pw',
    'helmade.xyz',
    'helpinghandtaxcenter.org',
    'helpwesearch.com',
    'herbert1818.site',
    'herp.in',
    'herpderp.nl',
    'hewke.xyz',
    'hezll.com',
    'hg8n415.com',
    'hi2.in',
    'hi5.si',
    'hi6547mue.com',
    'hiddencorner.xyz',
    'hiddentragedy.com',
    'hidebox.org',
    'hidemail.de',
    'hidemail.pro',
    'hidemail.us',
    'hideme.be',
    'hidemyass.com',
    'hidzz.com',
    'highbros.org',
    'hillary-email.com',
    'hiltonvr.com',
    'hiru-dea.com',
    'hissfuse.com',
    'hitbts.com',
    'hitprice.co',
    'hix.kr',
    'hiz.kr',
    'hjirnbt56g.xyz',
    'hjkcfa3o.com',
    'hk188188.com',
    'hku.us.to',
    'hmail.top',
    'hmail.us',
    'hmamail.com',
    'hmh.ro',
    'hntr93vhdv.uy.to',
    'ho3twwn.com',
    'hoanggiaanh.com',
    'hoanglong.tech',
    'hochsitze.com',
    'hoer.pw',
    'hola.org',
    'holdup.me',
    'homal.com',
    'honor-8.com',
    'hopemail.biz',
    'hopoverview.com',
    'hopto.org',
    'hornyalwary.top',
    'horsefucker.org',
    'hostcalls.com',
    'hostlaba.com',
    'hostmonitor.net',
    'hotelsatparis.com',
    'hotmai.com',
    'hotmailproduct.com',
    'hotmails.com',
    'hotmial.com',
    'hotpop.com',
    'hotprice.co',
    'hous.craigslist.org',
    'housat.com',
    'hpc.tw',
    'hs.vc',
    'hs130.com',
    'hsbc.coms.hk',
    'hstermail.com',
    'ht.cx',
    'hu4ht.com',
    'huajiachem.cn',
    'huangniu8.com',
    'hubii-network.com',
    'huiledargane.com',
    'hulapla.de',
    'humaility.com',
    'humn.ws.gy',
    'hungpackage.com',
    'hunrap.usa.cc',
    'hurify1.com',
    'hurramm.us',
    'hurrijian.us',
    'hush.ai',
    'hush.com',
    'huskion.net',
    'hvastudiesucces.nl',
    'hvtechnical.com',
    'hvzoi.com',
    'hwsye.net',
    'hypotekyonline.cz',
    'i-booking.us',
    'i-phone.nut.cc',
    'i-phones.shop',
    'i-taiwan.tv',
    'i.istii.ro',
    'i.klipp.su',
    'i.ryanb.com',
    'i.wawi.es',
    'i.xcode.ro',
    'i201zzf8x.com',
    'i2pmail.org',
    'i35t0a5.com',
    'i4j0j3iz0.com',
    'i6.cloudns.cc',
    'i6.cloudns.cx',
    'i66g2i2w.com',
    'i6appears.com',
    'iaoss.com',
    'ibm.coms.hk',
    'ibnuh.bz',
    'ibsats.com',
    'icantbelieveineedtoexplainthisshit.com',
    'iccmail.men',
    'icemovie.link',
    'icfu.mooo.com',
    'ichbinvollcool.de',
    'ichichich.faith',
    'ichigo.me',
    'iconsultant.me',
    'icraftx.net',
    'icx.in',
    'icx.ro',
    'id10tproof.com',
    'ideepmind.pw',
    'ideer.msk.ru',
    'ideer.pro',
    'idigo.org',
    'idn.vn',
    'ieatspam.eu',
    'ieatspam.info',
    'ieh-mail.de',
    'ige.es',
    'igelonline.de',
    'igg.biz',
    'igiveu.win',
    'ignoremail.com',
    'igqtrustee.com',
    'ihateyoualot.info',
    'ihaxyour.info',
    'ihazspam.ca',
    'iheartspam.org',
    'ikbenspamvrij.nl',
    'iki.kr',
    'ikke.win',
    'ikkjacket.com',
    'iku.us',
    'illegal.team',
    'illistnoise.com',
    'ilmale.it',
    'ilnostrogrossograssomatrimoniomolisano.com',
    'ilovemyniggers.club',
    'ilovespam.com',
    'imails.info',
    'imankul.com',
    'imgjar.com',
    'imgof.com',
    'imgv.de',
    'imhtcut.xyz',
    'immo-gerance.info',
    'imovie.link',
    'impastore.co',
    'imperfectron.com',
    'impostore.co',
    'improvedtt.com',
    'imstations.com',
    'imul.info',
    'inaby.com',
    'inapplicable.org',
    'inbound.plus',
    'inbox.si',
    'inbox2.info',
    'inboxalias.com',
    'inboxbear.com',
    'inboxclean.com',
    'inboxclean.org',
    'inboxdesign.me',
    'inboxed.im',
    'inboxed.pw',
    'inboxhub.net',
    'inboxkitten.com',
    'inboxproxy.com',
    'inboxstore.me',
    'incestry.co.uk',
    'inclusiveprogress.com',
    'incognitomail.com',
    'incognitomail.net',
    'incognitomail.org',
    'incq.com',
    'increase5f.com',
    'incrediemail.com',
    'incrementing.pw',
    'ind.st',
    'indeedlebeans.com',
    'indeedtime.us',
    'independentsucks.twilightparadox.com',
    'india2in.com',
    'indieclad.com',
    'indirect.ws',
    'indomaed.pw',
    'indonesianherbalmedicine.com',
    'indoserver.stream',
    'indosukses.press',
    'ineec.net',
    'infalled.com',
    'infest.org',
    'infideles.nu',
    'infocom.zp.ua',
    'inggo.org',
    'inmail.site',
    'inmail.xyz',
    'inoutmail.de',
    'inoutmail.eu',
    'inoutmail.info',
    'inoutmail.net',
    'inpowiki.xyz',
    'insanumingeniumhomebrew.com',
    'insorg-mail.info',
    'instafun.men',
    'instaku-media.com',
    'instance-email.com',
    'instant-mail.de',
    'instantblingmail.info',
    'instantemailaddress.com',
    'instantlyemail.com',
    'instantmail.fr',
    'instantmailaddress.com',
    'instaprice.co',
    'intel.coms.hk',
    'internetoftags.com',
    'interstats.org',
    'intersteller.com',
    'investore.co',
    'ioemail.win',
    'ioio.eu',
    'iozak.com',
    'ip4.pp.ua',
    'ip6.li',
    'ip6.pp.ua',
    'ipdeer.com',
    'ipemail.win',
    'ipiranga.dynu.com',
    'ipoo.org',
    'ipsur.org',
    'ipswell.com',
    'iqemail.win',
    'irabops.com',
    'irc.so',
    'ircbox.xyz',
    'irish2me.com',
    'irishspringrealty.com',
    'irlchase.pw',
    'iroid.com',
    'ironiebehindert.de',
    'irr.kr',
    'irssi.tv',
    'is.af',
    'isbjct4e.com',
    'isdaq.com',
    'ise4mqle13.o-r.kr',
    'islam.igg.biz',
    'isosq.com',
    'ispuntheweb.com',
    'ispyco.ru',
    'istakalisa.club',
    'istii.ro',
    'istlecker.de',
    'isukrainestillacountry.com',
    'it7.ovh',
    'italy-mail.com',
    'itis0k.com',
    'itmtx.com',
    'itoup.com',
    'its0k.com',
    'itsme.edu.pl',
    'itunesgiftcodegenerator.com',
    'iuemail.men',
    'iwantumake.us',
    'iwi.net',
    'ixx.io',
    'j-p.us',
    'j.rvb.ro',
    'j3rqt89ez.com',
    'j7.cloudns.cx',
    'j8k2.usa.cc',
    'jacckpot.site',
    'jackmailer.com',
    'jacquelx.com',
    'jadopado.com',
    'jafps.com',
    'jajxz.com',
    'jamesbond.flu.cc',
    'jamesbond.igg.biz',
    'jamesbond.nut.cc',
    'jamesbond.usa.cc',
    'jamieziggers.nl',
    'jamit.com.au',
    'jancok.in',
    'janproz.com',
    'japanyn7ys.com',
    'javmail.tech',
    'jbnote.com',
    'jcdmail.men',
    'jdmadventures.com',
    'jdz.ro',
    'je-recycle.info',
    'jeie.igg.biz',
    'jellyrolls.com',
    'jembulan.bounceme.net',
    'jeramywebb.com',
    'jet-renovation.fr',
    'jetable.com',
    'jetable.fr.nf',
    'jetable.net',
    'jetable.org',
    'jetable.pp.ua',
    'jetableemail.com',
    'jetableemails.com',
    'jiaxin8736.com',
    'jieber.net',
    'jil.kr',
    'jjmsb.eu.org',
    'jklasdf.com',
    'jmail.fr.nf',
    'jmail.ovh',
    'jmail.ro',
    'jnpayy.com',
    'jnxjn.com',
    'joaquinito01.servehttp.com',
    'job.craigslist.org',
    'jobbikszimpatizans.hu',
    'jobposts.net',
    'jobs-to-be-done.net',
    'joelpet.com',
    'joetestalot.com',
    'jokenaka.press',
    'jopho.com',
    'josefadventures.org',
    'joseihorumon.info',
    'josse.ltd',
    'jourrapide.com',
    'jp.ftp.sh',
    'jpco.org',
    'jqweblogs.com',
    'jredm.com',
    'jsonp.ro',
    'jsrsolutions.com',
    'jswfdb48z.com',
    'jto.kr',
    'jugglepile.com',
    'jungkamushukum.com',
    'junk.beats.org',
    'junk.ihmehl.com',
    'junk.to',
    'junk1e.com',
    'junkmail.com',
    'jupimail.com',
    'just4spam.com',
    'justbegood.pw',
    'justnowmail.com',
    'justonemail.net',
    'juyouxi.com',
    'jv6hgh1.com',
    'jwk4227ufn.com',
    'jwork.ru',
    'jyliananderik.com',
    'k-mail.top',
    'k.fido.be',
    'k3663a40w.com',
    'k3opticsf.com',
    'k4ds.org',
    'kadag.ir',
    'kademen.com',
    'kadokawa.top',
    'kah.pw',
    'kaijenwan.com',
    'kakadua.net',
    'kalapi.org',
    'kalemproje.com',
    'kampoeng3d.club',
    'kamsg.com',
    'kanciang.faith',
    'kandymail.com',
    'kanker.website',
    'kaovo.com',
    'kappala.info',
    'kariplan.com',
    'karitas.com.br',
    'kartvelo.com',
    'kartvelo.me',
    'kasmail.com',
    'kaspop.com',
    'katztube.com',
    'kazper.net',
    'kchkch.com',
    'kcrw.de',
    'kdublinstj.com',
    'keeplucky.pw',
    'keepmymail.com',
    'kein.hk',
    'keinhirn.de',
    'keinpardon.de',
    'keipino.de',
    'kekecog.com',
    'kekita.com',
    'keluruk.fun',
    'kemptvillebaseball.com',
    'kemska.pw',
    'kennedy808.com',
    'ketiksms.club',
    'kevintrankt.com',
    'khalifahallah.com',
    'khoabung.com',
    'khongsocho.xyz',
    'kiani.com',
    'kickmark.com',
    'kickmarx.net',
    'kiham.club',
    'killmail.com',
    'killmail.net',
    'kimsdisk.com',
    'kiois.com',
    'kir.ch.tc',
    'kiryubox.cu.cc',
    'kismail.ru',
    'kisshq.com',
    'kisstwink.com',
    'kitnastar.com',
    'kitten-mittons.com',
    'kksm.be',
    'klammlose.org',
    'klassmaster.com',
    'klassmaster.net',
    'klick-tipp.us',
    'klipp.su',
    'klipschx12.com',
    'kloap.com',
    'kludgemush.com',
    'klzlk.com',
    'kmail.mooo.com',
    'kmhow.com',
    'knol-power.nl',
    'knptest.com',
    'koiqe.com',
    'kommunity.biz',
    'kon42.com',
    'kontol.city',
    'kontol.co.uk',
    'kopagas.com',
    'kopaka.net',
    'kopqi.com',
    'kormail.xyz',
    'kosmetik-obatkuat.com',
    'kostenlosemailadresse.de',
    'koszmail.pl',
    'kotsu01.info',
    'kozow.com',
    'kpooa.com',
    'krd.ag',
    'ks87.igg.biz',
    'ks87.usa.cc',
    'ksmtrck.rf.gd',
    'kuai909.com',
    'kuaijenwan.com',
    'kuemail.men',
    'kuhrap.com',
    'kuikytut.review',
    'kuiqa.com',
    'kulturbetrieb.info',
    'kumail8.info',
    'kurzepost.de',
    'kusrc.com',
    'kwift.net',
    'kwilco.net',
    'kyal.pl',
    'kyois.com',
    'l-c-a.us',
    'l.safdv.com',
    'l0.l0l0.xyz',
    'l0l.l1l.ink',
    'l0real.net',
    'l2n5h8c7rh.com',
    'l33r.eu',
    'l5.ca',
    'l5prefixm.com',
    'l7b2l47k.com',
    'l8oaypr.com',
    'labetteraverouge.at',
    'labo.ch',
    'laboriously.com',
    'lacedmail.com',
    'lackmail.net',
    'lackmail.ru',
    'lacto.info',
    'lags.us',
    'lagushare.me',
    'lahamnakam.me',
    'lain.ch',
    'lajoska.pe.hu',
    'lak.pp.ua',
    'lakelivingstonrealestate.com',
    'lakqs.com',
    'lal.kr',
    'lam0k.com',
    'lambdasu.com',
    'lamdx.com',
    'lancego.space',
    'landmail.co',
    'laoeq.com',
    'laoho.com',
    'laporinaja.com',
    'laramail.io',
    'larisia.com',
    'larjem.com',
    'last-chance.pro',
    'lastmail.co',
    'lastmail.com',
    'latemail.tech',
    'laurenbt.com',
    'lavabit.com',
    'lawlita.com',
    'lawlz.net',
    'lazyinbox.com',
    'lazyinbox.us',
    'lbe.kr',
    'lce0ak.com',
    'lceart.com',
    'lceland.net',
    'lceland.org',
    'lcelander.com',
    'lcelandic.com',
    'ldaho.net',
    'ldaho0ak.com',
    'ldaholce.com',
    'ldop.com',
    'ldtp.com',
    'le.monchu.fr',
    'leapradius.com',
    'lecsaljuk.club',
    'ledoktre.com',
    'lee.mx',
    'leeching.net',
    'leemail.me',
    'legalrc.loan',
    'lei.kr',
    'lenovog4.com',
    'lequitywk.com',
    'lesbugs.com',
    'letmeinonthis.com',
    'letmymail.com',
    'letsmail9.com',
    'letthemeatspam.com',
    'level3.flu.cc',
    'level3.igg.biz',
    'level3.nut.cc',
    'level3.usa.cc',
    'lexisense.com',
    'lez.se',
    'lgloo.net',
    'lgloos.com',
    'lgxscreen.com',
    'lhsdv.com',
    'liamcyrus.com',
    'liamekaens.com',
    'libox.fr',
    'lifebyfood.com',
    'lifetimefriends.info',
    'lifetotech.com',
    'ligsb.com',
    'lijeuki.co',
    'likesyouback.com',
    'lillemap.net',
    'lilo.me',
    'lilylee.com',
    'lindenbaumjapan.com',
    'link.cloudns.asia',
    'link2mail.net',
    'linkedintuts2016.pw',
    'linux.7m.ro',
    'linuxmail.so',
    'linuxpl.eu',
    'liquidmail.de',
    'litedrop.com',
    'liveemail.xyz',
    'liveskiff.us',
    'livingsalty.us',
    'lixo.loxot.eu',
    'lkgn.se',
    'lkim1wlvpl.com',
    'lko.co.kr',
    'lko.kr',
    'llogin.ru',
    'lm0k.com',
    'lmcudh4h.com',
    'ln0rder.com',
    'ln0ut.com',
    'ln0ut.net',
    'lndex.net',
    'lndex.org',
    'lnvoke.net',
    'loadby.us',
    'loan101.pro',
    'loanins.org',
    'loaoa.com',
    'loapq.com',
    'loblaw.twilightparadox.com',
    'localserv.no-ip.org',
    'locanto1.club',
    'locantofuck.top',
    'locantospot.top',
    'locantowsite.club',
    'located6j.com',
    'locateme10.com',
    'locomodev.net',
    'logular.com',
    'loh.pp.ua',
    'loin.in',
    'loketa.com',
    'lokum.nu',
    'lol.ovpn.to',
    'lolfreak.net',
    'lolllipop.stream',
    'lolmail.biz',
    'lom.kr',
    'london2.space',
    'longio.org',
    'lookugly.com',
    'lopeure.com',
    'lopl.co.cc',
    'lordsofts.com',
    'lortemail.dk',
    'losemymail.com',
    'lostpositive.xyz',
    'lovebitco.in',
    'lovemeet.faith',
    'lovemeleaveme.com',
    'loves.dicksinhisan.us',
    'loves.dicksinmyan.us',
    'loy.kr',
    'lpfmgmtltd.com',
    'lpo.ddnsfree.com',
    'lr7.us',
    'lr78.com',
    'lrland.net',
    'lroid.com',
    'lron0re.com',
    'lru.me',
    'luckboy.pw',
    'luckjob.pw',
    'luckymail.org',
    'lucyu.com',
    'lukecarriere.com',
    'lukemail.info',
    'lukop.dk',
    'luo.kr',
    'lupabapak.org',
    'luv2.us',
    'lyfestylecreditsolutions.com',
    'lzoaq.com',
    'm.ddcrew.com',
    'm.nosuchdoma.in',
    'm.svlp.net',
    'm21.cc',
    'm2r60ff.com',
    'm4ilweb.info',
    'm5s.flu.cc',
    'm5s.igg.biz',
    'm5s.nut.cc',
    'm8r.davidfuhr.de',
    'm8r.mcasal.com',
    'ma-boite-aux-lettres.infos.st',
    'ma2limited.com',
    'maaill.com',
    'maboard.com',
    'macr2.com',
    'macromaid.com',
    'macromice.info',
    'magamail.com',
    'magicbeep.com',
    'magicbox.ro',
    'magspam.net',
    'mahdevip.com',
    'mahiidev.site',
    'maidlow.info',
    'mail-easy.fr',
    'mail-fake.com',
    'mail-filter.com',
    'mail-owl.com',
    'mail-temp.com',
    'mail-temporaire.com',
    'mail-temporaire.fr',
    'mail-tester.com',
    'mail.anhthu.org',
    'mail.aws910.com',
    'mail.bccto.com',
    'mail.bccto.me',
    'mail.bentrask.com',
    'mail.bestoption25.club',
    'mail.by',
    'mail.crowdpress.it',
    'mail.fast10s.design',
    'mail.fettometern.com',
    'mail.hanungofficial.club',
    'mail.illistnoise.com',
    'mail.jpgames.net',
    'mail.libivan.com',
    'mail.mailinator.com',
    'mail.me',
    'mail.mezimages.net',
    'mail.mixhd.xyz',
    'mail.mnisjk.com',
    'mail.neynt.ca',
    'mail.partskyline.com',
    'mail.piaa.me',
    'mail.ru',
    'mail.stars19.xyz',
    'mail.unionpay.pl',
    'mail.wtf',
    'mail.zp.ua',
    'mail1.drama.tw',
    'mail1.hacked.jp',
    'mail1.i-taiwan.tv',
    'mail1.ismoke.hk',
    'mail1.kaohsiung.tv',
    'mail1.kein.hk',
    'mail114.net',
    'mail1a.de',
    'mail2.drama.tw',
    'mail2.info.tm',
    'mail2.ntuz.me',
    'mail2.space',
    'mail2000.ru',
    'mail21.cc',
    'mail22.club',
    'mail22.space',
    'mail2rss.org',
    'mail2tor.com',
    'mail2world.com',
    'mail3.drama.tw',
    'mail333.com',
    'mail4-us.org',
    'mail4.drama.tw',
    'mail4gmail.com',
    'mail4trash.com',
    'mail4you.usa.cc',
    'mail5.drama.tw',
    'mail56.me',
    'mail666.ru',
    'mail707.com',
    'mail72.com',
    'mailabconline.com',
    'mailadadad.org',
    'mailapi.ru',
    'mailback.com',
    'mailbidon.com',
    'mailbiz.biz',
    'mailblocks.com',
    'mailblog.biz',
    'mailbox2go.de',
    'mailbox72.biz',
    'mailbox80.biz',
    'mailbox82.biz',
    'mailbox87.de',
    'mailbox92.biz',
    'mailbucket.org',
    'mailcat.biz',
    'mailcatch.com',
    'mailchop.com',
    'mailcker.com',
    'mailde.de',
    'mailde.info',
    'maildrop.cc',
    'maildu.de',
    'maildx.com',
    'maileater.com',
    'mailed.in',
    'mailed.ro',
    'maileimer.de',
    'maileme101.com',
    'mailexpire.com',
    'mailf5.com',
    'mailfall.com',
    'mailfish.de',
    'mailforspam.com',
    'mailfreeonline.com',
    'mailfs.com',
    'mailgov.info',
    'mailguard.me',
    'mailgutter.com',
    'mailhazard.com',
    'mailhazard.us',
    'mailhero.io',
    'mailhz.me',
    'mailimails.patzleiner.net',
    'mailimate.com',
    'mailin8r.com',
    'mailinatar.com',
    'mailinater.com',
    'mailinator.co.uk',
    'mailinator.com',
    'mailinator.info',
    'mailinator.net',
    'mailinator.org',
    'mailinator.pl',
    'mailinator.us',
    'mailinator.usa.cc',
    'mailinator0.com',
    'mailinator1.com',
    'mailinator2.com',
    'mailinator2.net',
    'mailinator3.com',
    'mailinator4.com',
    'mailinator5.com',
    'mailinator6.com',
    'mailinator7.com',
    'mailinator8.com',
    'mailinator9.com',
    'mailinatorzz.mooo.com',
    'mailinbox.co',
    'mailincubator.com',
    'mailismagic.com',
    'mailkor.xyz',
    'mailly.xyz',
    'mailmate.com',
    'mailme.ir',
    'mailme.judis.me',
    'mailme.lv',
    'mailme24.com',
    'mailmetrash.com',
    'mailmetrash.comilzilla.org',
    'mailmoat.com',
    'mailmoth.com',
    'mailms.com',
    'mailna.biz',
    'mailna.co',
    'mailna.in',
    'mailna.me',
    'mailnator.com',
    'mailnesia.com',
    'mailnull.com',
    'mailonaut.com',
    'mailorc.com',
    'mailorg.org',
    'mailox.biz',
    'mailpick.biz',
    'mailpooch.com',
    'mailproxsy.com',
    'mailquack.com',
    'mailrazer.com',
    'mailrc.biz',
    'mailrock.biz',
    'mailsac.com',
    'mailscdn.com',
    'mailscheap.us',
    'mailscrap.com',
    'mailseal.de',
    'mailshell.com',
    'mailsiphon.com',
    'mailslapping.com',
    'mailslite.com',
    'mailspam.me',
    'mailspam.xyz',
    'mailspeed.ru',
    'mailsucker.net',
    'mailtechx.com',
    'mailtemp.info',
    'mailtemp.net',
    'mailtemporaire.com',
    'mailtemporaire.fr',
    'mailtome.de',
    'mailtothis.com',
    'mailtraps.com',
    'mailtrash.net',
    'mailtrix.net',
    'mailtv.net',
    'mailtv.tv',
    'mailwithyou.com',
    'mailwriting.com',
    'mailz.info',
    'mailz.info.tm',
    'mailzen.win',
    'mailzi.ru',
    'mailzilla.com',
    'mailzilla.org',
    'mailzilla.orgmbx.cc',
    'mainerfolg.info',
    'majorleaguemail.com',
    'makemenaughty.club',
    'makemetheking.com',
    'makepleasure.club',
    'malahov.de',
    'malayalamdtp.com',
    'malibucoding.com',
    'mall.tko.co.kr',
    'mallinator.com',
    'malove.site',
    'mamber.net',
    'manifestgenerator.com',
    'mankyrecords.com',
    'mansiondev.com',
    'manybrain.com',
    'manyme.com',
    'mao.igg.biz',
    'margarette1818.site',
    'markmurfin.com',
    'martin.securehost.com.es',
    'masasih.loan',
    'maskedmails.com',
    'maskmail.net',
    'maskmemail.com',
    'masonline.info',
    'mastahype.net',
    'maswae.world',
    'matchpol.net',
    'matra.site',
    'mattersjf8.com',
    'mattmason.xyz',
    'max88.club',
    'maximalbonus.de',
    'maxprice.co',
    'mbdnsmail.mooo.com',
    'mbe.kr',
    'mbx.cc',
    'mcache.net',
    'mciek.com',
    'md5hashing.net',
    'mdu.edu.rs',
    'mealcash.com',
    'mebelnu.info',
    'mechanicalresumes.com',
    'mediciine.site',
    'medsheet.com',
    'meepsheep.eu',
    'meethornygirls.top',
    'meetlocalhorny.top',
    'mega.zik.dj',
    'meinspamschutz.de',
    'mejjang.xyz',
    'meltedbrownies.com',
    'meltmail.com',
    'memeil.top',
    'memeware.net',
    'memsg.site',
    'mephistore.co',
    'meprice.co',
    'merry.pink',
    'messagebeamer.de',
    'messageden.net',
    'messagesafe.co',
    'messwiththebestdielikethe.rest',
    'metalrika.club',
    'metaprice.co',
    'metroset.net',
    'mettamarketingsolutions.com',
    'mezimages.net',
    'mfsa.info',
    'mfsa.ru',
    'mhwolf.net',
    'miaferrari.com',
    'miam.kd2.org',
    'miauj.com',
    'micsocks.net',
    'midcoastcustoms.com',
    'midcoastcustoms.net',
    'midcoastsolutions.com',
    'midcoastsolutions.net',
    'midlertidig.com',
    'midlertidig.net',
    'midlertidig.org',
    'mierdamail.com',
    'migmail.net',
    'migmail.pl',
    'migumail.com',
    'mihanmail.ir',
    'mihep.com',
    'mijnhva.nl',
    'milavitsaromania.ro',
    'mildin.org.ua',
    'mindsetup.us',
    'minecraftrabbithole.com',
    'minex-coin.com',
    'ministry-of-silly-walks.de',
    'minsmail.com',
    'mintemail.com',
    'miodonski.ch',
    'miraigames.net',
    'mirmirchi.site',
    'mirrorrr.asia',
    'mirrror.asia',
    'misterpinball.de',
    'mituvn.com',
    'mji.ro',
    'mjukglass.nu',
    'mko.kr',
    'mkpfilm.com',
    'ml8.ca',
    'mlo.kr',
    'mlx.ooo',
    'mm.my',
    'mm5.se',
    'mmail.igg.biz',
    'mmailinater.com',
    'mmmmail.com',
    'mmoonz.faith',
    'mn.curppa.com',
    'mn.j0s.eu',
    'mn.riaki.com',
    'mnode.me',
    'moakt.co',
    'moakt.com',
    'moakt.ws',
    'moathrababah.com',
    'mobi.web.id',
    'mobileninja.co.uk',
    'mobilevpn.top',
    'moburl.com',
    'mockmyid.co',
    'mockmyid.com',
    'moeri.org',
    'mohmal.com',
    'mohmal.im',
    'mohmal.in',
    'mohmal.tech',
    'mohsenfb.com',
    'molms.com',
    'momentics.ru',
    'moncourrier.fr.nf',
    'monemail.fr.nf',
    'moneyboxtvc.com',
    'moneypipe.net',
    'monmail.fr.nf',
    'monumentmail.com',
    'moonm.review',
    'moonwake.com',
    'moot.es',
    'moreawesomethanyou.com',
    'morecoolstuff.net',
    'morefunmart.com',
    'moreorcs.com',
    'morsin.com',
    'motique.de',
    'mountainregionallibrary.net',
    'mouthube0t.com',
    'mowgli.jungleheart.com',
    'mox.pp.ua',
    'moza.pl',
    'mozej.com',
    'mp-j.igg.biz',
    'mp.igg.biz',
    'mp3geulis.net',
    'mr24.co',
    'mrchinh.com',
    'ms9.mailslite.com',
    'msa.minsmail.com',
    'msgden.com',
    'msgos.com',
    'msgsafe.ninja',
    'msk.ru',
    'mskey.co',
    'mspeciosa.com',
    'mswork.ru',
    'msxd.com',
    'mt2009.com',
    'mt2014.com',
    'mt2015.com',
    'mt2016.com',
    'mt2017.com',
    'mtmdev.com',
    'muathegame.com',
    'muchomail.com',
    'mucincanon.com',
    'muell.email',
    'muellemail.com',
    'muellmail.com',
    'muellpost.de',
    'mufux.com',
    'mugglenet.org',
    'muimail.com',
    'mundodigital.me',
    'mundopregunta.com',
    'mus.email',
    'musclemailbox.com',
    'musicmakes.us',
    'mustbe.ignorelist.com',
    'mustbedestroyed.org',
    'musttufa.site',
    'mutant.me',
    'muttvomit.com',
    'muttwalker.net',
    'mvrht.com',
    'mvrht.net',
    'mwarner.org',
    'mx0.wwwnew.eu',
    'mxbin.net',
    'mxfuel.com',
    'my.efxs.ca',
    'my.longaid.net',
    'my.vondata.com.ar',
    'my10minutemail.com',
    'myalias.pw',
    'mybitti.de',
    'mycard.net.ua',
    'mycleaninbox.net',
    'mycloudmail.tech',
    'mycorneroftheinter.net',
    'mydemo.equipment',
    'myecho.es',
    'myemailboxy.com',
    'myemaill.com',
    'myfreemail.tech',
    'myindohome.services',
    'mykickassideas.com',
    'mylapak.info',
    'mymail-in.net',
    'mymail90.com',
    'mymailoasis.com',
    'myn4s.ddns.net',
    'myneocards.cz',
    'mynetstore.de',
    'myopang.com',
    'mypacks.net',
    'mypartyclip.de',
    'myphantomemail.com',
    'myproximity.us',
    'mysamp.de',
    'myself.com',
    'myspaceinc.com',
    'myspaceinc.net',
    'myspaceinc.org',
    'myspacepimpedup.com',
    'myspamless.com',
    'mystvpn.com',
    'mytemp.email',
    'mytempemail.com',
    'mytempmail.com',
    'mythnick.club',
    'mytrashmail.com',
    'mytrashmail.net',
    'mytrashmailer.com',
    'mytrashmailr.com',
    'mywarnernet.net',
    'mywrld.site',
    'myzat.com',
    'myzx.com',
    'mziqo.com',
    'n.ra3.us',
    'n.spamtrap.co',
    'n.zavio.nl',
    'n1nja.org',
    'n8.gs',
    'naaughty.club',
    'nabuma.com',
    'nacho.pw',
    'nada.email',
    'nada.ltd',
    'nakam.xyz',
    'nakammoleb.xyz',
    'nakedtruth.biz',
    'nameaaa.myddns.rocks',
    'namefake.com',
    'namilu.com',
    'nanonym.ch',
    'national.shitposting.agency',
    'nationalgardeningclub.com',
    'naturalious.com',
    'nawmin.info',
    'nbhsssib.fun',
    'nbox.notif.me',
    'nbzmr.com',
    'nctuiem.xyz',
    'negated.com',
    'negrofilio.com',
    'neibu306.com',
    'neibu963.com',
    'neic.com',
    'neko2.net',
    'neomailbox.com',
    'nepnut.com',
    'nepwk.com',
    'nervmich.net',
    'nervtmich.net',
    'net.ua',
    'nethotmail.com',
    'netmails.com',
    'netmails.net',
    'netricity.nl',
    'netris.net',
    'netviewer-france.com',
    'networkofemail.com',
    'netzidiot.de',
    'neverbox.com',
    'neverbox.net',
    'nevermail.de',
    'new-purse.com',
    'newdawnnm.xyz',
    'newideasfornewpeople.info',
    'newscoin.club',
    'newsmag.us',
    'newsusfun.com',
    'next.ovh',
    'nextstopvalhalla.com',
    'nezdiro.org',
    'nezzart.com',
    'nfast.net',
    'nguyenusedcars.com',
    'nh3.ro',
    'nice-4u.com',
    'nicegarden.us',
    'nicemail.pro',
    'nicewoodenbaskets.com',
    'nicknassar.com',
    'nickrizos.com',
    'nie-podam.pl',
    'niepodam.pl',
    'nigge.rs',
    'nike.coms.hk',
    'nincsmail.com',
    'nincsmail.hu',
    'niwl.net',
    'njc65c15z.com',
    'nkhfmnt.xyz',
    'nko.kr',
    'nl.szucsati.net',
    'nm7.cc',
    'nmarticles.com',
    'nnh.com',
    'nnot.net',
    'nnoway.ru',
    'no-spam.ws',
    'no-spammers.com',
    'no-ux.com',
    'noblepioneer.com',
    'nobugmail.com',
    'nobulk.com',
    'nobuma.com',
    'noclickemail.com',
    'nodezine.com',
    'nodie.cc',
    'nodnor.club',
    'nogmailspam.info',
    'noicd.com',
    'nokiamail.com',
    'nom.za',
    'nomail.ch',
    'nomail.nodns.xyz',
    'nomail.pw',
    'nomail.xl.cx',
    'nomail2me.com',
    'nomailthankyou.com',
    'nomorespamemails.com',
    'nonexisted.nondomain',
    'nonspam.eu',
    'nonspammer.de',
    'nonze.ro',
    'noref.in',
    'norih.com',
    'norseforce.com',
    'northemquest.com',
    'norules.zone',
    'nospam.barbees.net',
    'nospam.thurstons.us',
    'nospam.today',
    'nospam.wins.com.br',
    'nospam.ze.tc',
    'nospam2me.com',
    'nospam4.us',
    'nospamfor.us',
    'nospammail.net',
    'nospamme.com',
    'nospammer.ovh',
    'nospamthanks.info',
    'nostrajewellery.xyz',
    'not0k.com',
    'nothingtoseehere.ca',
    'notif.me',
    'notmailinator.com',
    'notrnailinator.com',
    'notsharingmy.info',
    'novagun.com',
    'now.im',
    'now.mefound.com',
    'noway.pw',
    'nowhere.org',
    'nowmymail.com',
    'npv.kr',
    'nqav95zj0p.kro.kr',
    'nsaking.de',
    'ntlhelp.net',
    'ntt.gotdns.ch',
    'nubescontrol.com',
    'nuke.africa',
    'nullbox.info',
    'nuo.co.kr',
    'nuo.kr',
    'nuprice.co',
    'nurdea.com',
    'nurdea.net',
    'nurfuerspam.de',
    'nus.edu.sg',
    'nut-cc.nut.cc',
    'nut.cc',
    'nutcc.nut.cc',
    'nutpa.net',
    'nuts2trade.com',
    'nwldx.com',
    'nwldx.net',
    'nwytg.com',
    'nwytg.net',
    'nxbrasil.net',
    'ny7.me',
    'nypato.com',
    'nyrmusic.com',
    'o.cfo2go.ro',
    'o.idigo.org',
    'o.muti.ro',
    'o.oai.asia',
    'o.opendns.ro',
    'o.spamtrap.ro',
    'o060bgr3qg.com',
    'o22.info',
    'o2stk.org',
    'o3enzyme.com',
    'o7i.net',
    'oai.asia',
    'oalsp.com',
    'oaudienceij.com',
    'obfusko.com',
    'objectmail.com',
    'obo.kr',
    'obobbo.com',
    'obxpestcontrol.com',
    'oceancares.xyz',
    'odaymail.com',
    'odem.com',
    'odnorazovoe.ru',
    'oe1f42q.com',
    'oepia.com',
    'oerpub.org',
    'offsetmail.com',
    'offshore-proxies.net',
    'ohaaa.de',
    'ohdomain.xyz',
    'ohi.tw',
    'ohioticketpayments.xyz',
    'oiizz.com',
    'oiqas.com',
    'ok-body.pw',
    'okbody.pw',
    'okclprojects.com',
    'okrent.us',
    'okzk.com',
    'olypmall.ru',
    'omail.pro',
    'omdo.xyz',
    'omeaaa124.ddns.net',
    'omi4.net',
    'omnievents.org',
    'omzae.com',
    'on-off.cloudns.cx',
    'one-time.email',
    'one.pl',
    'one2mail.info',
    'onebiginbox.com',
    'onelegalplan.com',
    'onemoremail.net',
    'oneoffemail.com',
    'oneoffmail.com',
    'onewaymail.com',
    'onlatedotcom.info',
    'online.ms',
    'onlineidea.info',
    'onmail.win',
    'onprice.co',
    'onqin.com',
    'ontyne.biz',
    'oolus.com',
    'oopi.org',
    'oou.us',
    'opayq.com',
    'open.brainonfire.net',
    'opendns.ro',
    'openmindedzone.club',
    'opentrash.com',
    'opojare.org',
    'opp24.com',
    'oranek.com',
    'orange-bonplan.com',
    'ordinaryamerican.net',
    'ordinaryyz1.com',
    'oreidresume.com',
    'org.ua',
    'orgmbx.cc',
    'oroki.de',
    'osendingwr.com',
    'oshietechan.link',
    'otherdog.net',
    'otherinbox.codupmyspace.com',
    'otherinbox.com',
    'otnasus.xyz',
    'ourawesome.life',
    'ourawesome.online',
    'ourklips.com',
    'ourpreviewdomain.com',
    'outlawspam.com',
    'outlook.com.hotpusssy69.host',
    'outlookkk.online',
    'outlookpro.net',
    'outmail.win',
    'ov3u841.com',
    'ovi.usa.cc',
    'ovpn.to',
    'ovvee.com',
    'owa.kr',
    'owlpic.com',
    'owlymail.com',
    'ownsyou.de',
    'oxfarm1.com',
    'oxopoha.com',
    'oyu.kr',
    'ozozwd2p.com',
    'ozumz.com',
    'ozyl.de',
    'p.9q.ro',
    'p.k4ds.org',
    'p.mrrobotemail.com',
    'p33.org',
    'p71ce1m.com',
    'pa9e.com',
    'pachilly.com',
    'paddlepanel.com',
    'pamposhtrophy.com',
    'pancakemail.com',
    'pandostore.co',
    'papierkorb.me',
    'paplease.com',
    'parisannonce.com',
    'parisdentists.com',
    'parisvipescorts.com',
    'parkcrestlakewood.xyz',
    'partskyline.com',
    'party4you.me',
    'passionwear.us',
    'pastebitch.com',
    'patonce.com',
    'paulfucksallthebitches.com',
    'paulkippes.com',
    'pavilionx2.com',
    'pay-mon.com',
    'payperex2.com',
    'pc1520.com',
    'pcmylife.com',
    'pcusers.otherinbox.com',
    'pdold.com',
    'pe.hu',
    'peapz.com',
    'pecdo.com',
    'pecinan.com',
    'pecinan.net',
    'pecinan.org',
    'pedimed-szczecin.pl',
    'pencalc.xyz',
    'penguincreationdate.pw',
    'penis.computer',
    'penisgoes.in',
    'penspam.com',
    'peopledrivecompanies.com',
    'pepbot.com',
    'peppe.usa.cc',
    'pepsi.coms.hk',
    'perasut.us',
    'perfect-u.pw',
    'perfectu.pw',
    'pers.craigslist.org',
    'peterdethier.com',
    'petertijj.com',
    'petrolgames.com',
    'petrzilka.net',
    'pfui.ru',
    'phaantm.de',
    'pharmasiana.com',
    'phonearea.us',
    'photo-impact.eu',
    'photomark.net',
    'phpbb.uu.gl',
    'phpieso.com',
    'phuongblue1507.xyz',
    'phus8kajuspa.cu.cc',
    'pi.vu',
    'piaa.me',
    'picfame.com',
    'pid.mx',
    'pidmail.com',
    'piewish.com',
    'pig.pp.ua',
    'pii.at',
    'pika.pc486.net',
    'piki.si',
    'pimpedupmyspace.com',
    'pinehill-seattle.org',
    'pingir.com',
    'pisls.com',
    'pjjkp.com',
    'plexolan.de',
    'plez.org',
    'plhk.ru',
    'ploae.com',
    'plw.me',
    'po.bot.nu',
    'poczta.onet.pl',
    'podam.pl',
    'poh.pp.ua',
    'pokeett.site',
    'pokemail.net',
    'pokiemobile.com',
    'politikerclub.de',
    'poly-swarm.com',
    'polyfaust.com',
    'polymnestore.co',
    'polyswarms.com',
    'ponp.be',
    'pooae.com',
    'poofy.org',
    'pookmail.com',
    'poopiebutt.club',
    'pop3.xyz',
    'popconn.party',
    'popesodomy.com',
    'popgx.com',
    'popmail.io',
    'popmailserv.org',
    'porsh.net',
    'posdz.com',
    'post0.profimedia.net',
    'posta.store',
    'postacin.com',
    'postalmail.biz',
    'postcardsfromukraine.crowdpress.it',
    'postfach2go.de',
    'postonline.me',
    'poutineyourface.com',
    'powered.name',
    'powerml.racing',
    'powlearn.com',
    'poy.kr',
    'pp.ua',
    'ppetw.com',
    'ppymail.win',
    'pqoia.com',
    'pqoss.com',
    'pravorobotov.ru',
    'prayersa3.com',
    'premium-mail.fr',
    'premiumperson.website',
    'preseven.com',
    'prestore.co',
    'pricebit.co',
    'priceblog.co',
    'priceio.co',
    'pricenew.co',
    'pricenow.co',
    'priceonline.co',
    'pricepage.co',
    'priceworld.co',
    'primabananen.net',
    'prin.be',
    'priorityxn5.com',
    'priv.beastemail.com',
    'privacy.net',
    'privatdemail.net',
    'privatemailinator.nl',
    'privateme.website',
    'privy-mail.com',
    'privy-mail.de',
    'privymail.de',
    'pro-tag.org',
    'procrackers.com',
    'project-xhabbo.com',
    'projectcl.com',
    'promails.xyz',
    'promptly700.com',
    'proprice.co',
    'proprietativalcea.ro',
    'propscore.com',
    'protempmail.com',
    'protestore.co',
    'proxsei.com',
    'proxymail.eu',
    'proxyparking.com',
    'prs7.xyz',
    'prtnx.com',
    'prtz.eu',
    'psettinge5.com',
    'psh.me',
    'psles.com',
    'psoxs.com',
    'psychedelicwarrior.xyz',
    'pterodactyl.email',
    'publi.innovatio.es',
    'pubmail886.com',
    'puglieisi.com',
    'puji.pro',
    'pullcombine.com',
    'pulpmail.us',
    'pulwarm.net',
    'pumps-fashion.com',
    'punkass.com',
    'purcell.email',
    'purelogistics.org',
    'put2.net',
    'putthisinyourspamdatabase.com',
    'pw.epac.to',
    'pw.islam.igg.biz',
    'pw.j7.cloudns.cx',
    'pwp.lv',
    'pwrby.com',
    'q.xtc.yt',
    'q314.net',
    'q5vm7pi9.com',
    'q7t43q92.com',
    'q7t43q92.com.com',
    'q8cbwendy.com',
    'qacquirep.com',
    'qafatwallet.com',
    'qasti.com',
    'qbfree.us',
    'qbi.kr',
    'qbmail.bid',
    'qc.to',
    'qcmail.qc.to',
    'qedwardr.com',
    'qeispacesq.com',
    'qhstreetr.com',
    'qiaua.com',
    'qibl.at',
    'qipmail.net',
    'qiq.us',
    'qisdo.com',
    'qisoa.com',
    'qj97r73md7v5.com',
    'qlhnu526.com',
    'qnb.io',
    'qocya.com',
    'qoika.com',
    'qopmail.com',
    'qpalong.com',
    'qq.com',
    'qq.my',
    'qqqwwwil.men',
    'qqzymail.win',
    'qs.dp76.com',
    'qs2k.com',
    'qsl.ro',
    'qt1.ddns.net',
    'qtum-ico.com',
    'quadrafit.com',
    'quaestore.co',
    'querydirect.com',
    'questore.co',
    'queuem.com',
    'quickinbox.com',
    'quickmail.nl',
    'quickreport.it',
    'quid4pro.com',
    'quintania.top',
    'ququb.com',
    'qvap.ru',
    'qvy.me',
    'qwarmingu.com',
    'qwfox.com',
    'qwickmail.com',
    'qwqrwsf.date',
    'r.yasser.ru',
    'r0.igg.biz',
    'r31s4fo.com',
    'r4nd0m.de',
    'r8r4p0cb.com',
    'ra3.us',
    'rabin.ca',
    'rabiot.reisen',
    'radecoratingltd.com',
    'raetp9.com',
    'raikas77.eu',
    'rainmail.biz',
    'rainwaterstudios.org',
    'rajarajut.co',
    'raketenmann.de',
    'ralree.com',
    'ramjane.mooo.com',
    'rancidhome.net',
    'randomail.net',
    'rao.kr',
    'rape.lol',
    'rapt.be',
    'raqid.com',
    'rarame.club',
    'raspberrypi123.ddns.net',
    'rattlearray.com',
    'rattlecore.com',
    'rauxa.seny.cat',
    'rawhidefc.org',
    'rawmails.com',
    'rax.la',
    'raxtest.com',
    'razemail.com',
    'rbb.org',
    'rblx.site',
    'rcasd.com',
    'rcpt.at',
    'rcs7.xyz',
    'rdklcrv.xyz',
    're-gister.com',
    'reality-concept.club',
    'reallymymail.com',
    'realtyalerts.ca',
    'rebates.stream',
    'receiveee.chickenkiller.com',
    'receiveee.com',
    'recipeforfailure.com',
    'recode.me',
    'recognised.win',
    'reconmail.com',
    'recruitaware.com',
    'recursor.net',
    'recyclemail.dk',
    'redchan.it',
    'reddit.usa.cc',
    'reddithub.com',
    'redfeathercrow.com',
    'redmail.tech',
    'redpeanut.com',
    'redpen.trade',
    'reftoken.net',
    'refurhost.com',
    'regbypass.com',
    'regbypass.comsafe-mail.net',
    'rejectmail.com',
    'rejo.technology',
    'reliable-mail.com',
    'remarkable.rocks',
    'remote.li',
    'rendymail.com',
    'renraku.in',
    'repolusi.com',
    'reptilegenetics.com',
    'rerajut.com',
    'res.craigslist.org',
    'reservelp.de',
    'resistore.co',
    'resolution4print.info',
    'retkesbusz.nut.cc',
    'revolvingdoorhoax.org',
    'rfc822.org',
    'rfirewallj.com',
    'rfreedomj.com',
    'rgb9000.net',
    'rgphotos.net',
    'rhombushorizons.com',
    'rhyta.com',
    'riamof.club',
    'rich-money.pw',
    'richfinances.pw',
    'richfunds.pw',
    'richmoney.pw',
    'richonedai.pw',
    'richsmart.pw',
    'ricret.com',
    'ricrk.com',
    'riddermark.de',
    'risingsuntouch.com',
    'risu.be',
    'rk9.chickenkiller.com',
    'rklips.com',
    'rko.kr',
    'rkomo.com',
    'rma.ec',
    'rmqkr.net',
    'rnailinator.com',
    'rnzcomesth.com',
    'ro.lt',
    'roastscreen.com',
    'robertspcrepair.com',
    'robo3.club',
    'robo3.co',
    'robo3.me',
    'robo3.site',
    'robot-mail.com',
    'robot2.club',
    'robot2.me',
    'robox.agency',
    'rockkes.us',
    'rohingga.xyz',
    'rollindo.agency',
    'ronnierage.net',
    'rooftest.net',
    'rootfest.net',
    'rotaniliam.com',
    'row.kr',
    'rowe-solutions.com',
    'royal.net',
    'royaldoodles.org',
    'rppkn.com',
    'rq1.in',
    'rq6668f.com',
    'rr-0.cu.cc',
    'rr-1.cu.cc',
    'rr-2.cu.cc',
    'rr-3.cu.cc',
    'rrwbltw.xyz',
    'rs311e8.com',
    'rtotlmail.net',
    'rtrtr.com',
    'rtskiya.xyz',
    'ruditnugnab.xyz',
    'ruffrey.com',
    'ruggedinbox.com',
    'rumgel.com',
    'rundablage.com',
    'runi.ca',
    'rupayamail.com',
    'ruru.be',
    'rustydoor.com',
    'ruu.kr',
    'rvb.ro',
    'rx.dred.ru',
    'rx.qc.to',
    'rxtx.us',
    'ryanb.com',
    'ryumail.net',
    'ryumail.ooo',
    'rzn.host',
    's-s.flu.cc',
    's-s.igg.biz',
    's-s.nut.cc',
    's-s.usa.cc',
    's.bloq.ro',
    's.dextm.ro',
    's.ea.vu',
    's.proprietativalcea.ro',
    's.vdig.com',
    's0.at',
    's0ny.flu.cc',
    's0ny.igg.biz',
    's0ny.net',
    's0ny.nut.cc',
    's0ny.usa.cc',
    's33db0x.com',
    's51zdw001.com',
    's8sigmao.com',
    'sabrestlouis.com',
    'sach.ir',
    'sackboii.com',
    'safe-mail.net',
    'safermail.info',
    'safersignup.com',
    'safersignup.de',
    'safetempmail.com',
    'safetymail.info',
    'safetypost.de',
    'saharanightstempe.com',
    'sale.craigslist.org',
    'salonyfryzjerskie.info',
    'saltysushi.com',
    'salvatore1818.site',
    'samsclass.info',
    'sandcars.net',
    'sandelf.de',
    'sandwhichvideo.com',
    'sanfinder.com',
    'sanim.net',
    'sanstr.com',
    'sanvetetre.com',
    'sapbox.bid',
    'sapya.com',
    'sarapanakun.com',
    'sargrip.asia',
    'sasa22.usa.cc',
    'sast.ro',
    'satisfyme.club',
    'satukosong.com',
    'saukute.me',
    'sausen.com',
    'sawoe.com',
    'saxfun.party',
    'saynotospams.com',
    'sazhimail.ooo',
    'scanitxtr.com',
    'scatmail.com',
    'scay.net',
    'scbox.one.pl',
    'schachrol.com',
    'schafmail.de',
    'schrott-email.de',
    'screamfused.com',
    'screechcontrol.com',
    'sd3.in',
    'sdf.org',
    'sdnr.it',
    'searzh.com',
    'seasideorient.com',
    'secknow.info',
    'secmail.pw',
    'secretemail.de',
    'sector2.org',
    'secure-box.info',
    'secure-box.online',
    'secure-fb.com',
    'secure-mail.biz',
    'secure-mail.cc',
    'secure-mail.cn',
    'secured-link.net',
    'securehost.com.es',
    'securemail.flu.cc',
    'securemail.igg.biz',
    'securemail.nut.cc',
    'securemail.usa.cc',
    'secureserver.usa.cc',
    'seekapps.com',
    'seekfindask.com',
    'seekjobs4u.com',
    'sejaa.lv',
    'selfdestructingmail.com',
    'selfdestructingmail.org',
    'sellim.site',
    'semut-kecil.com',
    'semutkecil.com',
    'send-email.org',
    'send22u.info',
    'sendfree.org',
    'sendingspecialflyers.com',
    'sendspamhere.com',
    'senseless-entertainment.com',
    'sensualerotics.date',
    'seobungbinh.com',
    'seriousalts.de',
    'serv.craigslist.org',
    'server.ms',
    'servermaps.net',
    'services391.com',
    'seven6s.com',
    'sexforswingers.com',
    'sexical.com',
    'sexxfun69.site',
    'sexyalwasmi.top',
    'sexyalwax.online',
    'sexymail.ooo',
    'sezet.com',
    'seznam.cz',
    'sfamo.com',
    'sfgov.net',
    'sfmail.top',
    'shakemain.com',
    'shalar.net',
    'shapoo.ch',
    'sharedmailbox.org',
    'sharing-storage.com',
    'sharklasers.com',
    'shhmail.com',
    'shhuut.org',
    'shieldedmail.com',
    'shieldemail.com',
    'shiftmail.com',
    'shinnemo.com',
    'shipfromto.com',
    'shiphazmat.org',
    'shipping-regulations.com',
    'shippingterms.org',
    'shitmail.de',
    'shitmail.me',
    'shitmail.org',
    'shitposting.agency',
    'shitware.nl',
    'shmeriously.com',
    'shockinmytown.cu.cc',
    'shonky.info',
    'shopbaby.me',
    'shopussy.com',
    'shorterurl.biz',
    'shortmail.net',
    'shotmail.ru',
    'shouldpjr.com',
    'showme.social',
    'showslow.de',
    'shrib.com',
    'shuffle.email',
    'shurs.xyz',
    'shut.name',
    'shut.ws',
    'sibmail.com',
    'sify.com',
    'sign-up.website',
    'sikdar.site',
    'sikux.com',
    'silsilah.life',
    'simpleitsecurity.info',
    'sin.cl',
    'sinda.club',
    'sinfiltro.cl',
    'singlespride.com',
    'singssungg.faith',
    'sink.fblay.com',
    'sinnlos-mail.de',
    'sino.tw',
    'siteposter.net',
    'sizzlemctwizzle.com',
    'sjuaq.com',
    'skeefmail.com',
    'sky-inbox.com',
    'sky-ts.de',
    'skypaluten.de',
    'slapsfromlastnight.com',
    'slaskpost.rymdprojekt.se',
    'slaskpost.se',
    'slave-auctions.net',
    'slippery.email',
    'slipry.net',
    'slopsbox.com',
    'slothmail.net',
    'slowfoodfoothills.xyz',
    'slowslow.de',
    'sls.us',
    'slsrs.ru',
    'slu21svky.com',
    'slushmail.com',
    'sluteen.com',
    'slutty.horse',
    'sly.io',
    'smallanawanginbeach.com',
    'smap.4nmv.ru',
    'smapfree24.com',
    'smapfree24.de',
    'smapfree24.eu',
    'smapfree24.info',
    'smapfree24.org',
    'smaretboy.pw',
    'smarttalent.pw',
    'smashmail.de',
    'smellfear.com',
    'smellrear.com',
    'smoug.net',
    'smsforum.ro',
    'smtp33.com',
    'smtp99.com',
    'smuse.me',
    'smwg.info',
    'snakemail.com',
    'snapemail.me',
    'snapunit.com',
    'snapwet.com',
    'sneakemail.com',
    'sneakmail.de',
    'snkmail.com',
    'snkml.com',
    'socialfurry.org',
    'socrazy.club',
    'socrazy.online',
    'sofimail.com',
    'sofort-mail.de',
    'sofortmail.de',
    'softpls.asia',
    'sogetthis.com',
    'sohu.com',
    'sohu.net',
    'sohus.cn',
    'soioa.com',
    'soisz.com',
    'solar-impact.pro',
    'solowtech.com',
    'solvemail.info',
    'solventtrap.wiki',
    'soodmail.com',
    'soodomail.com',
    'soodonims.com',
    'soon.it',
    'sosmanga.com',
    'sp.woot.at',
    'spa.com',
    'spaereplease.com',
    'spam-be-gone.com',
    'spam-en.de',
    'spam-nicht.de',
    'spam.2012-2016.ru',
    'spam.care',
    'spam.dexter0.xyz',
    'spam.dhsf.net',
    'spam.flu.cc',
    'spam.igg.biz',
    'spam.jasonpearce.com',
    'spam.la',
    'spam.loldongs.org',
    'spam.netpirates.net',
    'spam.nut.cc',
    'spam.org.es',
    'spam.pyphus.org',
    'spam.rogers.us.com',
    'spam.shep.pw',
    'spam.su',
    'spam.trajano.net',
    'spam.usa.cc',
    'spam.visuao.net',
    'spam.wtf.at',
    'spam4.me',
    'spamail.de',
    'spamarrest.com',
    'spamavert.com',
    'spambob.com',
    'spambob.net',
    'spambob.org',
    'spambog.com',
    'spambog.de',
    'spambog.net',
    'spambog.ru',
    'spambooger.com',
    'spambox.info',
    'spambox.irishspringrealty.com',
    'spambox.me',
    'spambox.org',
    'spambox.us',
    'spambox.xyz',
    'spamcannon.com',
    'spamcannon.net',
    'spamcero.com',
    'spamcon.org',
    'spamcorptastic.com',
    'spamcowboy.com',
    'spamcowboy.net',
    'spamcowboy.org',
    'spamday.com',
    'spamdecoy.net',
    'spameater.org',
    'spamex.com',
    'spamfree.eu',
    'spamfree24.com',
    'spamfree24.de',
    'spamfree24.eu',
    'spamfree24.info',
    'spamfree24.net',
    'spamfree24.org',
    'spamgoes.in',
    'spamgourmet.com',
    'spamgourmet.net',
    'spamgourmet.org',
    'spamherelots.com',
    'spamhereplease.com',
    'spamhole.com',
    'spamify.com',
    'spaminator.de',
    'spamkill.info',
    'spaml.com',
    'spaml.de',
    'spamlot.net',
    'spammail.me',
    'spammedic.com',
    'spammehere.com',
    'spammehere.net',
    'spammingemail.com',
    'spammotel.com',
    'spamobox.com',
    'spamoff.de',
    'spamsalad.in',
    'spamslicer.com',
    'spamsphere.com',
    'spamspot.com',
    'spamstack.net',
    'spamthis.co.uk',
    'spamthisplease.com',
    'spamtrail.com',
    'spamtrap.co',
    'spamtrap.ro',
    'spamtroll.net',
    'spamwc.de',
    'spb.ru',
    'speed.1s.fr',
    'speedgaus.net',
    'spikio.com',
    'spindl-e.com',
    'spoofmail.de',
    'sporexbet.com',
    'sportylife.us',
    'spr.io',
    'spreaddashboard.com',
    'spritzzone.de',
    'spybox.de',
    'sqoai.com',
    'squirtsnap.com',
    'squizzy.de',
    'squizzy.eu',
    'squizzy.net',
    'sqxx.net',
    'sr.ro.lt',
    'sraka.xyz',
    'sroff.com',
    'sry.li',
    'ss.undo.it',
    'ssanphones.com',
    'ssgjylc1013.com',
    'sskmail.top',
    'sso-demo-okta.com',
    'ssoia.com',
    'ssongs34f.com',
    'ssunz.cricket',
    'stacklance.com',
    'staircraft5.com',
    'stanfordujjain.com',
    'starlight-breaker.net',
    'starpower.space',
    'startfu.com',
    'startkeys.com',
    'statdvr.com',
    'stathost.net',
    'staticintime.de',
    'statiix.com',
    'stealthypost.org',
    'steambot.net',
    'steamprank.com',
    'steamth.com',
    'stelliteop.info',
    'stexsy.com',
    'stg.malibucoding.com',
    'stinkefinger.net',
    'stomach4m.com',
    'stop-my-spam.com',
    'stop-my-spam.pp.ua',
    'storal.co',
    'storant.co',
    'storeamnos.co',
    'storectic.co',
    'storective.co',
    'storeillet.co',
    'storellin.co',
    'storendite.co',
    'storenia.co',
    'storent.co',
    'storeodon.co',
    'storeodont.co',
    'storeodoxa.co',
    'storeortyx.co',
    'storeotragus.co',
    'storero.co',
    'storestean.co',
    'storesteia.co',
    'storeutics.co',
    'storeweed.co',
    'storewood.co',
    'storeyee.com',
    'storiqax.com',
    'storiqax.top',
    'storist.co',
    'storj99.com',
    'storj99.top',
    'stpetersandstpauls.xyz',
    'streamfly.biz',
    'streamfly.link',
    'streetwisemail.com',
    'stromox.com',
    'stuckmail.com',
    'studentmail.me',
    'studiopolka.tokyo',
    'studioro.review',
    'stuff.munrohk.com',
    'stuffmail.de',
    'stumblemanage.com',
    'stumpfwerk.com',
    'styliste.pro',
    'subpastore.co',
    'suburbanthug.com',
    'succeedabw.com',
    'successforu.pw',
    'successlocation.work',
    'suckmyd.com',
    'sucknfuck.date',
    'sucknfuck.site',
    'sudolife.me',
    'sudolife.net',
    'sudomail.biz',
    'sudomail.com',
    'sudomail.net',
    'sudoverse.com',
    'sudoverse.net',
    'sudoweb.net',
    'sudoworld.com',
    'sudoworld.net',
    'suioe.com',
    'sunbuh.asia',
    'super-auswahl.de',
    'supergreatmail.com',
    'supergreen.com',
    'supermailer.jp',
    'superplatyna.com',
    'superrito.com',
    'superstachel.de',
    'suremail.info',
    'surveyrnonkey.net',
    'sutann.us',
    'sute.jp',
    'suzukilab.net',
    'svip520.cn',
    'svk.jp',
    'svxr.org',
    'sweetxxx.de',
    'swift10minutemail.com',
    'sxylc113.com',
    'sylvannet.com',
    'symphonyresume.com',
    'syujob.accountants',
    'szerz.com',
    'szucsati.net',
    't.psh.me',
    't24e4p7.com',
    't3t97d1d.com',
    'tafmail.com',
    'tafoi.gr',
    'taglead.com',
    'tagmymedia.com',
    'tagyourself.com',
    'takedowns.org',
    'talkinator.com',
    'talkmises.com',
    'tandy.co',
    'tanukis.org',
    'taosjw.com',
    'tapchicuoihoi.com',
    'taphear.com',
    'tarlancapital.com',
    'taskforcetech.com',
    'taskscbo.com',
    'taxi-france.com',
    'taylorventuresllc.com',
    'tb-on-line.net',
    'tdf-illustration.com',
    'te.budayationghoa.com',
    'te.pecinan.org',
    'tebwinsoi.ooo',
    'tech69.com',
    'techemail.com',
    'techfevo.info',
    'techgroup.me',
    'techmail.info',
    'technikue.men',
    'tedswoodworking.science',
    'teemia.com',
    'teerest.com',
    'teewars.org',
    'tefl.ro',
    'tegnabrapal.me',
    'telecomix.pl',
    'teleosaurs.xyz',
    'teleworm.com',
    'teleworm.us',
    'tellos.xyz',
    'temp-emails.com',
    'temp-mail.com',
    'temp-mail.de',
    'temp-mail.info',
    'temp-mail.net',
    'temp-mail.org',
    'temp-mail.pp.ua',
    'temp-mail.ru',
    'temp-mails.com',
    'temp.bartdevos.be',
    'temp.cloudns.asia',
    'temp.emeraldwebmail.com',
    'temp.headstrong.de',
    'temp.mail.y59.jp',
    'temp.wheezer.net',
    'temp1.club',
    'temp15qm.com',
    'temp2.club',
    'tempail.com',
    'tempalias.com',
    'tempe-mail.com',
    'tempemail.biz',
    'tempemail.co.za',
    'tempemail.com',
    'tempemail.net',
    'tempemail.org',
    'tempemail.pro',
    'tempemailaddress.com',
    'tempemails.io',
    'tempinbox.co.uk',
    'tempinbox.com',
    'tempm.com',
    'tempmail.co',
    'tempmail.de',
    'tempmail.eu',
    'tempmail.io',
    'tempmail.it',
    'tempmail.pp.ua',
    'tempmail.pro',
    'tempmail.space',
    'tempmail.sytes.net',
    'tempmail.top',
    'tempmail.us',
    'tempmail.website',
    'tempmail.win',
    'tempmail.ws',
    'tempmail2.com',
    'tempmaildemo.com',
    'tempmailer.com',
    'tempmailer.de',
    'tempmails.org',
    'tempomail.fr',
    'temporamail.com',
    'temporarily.de',
    'temporarioemail.com.br',
    'temporary-email.com',
    'temporaryemail.net',
    'temporaryemail.us',
    'temporaryforwarding.com',
    'temporaryinbox.com',
    'temporarymail.org',
    'temporarymailaddress.com',
    'tempr.email',
    'tempsky.com',
    'tempthe.net',
    'tempymail.com',
    'terminate.tech',
    'test.com',
    'test.crowdpress.it',
    'test.de',
    'testore.co',
    'testudine.com',
    'tf7nzhw.com',
    'tfwno.gf',
    'thangberus.net',
    'thanksnospam.info',
    'thankyou2010.com',
    'thatim.info',
    'thc.st',
    'theaperturelabs.com',
    'theaperturescience.com',
    'theaviors.com',
    'thebearshark.com',
    'thebest4ever.com',
    'thebestremont.ru',
    'thecloudindex.com',
    'thedarkmaster097.sytes.net',
    'thediamants.org',
    'thedirhq.info',
    'thefirstticket.com',
    'thelightningmail.net',
    'thelimestones.com',
    'themail.krd.ag',
    'thembones.com.au',
    'themostemail.com',
    'thenewsdhhayy.com',
    'theodore1818.site',
    'theone2017.us',
    'theopposition.club',
    'theothermail.com',
    'theplug.org',
    'thereddoors.online',
    'thescrappermovie.com',
    'theslatch.com',
    'thespawningpool.com',
    'thestats.top',
    'theteastory.info',
    'thetrash.email',
    'thex.ro',
    'thietbivanphong.asia',
    'thinkingus24.com',
    'thisisnotmyrealemail.com',
    'thismail.net',
    'thisurl.website',
    'thnikka.com',
    'thraml.com',
    'thrma.com',
    'throam.com',
    'thrott.com',
    'throwam.com',
    'throwawayemail.com',
    'throwawayemailaddress.com',
    'throwawaymail.com',
    'throwawaymail.pp.ua',
    'throya.com',
    'thug.pw',
    'thunderbolt.science',
    'thunkinator.org',
    'thxmate.com',
    'ti.igg.biz',
    'tiapz.com',
    'tic.ec',
    'ticklecontrol.com',
    'tijdelijkmailadres.nl',
    'tilien.com',
    'timekr.xyz',
    'timgiarevn.com',
    'timkassouf.com',
    'tinoza.org',
    'tinyurl24.com',
    'tipsb.com',
    'tittbit.in',
    'tiv.cc',
    'tizi.com',
    'tkitc.de',
    'tkmy88m.com',
    'tko.co.kr',
    'tko.kr',
    'tlpn.org',
    'tm.slsrs.ru',
    'tm.tosunkaya.com',
    'tm2mail.com',
    'tmail.com',
    'tmail.run',
    'tmail.ws',
    'tmailinator.com',
    'tmails.net',
    'tmo.kr',
    'tmp.refi64.com',
    'tmpeml.info',
    'tmpjr.me',
    'tmpmail.net',
    'tmpmail.org',
    'tntitans.club',
    'toastmatrix.com',
    'toastsum.com',
    'toddsbighug.com',
    'toi.kr',
    'toiea.com',
    'tokem.co',
    'tokenmail.de',
    'tokuriders.club',
    'tonymanso.com',
    'tool.pp.ua',
    'toomail.biz',
    'toothandmail.com',
    'top101.de',
    'top1mail.ru',
    'top1post.ru',
    'top9appz.info',
    'topikt.com',
    'toplessbucksbabes.us',
    'topmailings.com',
    'topmall.com',
    'topmall.info',
    'topmall.org',
    'topofertasdehoy.com',
    'topranklist.de',
    'toprumours.com',
    'torch.yi.org',
    'torm.xyz',
    'tormail.net',
    'tormail.org',
    'toss.pw',
    'tosunkaya.com',
    'totalvista.com',
    'totesmail.com',
    'totoan.info',
    'tp-qa-mail.com',
    'tqoai.com',
    'tqosi.com',
    'tracciabi.li',
    'tradermail.info',
    'tranceversal.com',
    'transistore.co',
    'trash-amil.com',
    'trash-mail.at',
    'trash-mail.com',
    'trash-mail.de',
    'trash-mail.net',
    'trash-me.com',
    'trash2009.com',
    'trash2010.com',
    'trash2011.com',
    'trash247.com',
    'trash4.me',
    'trashbox.eu',
    'trashcanmail.com',
    'trashdevil.com',
    'trashdevil.de',
    'trashemail.de',
    'trashemails.de',
    'trashimail.de',
    'trashinbox.com',
    'trashinbox.net',
    'trashmail.app',
    'trashmail.at',
    'trashmail.com',
    'trashmail.de',
    'trashmail.io',
    'trashmail.me',
    'trashmail.net',
    'trashmail.org',
    'trashmail.ws',
    'trashmailer.com',
    'trashmails.com',
    'trashspam.com',
    'trashymail.com',
    'trashymail.net',
    'trasz.com',
    'travala10.com',
    'trayna.com',
    'trbvm.com',
    'trbvn.com',
    'trbvo.com',
    'trendingtopic.cl',
    'trg.pw',
    'trgovinanaveliko.info',
    'trialmail.de',
    'trickmail.net',
    'trillianpro.com',
    'trimsj.com',
    'trobertqs.com',
    'trollproject.com',
    'tropicalbass.info',
    'trung.name.vn',
    'trungtamtoeic.com',
    'tryalert.com',
    'tryninja.io',
    'tryprice.co',
    'tryzoe.com',
    'tt2dx90.com',
    'ttszuo.xyz',
    'tualias.com',
    'tubruk.trade',
    'tucumcaritonite.com',
    'tug.minecraftrabbithole.com',
    'tukupedia.co',
    'tuncpersonel.com',
    'turoid.com',
    'turual.com',
    'tvchd.com',
    'tverya.com',
    'twddos.net',
    'tweakly.net',
    'twelvee.us',
    'twinmail.de',
    'twocowmail.net',
    'twoweirdtricks.com',
    'tx.igg.biz',
    'txpwg.usa.cc',
    'txt.flu.cc',
    'txt7e99.com',
    'txtadvertise.com',
    'ty.ceed.se',
    'ty.squirtsnap.com',
    'tyclonecuongsach.site',
    'tyhe.ro',
    'tyldd.com',
    'tz.tz',
    'u-wills-uc.pw',
    'u.0u.ro',
    'u.10x.es',
    'u.2sea.org',
    'u.900k.es',
    'u.civvic.ro',
    'u.dmarc.ro',
    'u.labo.ch',
    'u.qvap.ru',
    'u1.myftp.name',
    'u4nzbr5q3.com',
    'u6lvty2.com',
    'ua3jx7n0w3.com',
    'uacro.com',
    'uacrossad.com',
    'uapproves.com',
    'ubismail.net',
    'ubm.md',
    'ucandobest.pw',
    'ucansuc.pw',
    'ucche.us',
    'ucho.top',
    'ucylu.com',
    'udoiswell.pw',
    'uemail99.com',
    'ufacturing.com',
    'ufgqgrid.xyz',
    'uggsrock.com',
    'ugimail.net',
    'ugreatejob.pw',
    'uguuchantele.com',
    'uha.kr',
    'uhhu.ru',
    'uikd.com',
    'uiu.us',
    'ujames3nh.com',
    'ujxspots.com',
    'uk.to',
    'ukexample.com',
    'uko.kr',
    'ulaptopsn.com',
    'ultra.fyi',
    'ulumdocab.xyz',
    'umail.net',
    'umy.kr',
    'uncond.us',
    'undo.it',
    'unids.com',
    'unimark.org',
    'unit7lahaina.com',
    'unlimit.com',
    'unmail.ru',
    'unpastore.co',
    'unseen.eu',
    'uny.kr',
    'upliftnow.com',
    'uplipht.com',
    'uploadnolimit.com',
    'upozowac.info',
    'upskirtscr.com',
    'upy.kr',
    'uralplay.ru',
    'urbanchickencoop.com',
    'ureee.us',
    'urfey.com',
    'urfunktion.se',
    'urltc.com',
    'uroid.com',
    'us.af',
    'us.to',
    'usa-cc.usa.cc',
    'usa.cc',
    'usa.isgre.at',
    'usako.be',
    'usako.net',
    'uscaves.com',
    'used-product.fr',
    'username.e4ward.com',
    'usharingk.com',
    'usiaj.com',
    'utiket.us',
    'utilities-online.info',
    'uu.gl',
    'uu2.ovh',
    'uvy.kr',
    'uw5t6ds54.com',
    'uwillsuc.pw',
    'uwork4.us',
    'ux.dob.jp',
    'ux.uk.to',
    'uxorv.anonbox.net',
    'uyhip.com',
    'uyu.kr',
    'uz6tgwk.com',
    'uzrip.com',
    'v-mail.xyz',
    'v.0v.ro',
    'v.jsonp.ro',
    'v21.me.uk',
    'vaati.org',
    'valemail.net',
    'valhalladev.com',
    'vanacken.xyz',
    'vanhoangtn1.ooo',
    'vanhoangtn1.us',
    'vankin.de',
    'vay.kr',
    'vba.kr',
    'vctel.com',
    'vda.ro',
    'vdig.com',
    'vedula.com',
    'vektik.com',
    'vemomail.win',
    'venompen.com',
    'veo.kr',
    'verdejo.com',
    'verifymail.win',
    'vermutlich.net',
    'veryday.ch',
    'veryday.eu',
    'veryday.info',
    'veryprice.co',
    'veryrealemail.com',
    'vesa.pw',
    'vfemail.net',
    'vhglvi6o.com',
    'via.tokyo.jp',
    'victime.ninja',
    'victoriantwins.com',
    'vidchart.com',
    'viditag.com',
    'viewcastmedia.com',
    'viewcastmedia.net',
    'viewcastmedia.org',
    'vikingsonly.com',
    'villabhj.com',
    'vincenza1818.site',
    'vinernet.com',
    'vinsmoke.tech',
    'vip.cool',
    'vipepe.com',
    'vipmail.name',
    'vipmail.pw',
    'vipsohu.net',
    'vipxm.net',
    'viralhits.org',
    'viralplays.com',
    'viroleni.cu.cc',
    'visa.coms.hk',
    'vistomail.com',
    'vistore.co',
    'viwsala.com',
    'vixletdev.com',
    'vkcode.ru',
    'vmail.me',
    'vmail.tech',
    'vmailing.info',
    'vmani.com',
    'vmpanda.com',
    'vncoders.net',
    'vnedu.me',
    'vnshare.info',
    'voidbay.com',
    'vomoto.com',
    'vorga.org',
    'votiputox.org',
    'voxelcore.com',
    'vp.ycare.de',
    'vpfbattle.com',
    'vpn.st',
    'vpn33.top',
    'vprice.co',
    'vps30.com',
    'vps911.net',
    'vpslists.com',
    'vpsorg.pro',
    'vpsorg.top',
    'vpstraffic.com',
    'vr5gpowerv.com',
    'vrloco.com',
    'vrmtr.com',
    'vrpitch.com',
    'vrsim.ir',
    'vs904a6.com',
    'vsimcard.com',
    'vssms.com',
    'vstartup4q.com',
    'vteachesb.com',
    'vtxmail.us',
    'vubby.com',
    'vuiy.pw',
    'vvx046q.com',
    'vztc.com',
    'w.0w.ro',
    'w22fe21.com',
    'w3internet.co.uk',
    'w3windsor.com',
    'w4i3em6r.com',
    'w918bsq.com',
    'w9f.de',
    'w9y9640c.com',
    'wagfused.com',
    'waifu.club',
    'wakingupesther.com',
    'walala.org',
    'walkmail.net',
    'walkmail.ru',
    'wallm.com',
    'want2lov.us',
    'wantplay.site',
    'wants.dicksinhisan.us',
    'wants.dicksinmyan.us',
    'warau-kadoni.com',
    'warnednl2.com',
    'wasd.10mail.org',
    'wasd.dropmail.me',
    'wasteland.rfc822.org',
    'watch-harry-potter.com',
    'watchever.biz',
    'watchfull.net',
    'watchironman3onlinefreefullmovie.com',
    'wawi.es',
    'wazabi.club',
    'wbml.net',
    'we.lovebitco.in',
    'we.qq.my',
    'wealthymoney.pw',
    'web-contact.info',
    'web-email.eu',
    'web-emailbox.eu',
    'web-ideal.fr',
    'web-mail.pp.ua',
    'web.id',
    'web2mailco.com',
    'webarnak.fr.eu.org',
    'webcontact-france.eu',
    'webemail.me',
    'webkiff.info',
    'webm4il.info',
    'webmail.igg.biz',
    'webmail.kolmpuu.net',
    'webmeetme.com',
    'webtrip.ch',
    'webuser.in',
    'wee.my',
    'wef.gr',
    'wefjo.grn.cc',
    'weg-beschlussbuch.de',
    'weg-werf-email.de',
    'wegas.ru',
    'wegwerf-email-addressen.de',
    'wegwerf-email-adressen.de',
    'wegwerf-email.at',
    'wegwerf-email.de',
    'wegwerf-email.net',
    'wegwerf-emails.de',
    'wegwerfadresse.de',
    'wegwerfemail.com',
    'wegwerfemail.de',
    'wegwerfemail.info',
    'wegwerfemail.net',
    'wegwerfemail.org',
    'wegwerfemailadresse.com',
    'wegwerfmail.de',
    'wegwerfmail.info',
    'wegwerfmail.net',
    'wegwerfmail.org',
    'wegwerpmailadres.nl',
    'wegwrfmail.de',
    'wegwrfmail.net',
    'wegwrfmail.org',
    'welikecookies.com',
    'wellhungup.dynu.net',
    'wem.com',
    'wetrainbayarea.com',
    'wetrainbayarea.org',
    'wfought0o.com',
    'wg0.com',
    'wh4f.org',
    'whatiaas.com',
    'whatifanalytics.com',
    'whatpaas.com',
    'whatsaas.com',
    'whiffles.org',
    'whisperfocus.com',
    'whispersum.com',
    'whitebot.ru',
    'whopy.com',
    'whtjddn.33mail.com',
    'whyspam.me',
    'wibblesmith.com',
    'wicked.cricket',
    'wickmail.net',
    'widaryanto.info',
    'widget.gg',
    'wiki.8191.at',
    'wikidocuslava.ru',
    'wikilibhub.ru',
    'wikisite.co',
    'wil.kr',
    'wilemail.com',
    'willhackforfood.biz',
    'williamcastillo.me',
    'willselfdestruct.com',
    'wimsg.com',
    'winemaven.info',
    'winnweb.win',
    'wins.com.br',
    'wishan.net',
    'with-u.us',
    'wiz2.site',
    'wjhndxn.xyz',
    'wla9c4em.com',
    'wlist.ro',
    'wmail.club',
    'wmlorgana.com',
    'wn8c38i.com',
    'wolfmission.com',
    'wollan.info',
    'womenhealthcare.ooo',
    'wordme.stream',
    'work4uber.us',
    'worlddonation.org',
    'worldsonlineradios.com',
    'worldspace.link',
    'wormseo.cn',
    'wp2romantic.com',
    'wpg.im',
    'wpmail.org',
    'wr.moeri.org',
    'wr9v6at7.com',
    'wralawfirm.com',
    'writeme.us',
    'wronghead.com',
    'ws.gy',
    'wu138.club',
    'wu158.top',
    'wudet.men',
    'wuespdj.xyz',
    'wupics.com',
    'wuzup.net',
    'wuzupmail.net',
    'wvl238skmf.com',
    'www.bccto.com',
    'www.bccto.me',
    'www.e4ward.com',
    'www.gishpuppy.com',
    'www.live.co.kr.beo.kr',
    'www.mailinator.com',
    'www.redpeanut.com',
    'wwwnew.eu',
    'wxnw.net',
    'wyvernia.net',
    'wzukltd.com',
    'x.ip6.li',
    'x13x13x13.com',
    'x1x.spb.ru',
    'x1x22716.com',
    'x24.com',
    'x4y.club',
    'x5a9m8ugq.com',
    'x8h8x941l.com',
    'xagloo.co',
    'xagloo.com',
    'xbaby69.top',
    'xc05fypuj.com',
    'xcode.ro',
    'xcompress.com',
    'xcpy.com',
    'xemaps.com',
    'xemne.com',
    'xents.com',
    'xf.sluteen.com',
    'xfamiliar9.com',
    'xgmailoo.com',
    'xing886.uu.gl',
    'xinzk1ul.com',
    'xjin.xyz',
    'xjoi.com',
    'xl.cx',
    'xlgaokao.com',
    'xloveme.top',
    'xmail.com',
    'xmaily.com',
    'xn--9kq967o.com',
    'xn--b-dga.vn',
    'xn--d-bga.net',
    'xn--mgbgvi3fi.com',
    'xn--mll-hoa.email',
    'xn--mllemail-65a.com',
    'xn--mllmail-n2a.com',
    'xn--namnh-7ya4834c.net',
    'xnmail.mooo.com',
    'xoixa.com',
    'xost.us',
    'xoxox.cc',
    'xoxy.net',
    'xperiae5.com',
    'xprice.co',
    'xrho.com',
    'xuyushuai.com',
    'xv9u9m.com',
    'xvx.us',
    'xwaretech.com',
    'xwaretech.info',
    'xwaretech.net',
    'xww.ro',
    'xxi2.com',
    'xxlocanto.us',
    'xxme.me',
    'xxolocanto.us',
    'xxqx3802.com',
    'xyzfree.net',
    'xyzmail.men',
    'xzsok.com',
    'xzymoe.edu.pl',
    'y.bcb.ro',
    'y0brainx6.com',
    'y59.jp',
    'ya.yomail.info',
    'yadavnaresh.com.np',
    'yahmail.top',
    'yahomail.top',
    'yahoodashtrick.com',
    'yahooproduct.com',
    'yahooproduct.net',
    'yalamail.com',
    'yamail.win',
    'yandere.cu.cc',
    'yandex.com',
    'yandex.ru',
    'yanet.me',
    'yannmail.win',
    'yapped.net',
    'yaqp.com',
    'yasser.ru',
    'ycare.de',
    'ycn.ro',
    'ydeclinegv.com',
    'ye.vc',
    'yedi.org',
    'yentzscholarship.xyz',
    'yep.it',
    'yewmail.com',
    'ygroupvideoarchive.com',
    'ygroupvideoarchive.net',
    'yhg.biz',
    'yk20.com',
    'ymail.net',
    'ymail.org',
    'ymail.site',
    'yndrinks.com',
    'ynmrealty.com',
    'yodx.ro',
    'yogamaven.com',
    'yomail.info',
    'yoo.ro',
    'yood.org',
    'yop.email',
    'yop.profmusique.com',
    'yop.ze.cx',
    'yopmail.biz.st',
    'yopmail.com',
    'yopmail.fr',
    'yopmail.fr.nf',
    'yopmail.info',
    'yopmail.net',
    'yopmail.org',
    'yopmail.pp.ua',
    'yopmail.usa.cc',
    'yoru-dea.com',
    'you-spam.com',
    'you.e4ward.com',
    'youbestone.pw',
    'youcankeepit.info',
    'yougotgoated.com',
    'youmailr.com',
    'youneedmore.info',
    'youporn.flu.cc',
    'youporn.igg.biz',
    'youporn.usa.cc',
    'youpymail.com',
    'yourbonus.win',
    'yourdomain.com',
    'yourewronghereswhy.com',
    'yourlms.biz',
    'youveo.ch',
    'youzend.net',
    'ypmail.webarnak.fr.eu.org',
    'yreilof.xyz',
    'yroid.com',
    'yspend.com',
    'ytpayy.com',
    'yugasandrika.com',
    'yui.it',
    'yuoia.com',
    'yuslamail.com',
    'yuurok.com',
    'yuuywil.date',
    'yxzx.net',
    'yy-h2.nut.cc',
    'yyhmail.com',
    'yyj295r31.com',
    'yyolf.net',
    'yyt.resolution4print.info',
    'yytv.ddns.net',
    'z0d.eu',
    'z1p.biz',
    'z7az14m.com',
    'z86.ru',
    'za.com',
    'zain.site',
    'zainmax.net',
    'zaktouni.fr',
    'zamge.com',
    'zane.rocks',
    'zapbox.fr',
    'zasod.com',
    'zasve.info',
    'zavio.nl',
    'zdenka.net',
    'ze.cx',
    'ze.gally.jp',
    'ze.tc',
    'zebins.com',
    'zebins.eu',
    'zebra.email',
    'zehnminuten.de',
    'zehnminutenmail.de',
    'zep-hyr.com',
    'zepp.dk',
    'zeta-telecom.com',
    'zetmail.com',
    'zf4r34ie.com',
    'zfymail.com',
    'zhaoyuanedu.cn',
    'zhcne.com',
    'zhewei88.com',
    'zhorachu.com',
    'zhouemail.510520.org',
    'zik.dj',
    'zimbail.me',
    'zipcad.com',
    'zippiex.com',
    'zippymail.info',
    'zipsendtest.com',
    'zipzaprap.beerolympics.se',
    'zipzaps.de',
    'zixoa.com',
    'ziyap.com',
    'zmail.info.tm',
    'zoaxe.com',
    'zoemail.com',
    'zoemail.net',
    'zoemail.org',
    'zoetropes.org',
    'zombie-hive.com',
    'zomg.info',
    'zp.ua',
    'zubacteriax.com',
    'zumpul.com',
    'zv68.com',
    'zw6provider.com',
    'zxcv.com',
    'zxcvbnm.com',
    'zxcxc.com',
    'zymail.men',
    'zymuying.com',
    'zzi.us',
    'zzz.com',
];
<?php

return [
    '-online.de',
    '-tonline.de',
    'acor.de',
    'aecor.de',
    'ahoo.de',
    'al.com',
    'ao.com',
    'aol.cm',
    'aol.con',
    'aol.ocm',
    'aol.om',
    'aoll.com',
    'apl.com',
    'arco.de',
    'arocr.de',
    'aror.de',
    'feenet.de',
    'freeenet.de',
    'freeent.de',
    'freeet.de',
    'freemet.de',
    'freeneet.de',
    'freent.de',
    'frenet.de',
    'gm.de',
    'gm.net',
    'gm.xde',
    'gmc.de',
    'gmx.ded',
    'gmx.dw',
    'gmxx.de',
    'gmy.de',
    'gx.de',
    'hmx.de',
    'homail.de',
    'hotmai.de',
    'hotmal.de',
    'mx.de',
    'mx.net',
    'otmail.com',
    'r-online.de',
    'rcor.de',
    'reenet.de',
    't--online.de',
    't-0nline.de',
    't-nline.de',
    't-oline.de',
    't-omline.de',
    't-onine.de',
    't-onlien.de',
    't-onliine.de',
    't-onlin.de',
    't-onlinde.de',
    't-onlinr.de',
    't-onlione.de',
    't-onlline.de',
    't-onlne.de',
    't-onlone.de',
    't.-online.de',
    't.online.de',
    'tonline.de',
    'wb.de',
    'we.de',
    'web.ded',
    'web.dw',
    'wed.de',
    'weeb.de',
    'wen.de',
    'wweb.de',
    'yaho.de',
    'yahooo.de',
    'yaoo.de',
    'yhoo.de',
    'yahhoo.de',
];
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * E-Mail Check Class
 *
 * -> use "EmailCheck::isValid()" to validate a email-address
 *
 * @copyright   Copyright (c) 2018, Lars Moelleken (http://moelleken.org/)
 * @license     http://opensource.org/licenses/MIT	MIT License
 */
class EmailCheck
{
    /**
     * @var array|null
     */
    protected static $domainsExample = null;

    /**
     * @var array|null
     */
    protected static $domainsTemporary = null;

    /**
     * @var array|null
     */
    protected static $domainsTypo = null;

    /**
     * @var bool
     */
    protected static $useDnsCheck = true;

    /**
     * Check if the domain has a MX- or A-record in the DNS.
     *
     * @param string $domain
     *
     * @throws \Exception
     *
     * @return bool
     */
    public static function isDnsError(string $domain): bool
    {
        if (\function_exists('checkdnsrr')) {
            /** @noinspection IfReturnReturnSimplificationInspection */
            $mxFound = \checkdnsrr($domain . '.', 'MX');
            if ($mxFound === true) {
                return false;
            }

            $aFound = \checkdnsrr($domain . '.', 'A');
            /** @noinspection IfReturnReturnSimplificationInspection */
            if ($aFound === true) {
                return false;
            }

            return true;
        }

        throw new \Exception(' Can\'t call checkdnsrr');
    }

    /**
     * Check if the domain is a example domain.
     *
     * @param string $domain
     *
     * @return bool
     */
    public static function isExampleDomain(string $domain): bool
    {
        if (self::$domainsExample === null) {
            self::$domainsExample = self::getData('domainsExample');
        }

        if (\in_array($domain, self::$domainsExample, true)) {
            return true;
        }

        return false;
    }

    /**
     * Check if the domain is a temporary domain.
     *
     * @param string $domain
     *
     * @return bool
     */
    public static function isTemporaryDomain(string $domain): bool
    {
        if (self::$domainsTemporary === null) {
            self::$domainsTemporary = self::getData('domainsTemporary');
        }

        if (\in_array($domain, self::$domainsTemporary, true)) {
            return true;
        }

        if (\preg_match('/.*\.(?:tk|ml|ga|cf|gq)$/si', $domain)) {
            return true;
        }

        return false;
    }

    /**
     * Check if the domain has a typo.
     *
     * @param string $domain
     *
     * @return bool
     */
    public static function isTypoInDomain(string $domain): bool
    {
        if (self::$domainsTypo === null) {
            self::$domainsTypo = self::getData('domainsTypo');
        }

        if (\in_array($domain, self::$domainsTypo, true)) {
            return true;
        }

        return false;
    }

    /**
     * @param string $email
     *
     * @return false|array{local: string, domain: string}
     */
    public static function getMailParts(string $email)
    {
        if ($email === '') {
            return false;
        }

        $email = \str_replace(
            [
                '.', // non-Latin chars are also allowed | https://tools.ietf.org/html/rfc6530
                '＠', // non-Latin chars are also allowed | https://tools.ietf.org/html/rfc6530
            ],
            [
                '.',
                '@',
            ],
            $email
        );

        if (
            (\strpos($email, '@') === false) // "at" is needed
            ||
            (\strpos($email, '.') === false && \strpos($email, ':') === false) // "dot" or "colon" is needed
        ) {
            return false;
        }

        if (!\preg_match('/^(?<local>.*<?)(?:.*)@(?<domain>.*)(?:>?)$/', $email, $parts)) {
            return false;
        }

        $local = $parts['local'];
        $domain = $parts['domain'];

        if (!$local) {
            return false;
        }

        if (!$domain) {
            return false;
        }

        return [
            'local' => $local,
            'domain' => $domain,
        ];
    }

    /**
     * Check if the email is valid.
     *
     * @param string $email
     * @param bool   $useExampleDomainCheck
     * @param bool   $useTypoInDomainCheck
     * @param bool   $useTemporaryDomainCheck
     * @param bool   $useDnsCheck             (do not use, if you don't need it)
     *
     * @return bool
     */
    public static function isValid(string $email, bool $useExampleDomainCheck = false, bool $useTypoInDomainCheck = false, bool $useTemporaryDomainCheck = false, bool $useDnsCheck = false): bool
    {
        if (!isset($email[0])) {
            return false;
        }

        // make sure string length is limited to avoid DOS attacks
        $emailStringLength = \strlen($email);
        if (
            $emailStringLength >= 320
            ||
            $emailStringLength <= 2 // i@y //
        ) {
            return false;
        }
        unset($emailStringLength);

        $parts = self::getMailParts($email);
        if ($parts === false) {
            return false;
        }

        $local = $parts['local'];
        $domain = $parts['domain'];

        // Escaped spaces are allowed in the "local"-part.
        $local = \str_replace('\\ ', '', $local);

        // Spaces in quotes e.g. "firstname lastname"@foo.bar are also allowed in the "local"-part.
        $quoteHelperForIdn = false;
        if (\preg_match('/^"(?<inner>[^"]*)"$/mU', $local, $parts)) {
            $quoteHelperForIdn = true;
            $local = \trim(
                \str_replace(
                    $parts['inner'],
                    \str_replace(' ', '', $parts['inner']),
                    $local
                ),
                '"'
            );
        }

        if (
            \strpos($local, ' ') !== false // no spaces allowed, anymore
            ||
            \strpos($local, '".') !== false // no quote + dot allowed
        ) {
            return false;
        }

        list($local, $domain) = self::punnycode($local, $domain);

        if ($quoteHelperForIdn === true) {
            $local = '"' . $local . '"';
        }

        $email = $local . '@' . $domain;

        if (!\filter_var($email, \FILTER_VALIDATE_EMAIL)) {
            return false;
        }

        if ($useExampleDomainCheck === true && self::isExampleDomain($domain) === true) {
            return false;
        }

        if ($useTypoInDomainCheck === true && self::isTypoInDomain($domain) === true) {
            return false;
        }

        if ($useTemporaryDomainCheck === true && self::isTemporaryDomain($domain) === true) {
            return false;
        }

        if ($useDnsCheck === true && self::isDnsError($domain) === true) {
            return false;
        }

        return true;
    }

    /**
     * get data from "/data/*.php"
     *
     * @param string $file
     *
     * @return array|bool|int|string <p>Will return false on error.</p>
     */
    protected static function getData(string $file)
    {
        $file = __DIR__ . '/data/' . $file . '.php';
        if (\file_exists($file)) {
            /** @noinspection PhpIncludeInspection */
            return require $file;
        }

        return false;
    }

    /**
     * @param string $local
     * @param string $domain
     *
     * @return array
     */
    private static function punnycode(string $local, string $domain): array
    {

        // https://git.ispconfig.org/ispconfig/ispconfig3/blob/master/interface/lib/classes/functions.inc.php#L305
        if (
            \defined('IDNA_NONTRANSITIONAL_TO_ASCII')
            &&
            \defined('INTL_IDNA_VARIANT_UTS46')
            &&
            \constant('IDNA_NONTRANSITIONAL_TO_ASCII')
        ) {
            $useIdnaUts46 = true;
        } else {
            $useIdnaUts46 = false;
        }

        if ($useIdnaUts46 === true) {
            /** @noinspection PhpComposerExtensionStubsInspection */
            $localTmp = \idn_to_ascii($local, \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46);
        } else {
            /** @noinspection PhpComposerExtensionStubsInspection */
            $localTmp = \idn_to_ascii($local);
        }
        if ($localTmp) {
            $local = $localTmp;
        }
        unset($localTmp);

        if ($useIdnaUts46 === true) {
            /** @noinspection PhpComposerExtensionStubsInspection */
            $domainTmp = \idn_to_ascii($domain, \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46);
        } else {
            /** @noinspection PhpComposerExtensionStubsInspection */
            $domainTmp = \idn_to_ascii($domain);
        }
        if ($domainTmp) {
            $domain = $domainTmp;
        }
        unset($domainTmp);

        return [$local, $domain];
    }
}
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * ## 🇷🇺 Русским гражданам
 * В Украине сейчас идет война. Силами РФ наносятся удары по гражданской инфраструктуре в [Харькове][1], [Киеве][2], [Чернигове][3], [Сумах][4], [Ирпене][5] и десятках других городов. Гибнут люди - и гражданское население, и военные, в том числе российские призывники, которых бросили воевать. Чтобы лишить собственный народ доступа к информации, правительство РФ запретило называть войну войной, закрыло независимые СМИ и принимает сейчас ряд диктаторских законов. Эти законы призваны заткнуть рот всем, кто против войны. За обычный призыв к миру сейчас можно получить несколько лет тюрьмы.
 * Не молчите! Молчание - знак вашего согласия с политикой российского правительства.
 *  **Вы можете сделать выбор НЕ МОЛЧАТЬ.**
 * ---
 * ## 🇺🇸 To people of Russia
 * There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilian infrastructure in [Kharkiv][1], [Kyiv][2], [Chernihiv][3], [Sumy][4], [Irpin][5] and dozens of other cities. People are dying – both civilians and military servicemen, including Russian conscripts who were thrown into the fighting. In order to deprive its own people of access to information, the government of the Russian Federation has forbidden calling a war a war, shut down independent media and is passing a number of dictatorial laws. These laws are meant to silence all those who are against war. You can be jailed for multiple years for simply calling for peace.
 * Do not be silent! Silence is a sign that you accept the Russian government's policy.
 * **You can choose NOT TO BE SILENT.**
 * ---
 * - [1] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/P7K2MSZDGFMIJPDD7CI2GIROJI.jpg "Kharkiv under attack"
 * - [2] https://gdb.voanews.com/01bd0000-0aff-0242-fad0-08d9fc92c5b3_cx0_cy5_cw0_w1023_r1_s.jpg "Kyiv under attack"
 * - [3] https://ichef.bbci.co.uk/news/976/cpsprodpb/163DD/production/_123510119_hi074310744.jpg "Chernihiv under attack"
 * - [4] https://www.youtube.com/watch?v=8K-bkqKKf2A "Sumy under attack"
 * - [5] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/K4MTMLEHTRKGFK3GSKAT4GR3NE.jpg "Irpin under attack"
 *
 * @psalm-immutable
 */
final class ASCII
{
    //
    // INFO: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
    //

    const UZBEK_LANGUAGE_CODE = 'uz';

    const TURKMEN_LANGUAGE_CODE = 'tk';

    const THAI_LANGUAGE_CODE = 'th';

    const PASHTO_LANGUAGE_CODE = 'ps';

    const ORIYA_LANGUAGE_CODE = 'or';

    const MONGOLIAN_LANGUAGE_CODE = 'mn';

    const KOREAN_LANGUAGE_CODE = 'ko';

    const KIRGHIZ_LANGUAGE_CODE = 'ky';

    const ARMENIAN_LANGUAGE_CODE = 'hy';

    const BENGALI_LANGUAGE_CODE = 'bn';

    const BELARUSIAN_LANGUAGE_CODE = 'be';

    const AMHARIC_LANGUAGE_CODE = 'am';

    const JAPANESE_LANGUAGE_CODE = 'ja';

    const CHINESE_LANGUAGE_CODE = 'zh';

    const DUTCH_LANGUAGE_CODE = 'nl';

    const ITALIAN_LANGUAGE_CODE = 'it';

    const MACEDONIAN_LANGUAGE_CODE = 'mk';

    const PORTUGUESE_LANGUAGE_CODE = 'pt';

    const GREEKLISH_LANGUAGE_CODE = 'el__greeklish';

    const GREEK_LANGUAGE_CODE = 'el';

    const HINDI_LANGUAGE_CODE = 'hi';

    const SWEDISH_LANGUAGE_CODE = 'sv';

    const TURKISH_LANGUAGE_CODE = 'tr';

    const BULGARIAN_LANGUAGE_CODE = 'bg';

    const HUNGARIAN_LANGUAGE_CODE = 'hu';

    const MYANMAR_LANGUAGE_CODE = 'my';

    const CROATIAN_LANGUAGE_CODE = 'hr';

    const FINNISH_LANGUAGE_CODE = 'fi';

    const GEORGIAN_LANGUAGE_CODE = 'ka';

    const RUSSIAN_LANGUAGE_CODE = 'ru';

    const RUSSIAN_PASSPORT_2013_LANGUAGE_CODE = 'ru__passport_2013';

    const RUSSIAN_GOST_2000_B_LANGUAGE_CODE = 'ru__gost_2000_b';

    const UKRAINIAN_LANGUAGE_CODE = 'uk';

    const KAZAKH_LANGUAGE_CODE = 'kk';

    const CZECH_LANGUAGE_CODE = 'cs';

    const DANISH_LANGUAGE_CODE = 'da';

    const POLISH_LANGUAGE_CODE = 'pl';

    const ROMANIAN_LANGUAGE_CODE = 'ro';

    const ESPERANTO_LANGUAGE_CODE = 'eo';

    const ESTONIAN_LANGUAGE_CODE = 'et';

    const LATVIAN_LANGUAGE_CODE = 'lv';

    const LITHUANIAN_LANGUAGE_CODE = 'lt';

    const NORWEGIAN_LANGUAGE_CODE = 'no';

    const VIETNAMESE_LANGUAGE_CODE = 'vi';

    const ARABIC_LANGUAGE_CODE = 'ar';

    const PERSIAN_LANGUAGE_CODE = 'fa';

    const SERBIAN_LANGUAGE_CODE = 'sr';

    const SERBIAN_CYRILLIC_LANGUAGE_CODE = 'sr__cyr';

    const SERBIAN_LATIN_LANGUAGE_CODE = 'sr__lat';

    const AZERBAIJANI_LANGUAGE_CODE = 'az';

    const SLOVAK_LANGUAGE_CODE = 'sk';

    const FRENCH_LANGUAGE_CODE = 'fr';

    const FRENCH_AUSTRIAN_LANGUAGE_CODE = 'fr_at';

    const FRENCH_SWITZERLAND_LANGUAGE_CODE = 'fr_ch';

    const GERMAN_LANGUAGE_CODE = 'de';

    const GERMAN_AUSTRIAN_LANGUAGE_CODE = 'de_at';

    const GERMAN_SWITZERLAND_LANGUAGE_CODE = 'de_ch';

    const ENGLISH_LANGUAGE_CODE = 'en';

    const EXTRA_LATIN_CHARS_LANGUAGE_CODE = 'latin';

    const EXTRA_WHITESPACE_CHARS_LANGUAGE_CODE = ' ';

    const EXTRA_MSWORD_CHARS_LANGUAGE_CODE = 'msword';

    /**
     * @var array<string, array<string, string>>|null
     */
    private static $ASCII_MAPS;

    /**
     * @var array<string, array<string, string>>|null
     */
    private static $ASCII_MAPS_AND_EXTRAS;

    /**
     * @var array<string, array<string, string>>|null
     */
    private static $ASCII_EXTRAS;

    /**
     * @var array<string, int>|null
     */
    private static $ORD;

    /**
     * @var array<string, int>|null
     */
    private static $LANGUAGE_MAX_KEY;

    /**
     * url: https://en.wikipedia.org/wiki/Wikipedia:ASCII#ASCII_printable_characters
     *
     * @var string
     */
    private static $REGEX_ASCII = "[^\x09\x10\x13\x0A\x0D\x20-\x7E]";

    /**
     * bidirectional text chars
     *
     * url: https://www.w3.org/International/questions/qa-bidi-unicode-controls
     *
     * @var array<int, string>
     */
    private static $BIDI_UNI_CODE_CONTROLS_TABLE = [
        // LEFT-TO-RIGHT EMBEDDING (use -> dir = "ltr")
        8234 => "\xE2\x80\xAA",
        // RIGHT-TO-LEFT EMBEDDING (use -> dir = "rtl")
        8235 => "\xE2\x80\xAB",
        // POP DIRECTIONAL FORMATTING // (use -> </bdo>)
        8236 => "\xE2\x80\xAC",
        // LEFT-TO-RIGHT OVERRIDE // (use -> <bdo dir = "ltr">)
        8237 => "\xE2\x80\xAD",
        // RIGHT-TO-LEFT OVERRIDE // (use -> <bdo dir = "rtl">)
        8238 => "\xE2\x80\xAE",
        // LEFT-TO-RIGHT ISOLATE // (use -> dir = "ltr")
        8294 => "\xE2\x81\xA6",
        // RIGHT-TO-LEFT ISOLATE // (use -> dir = "rtl")
        8295 => "\xE2\x81\xA7",
        // FIRST STRONG ISOLATE // (use -> dir = "auto")
        8296 => "\xE2\x81\xA8",
        // POP DIRECTIONAL ISOLATE
        8297 => "\xE2\x81\xA9",
    ];

    /**
     * Get all languages from the constants "ASCII::.*LANGUAGE_CODE".
     *
     * @return array<string, string>
     *                                 <p>An associative array where the key is the language code in lowercase
     *                                 and the value is the corresponding language string.</p>
     */
    public static function getAllLanguages(): array
    {
        // init
        static $LANGUAGES = [];

        if ($LANGUAGES !== []) {
            return $LANGUAGES;
        }

        foreach ((new \ReflectionClass(__CLASS__))->getConstants() as $constant => $lang) {
            if (\strpos($constant, 'EXTRA') !== false) {
                $LANGUAGES[\strtolower($constant)] = $lang;
            } else {
                $LANGUAGES[\strtolower(\str_replace('_LANGUAGE_CODE', '', $constant))] = $lang;
            }
        }

        return $LANGUAGES;
    }

    /**
     * Returns an replacement array for ASCII methods.
     *
     * EXAMPLE: <code>
     * $array = ASCII::charsArray();
     * var_dump($array['ru']['б']); // 'b'
     * </code>
     *
     * @param bool $replace_extra_symbols [optional] <p>Add some more replacements e.g. "£" with " pound ".</p>
     *
     * @psalm-pure
     *
     * @return array<string, array<string , string>>
     *                                               <p>An array where the key is the language code, and the value is
     *                                               an associative array mapping original characters to their replacements.</p>
     */
    public static function charsArray(bool $replace_extra_symbols = false): array
    {
        if ($replace_extra_symbols) {
            self::prepareAsciiAndExtrasMaps();

            return self::$ASCII_MAPS_AND_EXTRAS ?? [];
        }

        self::prepareAsciiMaps();

        return self::$ASCII_MAPS ?? [];
    }

    /**
     * Returns an replacement array for ASCII methods with a mix of multiple languages.
     *
     * EXAMPLE: <code>
     * $array = ASCII::charsArrayWithMultiLanguageValues();
     * var_dump($array['b']); // ['β', 'б', 'ဗ', 'ბ', 'ب']
     * </code>
     *
     * @param bool $replace_extra_symbols [optional] <p>Add some more replacements e.g. "£" with " pound ".</p>
     *
     * @psalm-pure
     *
     * @return array<string, list<string>>
     *                                     <p>An array of replacements.</p>
     */
    public static function charsArrayWithMultiLanguageValues(bool $replace_extra_symbols = false): array
    {
        static $CHARS_ARRAY = [];
        $cacheKey = '' . $replace_extra_symbols;

        if (isset($CHARS_ARRAY[$cacheKey])) {
            return $CHARS_ARRAY[$cacheKey];
        }

        // init
        $return = [];
        $language_all_chars = self::charsArrayWithSingleLanguageValues(
            $replace_extra_symbols,
            false
        );

        /* @noinspection AlterInForeachInspection | ok here */
        foreach ($language_all_chars as $key => &$value) {
            $return[$value][] = $key;
        }

        $CHARS_ARRAY[$cacheKey] = $return;

        return $return;
    }

    /**
     * Returns an replacement array for ASCII methods with one language.
     *
     * For example, German will map 'ä' to 'ae', while other languages
     * will simply return e.g. 'a'.
     *
     * EXAMPLE: <code>
     * $array = ASCII::charsArrayWithOneLanguage('ru');
     * $tmpKey = \array_search('yo', $array['replace']);
     * echo $array['orig'][$tmpKey]; // 'ё'
     * </code>
     *
     * @param string $language              [optional] <p>Language of the source string e.g.: en, de_at, or de-ch.
     *                                      (default is 'en') | ASCII::*_LANGUAGE_CODE</p>
     * @param bool   $replace_extra_symbols [optional] <p>Add some more replacements e.g. "£" with " pound ".</p>
     * @param bool   $asOrigReplaceArray    [optional] <p>TRUE === return {orig: list<string>, replace: list<string>}
     *                                      array</p>
     *
     * @psalm-pure
     *
     * @return ($asOrigReplaceArray is true ? array{orig: list<string>, replace: list<string>} : array<string, string>)
     *
     * @phpstan-param ASCII::*_LANGUAGE_CODE $language
     */
    public static function charsArrayWithOneLanguage(
        string $language = self::ENGLISH_LANGUAGE_CODE,
        bool $replace_extra_symbols = false,
        bool $asOrigReplaceArray = true
    ): array {
        $language = self::get_language($language);

        // init
        static $CHARS_ARRAY = [];
        $cacheKey = '' . $replace_extra_symbols . '-' . $asOrigReplaceArray;

        // check static cache
        if (isset($CHARS_ARRAY[$cacheKey][$language])) {
            return $CHARS_ARRAY[$cacheKey][$language];
        }

        if ($replace_extra_symbols) {
            self::prepareAsciiAndExtrasMaps();

            if (isset(self::$ASCII_MAPS_AND_EXTRAS[$language])) {
                $tmpArray = self::$ASCII_MAPS_AND_EXTRAS[$language];

                if ($asOrigReplaceArray) {
                    $CHARS_ARRAY[$cacheKey][$language] = [
                        'orig'    => \array_keys($tmpArray),
                        'replace' => \array_values($tmpArray),
                    ];
                } else {
                    $CHARS_ARRAY[$cacheKey][$language] = $tmpArray;
                }
            } else {
                if ($asOrigReplaceArray) {
                    $CHARS_ARRAY[$cacheKey][$language] = [
                        'orig'    => [],
                        'replace' => [],
                    ];
                } else {
                    $CHARS_ARRAY[$cacheKey][$language] = [];
                }
            }
        } else {
            self::prepareAsciiMaps();

            if (isset(self::$ASCII_MAPS[$language])) {
                $tmpArray = self::$ASCII_MAPS[$language];

                if ($asOrigReplaceArray) {
                    $CHARS_ARRAY[$cacheKey][$language] = [
                        'orig'    => \array_keys($tmpArray),
                        'replace' => \array_values($tmpArray),
                    ];
                } else {
                    $CHARS_ARRAY[$cacheKey][$language] = $tmpArray;
                }
            } else {
                if ($asOrigReplaceArray) {
                    $CHARS_ARRAY[$cacheKey][$language] = [
                        'orig'    => [],
                        'replace' => [],
                    ];
                } else {
                    $CHARS_ARRAY[$cacheKey][$language] = [];
                }
            }
        }

        return $CHARS_ARRAY[$cacheKey][$language] ?? ['orig' => [], 'replace' => []];
    }

    /**
     * Returns an replacement array for ASCII methods with multiple languages.
     *
     * EXAMPLE: <code>
     * $array = ASCII::charsArrayWithSingleLanguageValues();
     * $tmpKey = \array_search('hnaik', $array['replace']);
     * echo $array['orig'][$tmpKey]; // '၌'
     * </code>
     *
     * @param bool $replace_extra_symbols [optional] <p>Add some more replacements e.g. "£" with " pound ".</p>
     * @param bool $asOrigReplaceArray    [optional] <p>TRUE === return {orig: list<string>, replace: list<string>}
     *                                    array</p>
     *
     * @psalm-pure
     *
     * @return ($asOrigReplaceArray is true ? array{orig: list<string>, replace: list<string>} : array<string, string>)
     */
    public static function charsArrayWithSingleLanguageValues(
        bool $replace_extra_symbols = false,
        bool $asOrigReplaceArray = true
    ): array {
        // init
        static $CHARS_ARRAY = [];
        $cacheKey = '' . $replace_extra_symbols . '-' . $asOrigReplaceArray;

        if (isset($CHARS_ARRAY[$cacheKey])) {
            return $CHARS_ARRAY[$cacheKey];
        }

        if ($replace_extra_symbols) {
            self::prepareAsciiAndExtrasMaps();

            /* @noinspection AlterInForeachInspection | ok here */
            foreach (self::$ASCII_MAPS_AND_EXTRAS ?? [] as &$map) {
                $CHARS_ARRAY[$cacheKey][] = $map;
            }
        } else {
            self::prepareAsciiMaps();

            /* @noinspection AlterInForeachInspection | ok here */
            foreach (self::$ASCII_MAPS ?? [] as &$map) {
                $CHARS_ARRAY[$cacheKey][] = $map;
            }
        }

        $CHARS_ARRAY[$cacheKey] = \array_merge([], ...$CHARS_ARRAY[$cacheKey]);

        if ($asOrigReplaceArray) {
            $CHARS_ARRAY[$cacheKey] = [
                'orig'    => \array_keys($CHARS_ARRAY[$cacheKey]),
                'replace' => \array_values($CHARS_ARRAY[$cacheKey]),
            ];
        }

        return $CHARS_ARRAY[$cacheKey];
    }

    /**
     * Accepts a string and removes all non-UTF-8 characters from it + extras if needed.
     *
     * @param string $str                         <p>The string to be sanitized.</p>
     * @param bool   $normalize_whitespace        [optional] <p>Set to true, if you need to normalize the
     *                                            whitespace.</p>
     * @param bool   $normalize_msword            [optional] <p>Set to true, if you need to normalize MS Word chars
     *                                            e.g.: "…"
     *                                            => "..."</p>
     * @param bool   $keep_non_breaking_space     [optional] <p>Set to true, to keep non-breaking-spaces, in
     *                                            combination with
     *                                            $normalize_whitespace</p>
     * @param bool   $remove_invisible_characters [optional] <p>Set to false, if you not want to remove invisible
     *                                            characters e.g.: "\0"</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A clean UTF-8 string.</p>
     */
    public static function clean(
        string $str,
        bool $normalize_whitespace = true,
        bool $keep_non_breaking_space = false,
        bool $normalize_msword = true,
        bool $remove_invisible_characters = true
    ): string {
        // http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string
        // caused connection reset problem on larger strings

        $regex = '/
          (
            (?: [\x00-\x7F]               # single-byte sequences   0xxxxxxx
            |   [\xC0-\xDF][\x80-\xBF]    # double-byte sequences   110xxxxx 10xxxxxx
            |   [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences   1110xxxx 10xxxxxx * 2
            |   [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
            ){1,100}                      # ...one or more times
          )
        | ( [\x80-\xBF] )                 # invalid byte in range 10000000 - 10111111
        | ( [\xC0-\xFF] )                 # invalid byte in range 11000000 - 11111111
        /x';
        $str = (string) \preg_replace($regex, '$1', $str);

        if ($normalize_whitespace) {
            $str = self::normalize_whitespace($str, $keep_non_breaking_space);
        }

        if ($normalize_msword) {
            $str = self::normalize_msword($str);
        }

        if ($remove_invisible_characters) {
            $str = self::remove_invisible_characters($str);
        }

        return $str;
    }

    /**
     * Checks if a string is 7 bit ASCII.
     *
     * EXAMPLE: <code>
     * ASCII::is_ascii('白'); // false
     * </code>
     *
     * @param string $str <p>The string to check.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>
     *              <strong>true</strong> if it is ASCII<br>
     *              <strong>false</strong> otherwise
     *              </p>
     */
    public static function is_ascii(string $str): bool
    {
        if ($str === '') {
            return true;
        }

        return !\preg_match('/' . self::$REGEX_ASCII . '/', $str);
    }

    /**
     * Returns a string with smart quotes, ellipsis characters, and dashes from
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
     * equivalents.
     *
     * EXAMPLE: <code>
     * ASCII::normalize_msword('„Abcdef…”'); // '"Abcdef..."'
     * </code>
     *
     * @param string $str <p>The string to be normalized.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with normalized characters for commonly used chars in Word documents.</p>
     */
    public static function normalize_msword(string $str): string
    {
        if ($str === '') {
            return '';
        }

        static $MSWORD_CACHE = ['orig' => [], 'replace' => []];

        if (empty($MSWORD_CACHE['orig'])) {
            self::prepareAsciiMaps();

            $map = self::$ASCII_MAPS[self::EXTRA_MSWORD_CHARS_LANGUAGE_CODE] ?? [];

            $MSWORD_CACHE = [
                'orig'    => \array_keys($map),
                'replace' => \array_values($map),
            ];
        }

        return \str_replace($MSWORD_CACHE['orig'], $MSWORD_CACHE['replace'], $str);
    }

    /**
     * Normalize the whitespace.
     *
     * EXAMPLE: <code>
     * ASCII::normalize_whitespace("abc-\xc2\xa0-öäü-\xe2\x80\xaf-\xE2\x80\xAC", true); // "abc-\xc2\xa0-öäü- -"
     * </code>
     *
     * @param string $str                          <p>The string to be normalized.</p>
     * @param bool   $keepNonBreakingSpace         [optional] <p>Set to true, to keep non-breaking-spaces.</p>
     * @param bool   $keepBidiUnicodeControls      [optional] <p>Set to true, to keep non-printable (for the web)
     *                                             bidirectional text chars.</p>
     * @param bool   $normalize_control_characters [optional] <p>Set to true, to convert e.g. LINE-, PARAGRAPH-SEPARATOR with "\n" and LINE TABULATION with "\t".</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with normalized whitespace.</p>
     */
    public static function normalize_whitespace(
        string $str,
        bool $keepNonBreakingSpace = false,
        bool $keepBidiUnicodeControls = false,
        bool $normalize_control_characters = false
    ): string {
        if ($str === '') {
            return '';
        }

        static $WHITESPACE_CACHE = [];
        $cacheKey = (int) $keepNonBreakingSpace;

        if ($normalize_control_characters) {
            $str = \str_replace(
                [
                    "\x0d\x0c",     // 'END OF LINE'
                    "\xe2\x80\xa8", // 'LINE SEPARATOR'
                    "\xe2\x80\xa9", // 'PARAGRAPH SEPARATOR'
                    "\x0c",         // 'FORM FEED' // "\f"
                    "\x0b",         // 'VERTICAL TAB' // "\v"
                ],
                [
                    "\n",
                    "\n",
                    "\n",
                    "\n",
                    "\t",
                ],
                $str
            );
        }

        if (!isset($WHITESPACE_CACHE[$cacheKey])) {
            self::prepareAsciiMaps();

            $WHITESPACE_CACHE[$cacheKey] = self::$ASCII_MAPS[self::EXTRA_WHITESPACE_CHARS_LANGUAGE_CODE] ?? [];

            if ($keepNonBreakingSpace) {
                unset($WHITESPACE_CACHE[$cacheKey]["\xc2\xa0"]);
            }

            $WHITESPACE_CACHE[$cacheKey] = array_keys($WHITESPACE_CACHE[$cacheKey]);
        }

        if (!$keepBidiUnicodeControls) {
            static $BIDI_UNICODE_CONTROLS_CACHE = null;

            if ($BIDI_UNICODE_CONTROLS_CACHE === null) {
                $BIDI_UNICODE_CONTROLS_CACHE = self::$BIDI_UNI_CODE_CONTROLS_TABLE;
            }

            $str = \str_replace($BIDI_UNICODE_CONTROLS_CACHE, '', $str);
        }

        return \str_replace($WHITESPACE_CACHE[$cacheKey], ' ', $str);
    }

    /**
     * Remove invisible characters from a string.
     *
     * This prevents malicious code injection through null bytes or other control characters.
     *
     * copy&past from https://github.com/bcit-ci/CodeIgniter/blob/develop/system/core/Common.php
     *
     * @param string $str
     * @param bool   $url_encoded
     * @param string $replacement
     * @param bool   $keep_basic_control_characters
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function remove_invisible_characters(
        string $str,
        bool $url_encoded = false,
        string $replacement = '',
        bool $keep_basic_control_characters = true
    ): string {
        // init
        $non_displayables = [];

        // every control character except:
        // - newline (dec 10),
        // - carriage return (dec 13),
        // - horizontal tab (dec 09)
        if ($url_encoded) {
            $non_displayables[] = '/%0[0-8bcefBCEF]/'; // url encoded 00-08, 11, 12, 14, 15
            $non_displayables[] = '/%1[0-9a-fA-F]/'; // url encoded 16-31
        }

        if ($keep_basic_control_characters) {
            $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
        } else {
            $str = self::normalize_whitespace($str, false, false, true);
            $non_displayables[] = '/[^\P{C}\s]/u';
        }

        do {
            $str = (string) \preg_replace($non_displayables, $replacement, $str, -1, $count);
        } while ($count !== 0);

        return $str;
    }

    /**
     * WARNING: This method will return broken characters and is only for special cases.
     *
     * Convert two UTF-8 encoded strings to a single-byte strings suitable for
     * functions that need the same string length after the conversion.
     *
     * The function simply uses (and updates) a tailored dynamic encoding
     * (in/out map parameter) where non-ascii characters are remapped to
     * the range [128-255] in order of appearance.
     *
     * @return array{0: string, 1: string}
     */
    public static function to_ascii_remap(string $str1, string $str2): array
    {
        $charMap = [];
        $str1 = self::to_ascii_remap_intern($str1, $charMap);
        $str2 = self::to_ascii_remap_intern($str2, $charMap);

        return [$str1, $str2];
    }

    /**
     * Returns an ASCII version of the string. A set of non-ASCII characters are
     * replaced with their closest ASCII counterparts, and the rest are removed
     * by default. The language or locale of the source string can be supplied
     * for language-specific transliteration in any of the following formats:
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
     * to "aeoeue" rather than "aou" as in other languages.
     *
     * EXAMPLE: <code>
     * ASCII::to_ascii('�Düsseldorf�', 'en'); // Dusseldorf
     * </code>
     *
     * @param string    $str                       <p>The input string.</p>
     * @param string    $language                  [optional] <p>Language of the source string.
     *                                             (default is 'en') | ASCII::*_LANGUAGE_CODE</p>
     * @param bool      $remove_unsupported_chars  [optional] <p>Whether to remove the
     *                                             unsupported characters.</p>
     * @param bool      $replace_extra_symbols     [optional]  <p>Add some more replacements e.g. "£" with " pound
     *                                             ".</p>
     * @param bool      $use_transliterate         [optional]  <p>Use ASCII::to_transliterate() for unknown chars.</p>
     * @param bool      $replace_single_chars_only [optional]  <p>Single char replacement is better for the
     *                                             performance, but some languages need to replace more than one char
     *                                             at the same time. If FALSE === auto-setting, depended on the
     *                                             language</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string that contains only ASCII characters.</p>
     *
     * @phpstan-param ASCII::*_LANGUAGE_CODE $language
     */
    public static function to_ascii(
        string $str,
        string $language = self::ENGLISH_LANGUAGE_CODE,
        bool $remove_unsupported_chars = true,
        bool $replace_extra_symbols = false,
        bool $use_transliterate = false,
        bool $replace_single_chars_only = false
    ): string {
        if ($str === '') {
            return '';
        }

        /** @phpstan-var ASCII::*_LANGUAGE_CODE $language - hack for phpstan */
        $language = self::get_language($language);

        static $EXTRA_SYMBOLS_CACHE = null;

        static $REPLACE_HELPER_CACHE = [];
        $cacheKey = $language . '-' . $replace_extra_symbols;

        if (!isset($REPLACE_HELPER_CACHE[$cacheKey])) {
            $langAll = self::charsArrayWithSingleLanguageValues($replace_extra_symbols, false);

            $langSpecific = self::charsArrayWithOneLanguage($language, $replace_extra_symbols, false);

            if ($langSpecific === []) {
                $REPLACE_HELPER_CACHE[$cacheKey] = $langAll;
            } else {
                $REPLACE_HELPER_CACHE[$cacheKey] = \array_merge([], $langAll, $langSpecific);
            }
        }

        if (
            $replace_extra_symbols
            &&
            $EXTRA_SYMBOLS_CACHE === null
        ) {
            $EXTRA_SYMBOLS_CACHE = [];
            foreach (self::$ASCII_EXTRAS ?? [] as $extrasDataTmp) {
                foreach ($extrasDataTmp as $extrasDataKeyTmp => $extrasDataValueTmp) {
                    $EXTRA_SYMBOLS_CACHE[$extrasDataKeyTmp] = $extrasDataKeyTmp;
                }
            }
            $EXTRA_SYMBOLS_CACHE = \implode('', $EXTRA_SYMBOLS_CACHE);
        }

        $charDone = [];
        if (\preg_match_all('/' . self::$REGEX_ASCII . ($replace_extra_symbols ? '|[' . $EXTRA_SYMBOLS_CACHE . ']' : '') . '/u', $str, $matches)) {
            if (!$replace_single_chars_only) {
                if (self::$LANGUAGE_MAX_KEY === null) {
                    self::$LANGUAGE_MAX_KEY = self::getData('ascii_language_max_key');
                }

                $maxKeyLength = self::$LANGUAGE_MAX_KEY[$language] ?? 0;

                if ($maxKeyLength >= 5) {
                    foreach ($matches[0] as $keyTmp => $char) {
                        if (isset($matches[0][$keyTmp + 4])) {
                            $fiveChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2] . $matches[0][$keyTmp + 3] . $matches[0][$keyTmp + 4];
                        } else {
                            $fiveChars = null;
                        }
                        if (
                            $fiveChars
                            &&
                            !isset($charDone[$fiveChars])
                            &&
                            isset($REPLACE_HELPER_CACHE[$cacheKey][$fiveChars])
                            &&
                            \strpos($str, $fiveChars) !== false
                        ) {
                            // DEBUG
                            //\var_dump($str, $fiveChars, $REPLACE_HELPER_CACHE[$cacheKey][$fiveChars]);

                            $charDone[$fiveChars] = true;
                            $str = \str_replace($fiveChars, $REPLACE_HELPER_CACHE[$cacheKey][$fiveChars], $str);

                            // DEBUG
                            //\var_dump($str, "\n");
                        }
                    }
                }

                if ($maxKeyLength >= 4) {
                    foreach ($matches[0] as $keyTmp => $char) {
                        if (isset($matches[0][$keyTmp + 3])) {
                            $fourChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2] . $matches[0][$keyTmp + 3];
                        } else {
                            $fourChars = null;
                        }
                        if (
                            $fourChars
                            &&
                            !isset($charDone[$fourChars])
                            &&
                            isset($REPLACE_HELPER_CACHE[$cacheKey][$fourChars])
                            &&
                            \strpos($str, $fourChars) !== false
                        ) {
                            // DEBUG
                            //\var_dump($str, $fourChars, $REPLACE_HELPER_CACHE[$cacheKey][$fourChars]);

                            $charDone[$fourChars] = true;
                            $str = \str_replace($fourChars, $REPLACE_HELPER_CACHE[$cacheKey][$fourChars], $str);

                            // DEBUG
                            //\var_dump($str, "\n");
                        }
                    }
                }

                foreach ($matches[0] as $keyTmp => $char) {
                    if (isset($matches[0][$keyTmp + 2])) {
                        $threeChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2];
                    } else {
                        $threeChars = null;
                    }
                    if (
                        $threeChars
                        &&
                        !isset($charDone[$threeChars])
                        &&
                        isset($REPLACE_HELPER_CACHE[$cacheKey][$threeChars])
                        &&
                        \strpos($str, $threeChars) !== false
                    ) {
                        // DEBUG
                        //\var_dump($str, $threeChars, $REPLACE_HELPER_CACHE[$cacheKey][$threeChars]);

                        $charDone[$threeChars] = true;
                        $str = \str_replace($threeChars, $REPLACE_HELPER_CACHE[$cacheKey][$threeChars], $str);

                        // DEBUG
                        //\var_dump($str, "\n");
                    }
                }

                foreach ($matches[0] as $keyTmp => $char) {
                    if (isset($matches[0][$keyTmp + 1])) {
                        $twoChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1];
                    } else {
                        $twoChars = null;
                    }
                    if (
                        $twoChars
                        &&
                        !isset($charDone[$twoChars])
                        &&
                        isset($REPLACE_HELPER_CACHE[$cacheKey][$twoChars])
                        &&
                        \strpos($str, $twoChars) !== false
                    ) {
                        // DEBUG
                        //\var_dump($str, $twoChars, $REPLACE_HELPER_CACHE[$cacheKey][$twoChars]);

                        $charDone[$twoChars] = true;
                        $str = \str_replace($twoChars, $REPLACE_HELPER_CACHE[$cacheKey][$twoChars], $str);

                        // DEBUG
                        //\var_dump($str, "\n");
                    }
                }
            }

            foreach ($matches[0] as $char) {
                if (
                    !isset($charDone[$char])
                    &&
                    isset($REPLACE_HELPER_CACHE[$cacheKey][$char])
                    &&
                    \strpos($str, $char) !== false
                ) {
                    // DEBUG
                    //\var_dump($str, $char, $REPLACE_HELPER_CACHE[$cacheKey][$char]);

                    $charDone[$char] = true;
                    $str = \str_replace($char, $REPLACE_HELPER_CACHE[$cacheKey][$char], $str);

                    // DEBUG
                    //\var_dump($str, "\n");
                }
            }
        }

        if (!isset(self::$ASCII_MAPS[$language])) {
            $use_transliterate = true;
        }

        if ($use_transliterate) {
            $str = self::to_transliterate($str, null, false);
        }

        if ($remove_unsupported_chars) {
            $str = (string) \str_replace(["\n\r", "\n", "\r", "\t"], ' ', $str);
            $str = (string) \preg_replace('/' . self::$REGEX_ASCII . '/', '', $str);
        }

        return $str;
    }

    /**
     * Convert given string to safe filename (and keep string case).
     *
     * EXAMPLE: <code>
     * ASCII::to_filename('שדגשדג.png', true)); // 'shdgshdg.png'
     * </code>
     *
     * @param string $str               <p>The string input.</p>
     * @param bool   $use_transliterate <p>ASCII::to_transliterate() is used by default - unsafe characters are
     *                                  simply replaced with hyphen otherwise.</p>
     * @param string $fallback_char     <p>The fallback character. - "-" is the default</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string that contains only safe characters for a filename.</p>
     */
    public static function to_filename(
        string $str,
        bool $use_transliterate = true,
        string $fallback_char = '-'
    ): string {
        if ($use_transliterate) {
            $str = self::to_transliterate($str, $fallback_char);
        }

        $fallback_char_escaped = \preg_quote($fallback_char, '/');

        $str = (string) \preg_replace(
            [
                '/[^' . $fallback_char_escaped . '.\\-a-zA-Z\d\\s]/', // 1) remove un-needed chars
                '/\s+/u',                                             // 2) convert spaces to $fallback_char
                '/[' . $fallback_char_escaped . ']+/u',               // 3) remove double $fallback_char's
            ],
            [
                '',
                $fallback_char,
                $fallback_char,
            ],
            $str
        );

        return \trim($str, $fallback_char);
    }

    /**
     * Converts a string into a URL-friendly slug.
     *
     * - This includes replacing non-ASCII characters with their closest ASCII equivalents, removing remaining
     *   non-ASCII and non-alphanumeric characters, and replacing whitespace with $separator.
     * - The separator defaults to a single dash, and the string is also converted to lowercase.
     * - The language of the source string can also be supplied for language-specific transliteration.
     *
     * @param string                $str                   <p>The string input.</p>
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
     * @param string                $language              [optional] <p>Language of the source string.
     *                                                     (default is 'en') | ASCII::*_LANGUAGE_CODE</p>
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
     * @param bool                  $replace_extra_symbols [optional] <p>Add some more replacements e.g. "£" with "
     *                                                     pound ".</p>
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
     * @param bool                  $use_transliterate     [optional] <p>Use ASCII::to_transliterate() for unknown
     *                                                     chars.</p>
     * @psalm-pure
     *
     * @return string
     *                <p>The URL-friendly slug.</p>
     *
     * @phpstan-param ASCII::*_LANGUAGE_CODE $language
     */
    public static function to_slugify(
        string $str,
        string $separator = '-',
        string $language = self::ENGLISH_LANGUAGE_CODE,
        array $replacements = [],
        bool $replace_extra_symbols = false,
        bool $use_str_to_lower = true,
        bool $use_transliterate = false
    ): string {
        if ($str === '') {
            return '';
        }

        foreach ($replacements as $from => $to) {
            $str = \str_replace($from, $to, $str);
        }

        $str = self::to_ascii(
            $str,
            $language,
            false,
            $replace_extra_symbols,
            $use_transliterate
        );

        $str = \str_replace('@', $separator, $str);

        $str = (string) \preg_replace(
            '/[^a-zA-Z\\d\\s\\-_' . \preg_quote($separator, '/') . ']/',
            '',
            $str
        );

        if ($use_str_to_lower) {
            $str = \strtolower($str);
        }

        $str = (string) \preg_replace('/^[\'\\s]+|[\'\\s]+$/', '', $str);
        $str = (string) \preg_replace('/\\B([A-Z])/', '-\1', $str);
        $str = (string) \preg_replace('/[\\-_\\s]+/', $separator, $str);

        $l = \strlen($separator);
        if ($l && \strpos($str, $separator) === 0) {
            $str = (string) \substr($str, $l);
        }

        if (\substr($str, -$l) === $separator) {
            $str = (string) \substr($str, 0, \strlen($str) - $l);
        }

        return $str;
    }

    /**
     * Returns an ASCII version of the string. A set of non-ASCII characters are
     * replaced with their closest ASCII counterparts, and the rest are removed
     * unless instructed otherwise.
     *
     * EXAMPLE: <code>
     * ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii'
     * </code>
     *
     * @param string      $str     <p>The input string.</p>
     * @param string|null $unknown [optional] <p>Character use if character unknown. (default is '?')
     *                             But you can also use NULL to keep the unknown chars.</p>
     * @param bool        $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A String that contains only ASCII characters.</p>
     */
    public static function to_transliterate(
        string $str,
        $unknown = '?',
        bool $strict = false
    ): string {
        static $UTF8_TO_TRANSLIT = null;

        static $TRANSLITERATOR = null;

        static $SUPPORT_INTL = null;

        if ($str === '') {
            return '';
        }

        if ($SUPPORT_INTL === null) {
            $SUPPORT_INTL = \extension_loaded('intl');
        }

        // check if we only have ASCII, first (better performance)
        $str_tmp = $str;
        if (self::is_ascii($str)) {
            return $str;
        }

        $str = self::clean($str);

        // check again if we only have ASCII, now ...
        if (
            $str_tmp !== $str
            &&
            self::is_ascii($str)
        ) {
            return $str;
        }

        if (
            $strict
            &&
            $SUPPORT_INTL === true
        ) {
            if (!isset($TRANSLITERATOR)) {
                // INFO: see "*-Latin" rules via "transliterator_list_ids()"
                $TRANSLITERATOR = \transliterator_create('NFKC; [:Nonspacing Mark:] Remove; NFKC; Any-Latin; Latin-ASCII;');
            }

            // INFO: https://unicode.org/cldr/utility/character.jsp
            $str_tmp = \transliterator_transliterate($TRANSLITERATOR, $str);

            if ($str_tmp !== false) {
                // check again if we only have ASCII, now ...
                if (
                    $str_tmp !== $str
                    &&
                    self::is_ascii($str_tmp)
                ) {
                    return $str_tmp;
                }

                $str = $str_tmp;
            }
        }

        if (self::$ORD === null) {
            self::$ORD = self::getData('ascii_ord');
        }

        \preg_match_all('/.|[^\x00]$/us', $str, $array_tmp);
        $chars = $array_tmp[0];
        $ord = null;
        $str_tmp = '';
        foreach ($chars as &$c) {
            $ordC0 = self::$ORD[$c[0]];

            if ($ordC0 >= 0 && $ordC0 <= 127) {
                $str_tmp .= $c;

                continue;
            }

            $ordC1 = self::$ORD[$c[1]];

            // ASCII - next please
            if ($ordC0 >= 192 && $ordC0 <= 223) {
                $ord = ($ordC0 - 192) * 64 + ($ordC1 - 128);
            }

            if ($ordC0 >= 224) {
                $ordC2 = self::$ORD[$c[2]];

                if ($ordC0 <= 239) {
                    $ord = ($ordC0 - 224) * 4096 + ($ordC1 - 128) * 64 + ($ordC2 - 128);
                }

                if ($ordC0 >= 240) {
                    $ordC3 = self::$ORD[$c[3]];

                    if ($ordC0 <= 247) {
                        $ord = ($ordC0 - 240) * 262144 + ($ordC1 - 128) * 4096 + ($ordC2 - 128) * 64 + ($ordC3 - 128);
                    }

                    // We only process valid UTF-8 chars (<= 4 byte), so we don't need this code here ...
                    /*
                    if ($ordC0 >= 248) {
                        $ordC4 = self::$ORD[$c[4]];

                        if ($ordC0 <= 251) {
                            $ord = ($ordC0 - 248) * 16777216 + ($ordC1 - 128) * 262144 + ($ordC2 - 128) * 4096 + ($ordC3 - 128) * 64 + ($ordC4 - 128);
                        }

                        if ($ordC0 >= 252) {
                            $ordC5 = self::$ORD[$c[5]];

                            if ($ordC0 <= 253) {
                                $ord = ($ordC0 - 252) * 1073741824 + ($ordC1 - 128) * 16777216 + ($ordC2 - 128) * 262144 + ($ordC3 - 128) * 4096 + ($ordC4 - 128) * 64 + ($ordC5 - 128);
                            }
                        }
                    }
                     */
                }
            }

            if (
                $ordC0 === 254
                ||
                $ordC0 === 255
                ||
                $ord === null
            ) {
                $str_tmp .= $unknown ?? $c;

                continue;
            }

            $bank = $ord >> 8;
            if (!isset($UTF8_TO_TRANSLIT[$bank])) {
                $UTF8_TO_TRANSLIT[$bank] = self::getDataIfExists(\sprintf('x%03x', $bank));
            }

            $new_char = $ord & 255;

            if (isset($UTF8_TO_TRANSLIT[$bank][$new_char])) {
                // keep for debugging
                /*
                echo "file: " . sprintf('x%02x', $bank) . "\n";
                echo "char: " . $c . "\n";
                echo "ord: " . $ord . "\n";
                echo "new_char: " . $new_char . "\n";
                echo "new_char: " . mb_chr($new_char) . "\n";
                echo "ascii: " . $UTF8_TO_TRANSLIT[$bank][$new_char] . "\n";
                echo "bank:" . $bank . "\n\n";
                 */

                $new_char = $UTF8_TO_TRANSLIT[$bank][$new_char];

                /* @noinspection PhpStatementHasEmptyBodyInspection */
                if ($unknown === null && $new_char === '') {
                    // nothing
                } elseif (
                    $new_char === '[?]'
                    ||
                    $new_char === '[?] '
                ) {
                    $c = $unknown ?? $c;
                } else {
                    $c = $new_char;
                }
            } else {
                // keep for debugging missing chars
                /*
                echo "file: " . sprintf('x%02x', $bank) . "\n";
                echo "char: " . $c . "\n";
                echo "ord: " . $ord . "\n";
                echo "new_char: " . $new_char . "\n";
                echo "new_char: " . mb_chr($new_char) . "\n";
                echo "bank:" . $bank . "\n\n";
                 */

                $c = $unknown ?? $c;
            }

            $str_tmp .= $c;
        }

        return $str_tmp;
    }

    /**
     * WARNING: This method will return broken characters and is only for special cases.
     *
     * Convert a UTF-8 encoded string to a single-byte string suitable for
     * functions that need the same string length after the conversion.
     *
     * The function simply uses (and updates) a tailored dynamic encoding
     * (in/out map parameter) where non-ascii characters are remapped to
     * the range [128-255] in order of appearance.
     *
     * Thus, it supports up to 128 different multibyte code points max over
     * the whole set of strings sharing this encoding.
     *
     * Source: https://github.com/KEINOS/mb_levenshtein
     *
     * @param string $str <p>UTF-8 string to be converted to extended ASCII.</p>
     * @param array  $map <p>Internal-Map of code points to ASCII characters.</p>
     *
     * @return string
     *                <p>Mapped broken string.</p>
     *
     * @phpstan-param array<string, string> $map
     */
    private static function to_ascii_remap_intern(string $str, array &$map): string
    {
        // find all utf-8 characters
        $matches = [];
        if (!\preg_match_all('/[\xC0-\xF7][\x80-\xBF]+/', $str, $matches)) {
            return $str; // plain ascii string
        }

        // update the encoding map with the characters not already met
        $mapCount = \count($map);
        foreach ($matches[0] as $mbc) {
            if (!isset($map[$mbc])) {
                $map[$mbc] = \chr(128 + $mapCount);
                ++$mapCount;
            }
        }

        // finally, remap non-ascii characters
        return \strtr($str, $map);
    }

    /**
     * Get the language from a string.
     *
     * e.g.: de_at -> de_at
     *       de_DE -> de
     *       DE_DE -> de
     *       de-de -> de
     *
     * @return string
     */
    private static function get_language(string $language)
    {
        if ($language === '') {
            return '';
        }

        if (
            \strpos($language, '_') === false
            &&
            \strpos($language, '-') === false
        ) {
            return \strtolower($language);
        }

        $language = \str_replace('-', '_', \strtolower($language));

        $regex = '/(?<first>[a-z]+)_\g{first}/';

        return (string) \preg_replace($regex, '$1', $language);
    }

    /**
     * Get data from "/data/*.php".
     *
     * @return array<array-key,mixed>
     */
    private static function getData(string $file)
    {
        return include __DIR__ . '/data/' . $file . '.php';
    }

    /**
     * Get data from "/data/*.php".
     *
     * @return array<array-key,mixed>
     */
    private static function getDataIfExists(string $file): array
    {
        $file = __DIR__ . '/data/' . $file . '.php';
        if (\is_file($file)) {
            return include $file;
        }

        return [];
    }

    /**
     * @return void
     */
    private static function prepareAsciiAndExtrasMaps()
    {
        if (self::$ASCII_MAPS_AND_EXTRAS === null) {
            self::prepareAsciiMaps();
            self::prepareAsciiExtras();

            self::$ASCII_MAPS_AND_EXTRAS = \array_merge_recursive(
                self::$ASCII_MAPS ?? [],
                self::$ASCII_EXTRAS ?? []
            );
        }
    }

    /**
     * @return void
     */
    private static function prepareAsciiMaps()
    {
        if (self::$ASCII_MAPS === null) {
            self::$ASCII_MAPS = self::getData('ascii_by_languages');
        }
    }

    /**
     * @return void
     */
    private static function prepareAsciiExtras()
    {
        if (self::$ASCII_EXTRAS === null) {
            self::$ASCII_EXTRAS = self::getData('ascii_extras_by_languages');
        }
    }
}
<?php

// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes

return [
    // Dutch (Flemish)
    'nl' => [
        'Á' => 'A',
        'á' => 'a',
        'Ä' => 'A',
        'ä' => 'a',
        'À' => 'A',
        'à' => 'a',
        'Â' => 'A',
        'â' => 'a',
        'É' => 'E',
        'é' => 'e',
        'Ë' => 'E',
        'ë' => 'e',
        'È' => 'E',
        'è' => 'e',
        'Ê' => 'E',
        'ê' => 'e',
        'Í' => 'I',
        'í' => 'i',
        'Ï' => 'I',
        'ï' => 'i',
        'Ì' => 'I',
        'ì' => 'i',
        'Î' => 'I',
        'î' => 'i',
        'Ó' => 'O',
        'ó' => 'o',
        'Ö' => 'O',
        'ö' => 'o',
        'Ò' => 'O',
        'ò' => 'o',
        'Ô' => 'O',
        'ô' => 'o',
        'Ú' => 'U',
        'ú' => 'u',
        'Ü' => 'U',
        'ü' => 'u',
        'Ù' => 'U',
        'ù' => 'u',
        'Û' => 'U',
        'û' => 'u',
        'Ý' => 'Y',
        'ý' => 'y',
        'Ÿ' => 'Y',
    ],
    // Italian
    'it' => [
        'à' => 'a',
        'À' => 'A',
        'é' => 'e',
        'É' => 'E',
        'è' => 'e',
        'È' => 'E',
        'ì' => 'i',
        'Ì' => 'I',
        'Ò' => 'O',
        'ò' => 'o',
        'ù' => 'u',
        'Ù' => 'U',
    ],
    // Macedonian
    'mk' => [
        'А' => 'A',
        'Б' => 'B',
        'В' => 'V',
        'Г' => 'G',
        'Д' => 'D',
        'Ѓ' => 'Gj',
        'Е' => 'E',
        'Ж' => 'Zh',
        'З' => 'Z',
        'Ѕ' => 'Dz',
        'И' => 'I',
        'Ј' => 'J',
        'К' => 'K',
        'Л' => 'L',
        'Љ' => 'Lj',
        'М' => 'M',
        'Н' => 'N',
        'Њ' => 'Nj',
        'О' => 'O',
        'П' => 'P',
        'Р' => 'R',
        'С' => 'S',
        'Т' => 'T',
        'Ќ' => 'Kj',
        'У' => 'U',
        'Ф' => 'F',
        'Х' => 'H',
        'Ц' => 'C',
        'Ч' => 'Ch',
        'Џ' => 'Dj',
        'Ш' => 'Sh',
        'а' => 'a',
        'б' => 'b',
        'в' => 'v',
        'г' => 'g',
        'д' => 'd',
        'ѓ' => 'gj',
        'е' => 'e',
        'ж' => 'zh',
        'з' => 'z',
        'ѕ' => 'dz',
        'и' => 'i',
        'ј' => 'j',
        'к' => 'k',
        'л' => 'l',
        'љ' => 'lj',
        'м' => 'm',
        'н' => 'n',
        'њ' => 'nj',
        'о' => 'o',
        'п' => 'p',
        'р' => 'r',
        'с' => 's',
        'т' => 't',
        'ќ' => 'kj',
        'у' => 'u',
        'ф' => 'f',
        'х' => 'h',
        'ц' => 'c',
        'ч' => 'ch',
        'џ' => 'dj',
        'ш' => 'sh',
    ],
    // Portuguese (Brazil)
    'pt' => [
        'æ' => 'ae',
        'ǽ' => 'ae',
        'À' => 'A',
        'Á' => 'A',
        'Â' => 'A',
        'Ã' => 'A',
        'Å' => 'AA',
        'Ǻ' => 'A',
        'Ă' => 'A',
        'Ǎ' => 'A',
        'Æ' => 'AE',
        'Ǽ' => 'AE',
        'à' => 'a',
        'á' => 'a',
        'â' => 'a',
        'ã' => 'a',
        'å' => 'aa',
        'ǻ' => 'a',
        'ă' => 'a',
        'ǎ' => 'a',
        'ª' => 'a',
        'Ĉ' => 'C',
        'Ċ' => 'C',
        'Ç' => 'C',
        'ç' => 'c',
        'ĉ' => 'c',
        'ċ' => 'c',
        'Ð' => 'Dj',
        'Đ' => 'D',
        'ð' => 'dj',
        'đ' => 'd',
        'È' => 'E',
        'É' => 'E',
        'Ê' => 'E',
        'Ë' => 'E',
        'Ĕ' => 'E',
        'Ė' => 'E',
        'è' => 'e',
        'é' => 'e',
        'ê' => 'e',
        'ë' => 'e',
        'ĕ' => 'e',
        'ė' => 'e',
        'ƒ' => 'f',
        'Ĝ' => 'G',
        'Ġ' => 'G',
        'ĝ' => 'g',
        'ġ' => 'g',
        'Ĥ' => 'H',
        'Ħ' => 'H',
        'ĥ' => 'h',
        'ħ' => 'h',
        'Ì' => 'I',
        'Í' => 'I',
        'Î' => 'I',
        'Ï' => 'I',
        'Ĩ' => 'I',
        'Ĭ' => 'I',
        'Ǐ' => 'I',
        'Į' => 'I',
        'Ĳ' => 'IJ',
        'ì' => 'i',
        'í' => 'i',
        'î' => 'i',
        'ï' => 'i',
        'ĩ' => 'i',
        'ĭ' => 'i',
        'ǐ' => 'i',
        'į' => 'i',
        'ĳ' => 'ij',
        'Ĵ' => 'J',
        'ĵ' => 'j',
        'Ĺ' => 'L',
        'Ľ' => 'L',
        'Ŀ' => 'L',
        'ĺ' => 'l',
        'ľ' => 'l',
        'ŀ' => 'l',
        'Ñ' => 'N',
        'ñ' => 'n',
        'ŉ' => 'n',
        'Ò' => 'O',
        'Ó' => 'O',
        'Ô' => 'O',
        'Õ' => 'O',
        'Ō' => 'O',
        'Ŏ' => 'O',
        'Ǒ' => 'O',
        'Ő' => 'O',
        'Ơ' => 'O',
        'Ø' => 'OE',
        'Ǿ' => 'O',
        'Œ' => 'OE',
        'ò' => 'o',
        'ó' => 'o',
        'ô' => 'o',
        'õ' => 'o',
        'ō' => 'o',
        'ŏ' => 'o',
        'ǒ' => 'o',
        'ő' => 'o',
        'ơ' => 'o',
        'ø' => 'oe',
        'ǿ' => 'o',
        'º' => 'o',
        'œ' => 'oe',
        'Ŕ' => 'R',
        'Ŗ' => 'R',
        'ŕ' => 'r',
        'ŗ' => 'r',
        'Ŝ' => 'S',
        'Ș' => 'S',
        'ŝ' => 's',
        'ș' => 's',
        'ſ' => 's',
        'Ţ' => 'T',
        'Ț' => 'T',
        'Ŧ' => 'T',
        'Þ' => 'TH',
        'ţ' => 't',
        'ț' => 't',
        'ŧ' => 't',
        'þ' => 'th',
        'Ù' => 'U',
        'Ú' => 'U',
        'Û' => 'U',
        'Ü' => 'U',
        'Ũ' => 'U',
        'Ŭ' => 'U',
        'Ű' => 'U',
        'Ų' => 'U',
        'Ư' => 'U',
        'Ǔ' => 'U',
        'Ǖ' => 'U',
        'Ǘ' => 'U',
        'Ǚ' => 'U',
        'Ǜ' => 'U',
        'ù' => 'u',
        'ú' => 'u',
        'û' => 'u',
        'ü' => 'u',
        'ũ' => 'u',
        'ŭ' => 'u',
        'ű' => 'u',
        'ų' => 'u',
        'ư' => 'u',
        'ǔ' => 'u',
        'ǖ' => 'u',
        'ǘ' => 'u',
        'ǚ' => 'u',
        'ǜ' => 'u',
        'Ŵ' => 'W',
        'ŵ' => 'w',
        'Ý' => 'Y',
        'Ÿ' => 'Y',
        'Ŷ' => 'Y',
        'ý' => 'y',
        'ÿ' => 'y',
        'ŷ' => 'y',
    ],
    // Greek(lish) (Elláda)
    'el__greeklish' => [
        'ΑΥ' => 'AU',
        'ΑΎ' => 'AU',
        'Αυ' => 'Au',
        'Αύ' => 'Au',
        'ΕΊ' => 'EI',
        'ΕΙ' => 'EI',
        'Ει' => 'EI',
        'ΕΥ' => 'EU',
        'ΕΎ' => 'EU',
        'Εί' => 'Ei',
        'Ευ' => 'Eu',
        'Εύ' => 'Eu',
        'ΟΙ' => 'OI',
        'ΟΊ' => 'OI',
        'ΟΥ' => 'OU',
        'ΟΎ' => 'OU',
        'Οι' => 'Oi',
        'Οί' => 'Oi',
        'Ου' => 'Ou',
        'Ού' => 'Ou',
        'ΥΙ' => 'YI',
        'ΎΙ' => 'YI',
        'Υι' => 'Yi',
        'Ύι' => 'Yi',
        'ΥΊ' => 'Yi',
        'Υί' => 'Yi',
        'αυ' => 'au',
        'αύ' => 'au',
        'εί' => 'ei',
        'ει' => 'ei',
        'ευ' => 'eu',
        'εύ' => 'eu',
        'οι' => 'oi',
        'οί' => 'oi',
        'ου' => 'ou',
        'ού' => 'ou',
        'υι' => 'yi',
        'ύι' => 'yi',
        'υί' => 'yi',
        'Α'  => 'A',
        'Ά'  => 'A',
        'Β'  => 'B',
        'Δ'  => 'D',
        'Ε'  => 'E',
        'Έ'  => 'E',
        'Φ'  => 'F',
        'Γ'  => 'G',
        'Η'  => 'H',
        'Ή'  => 'H',
        'Ι'  => 'I',
        'Ί'  => 'I',
        'Ϊ'  => 'I',
        'Κ'  => 'K',
        'Ξ'  => 'Ks',
        'Λ'  => 'L',
        'Μ'  => 'M',
        'Ν'  => 'N',
        'Π'  => 'N',
        'Ο'  => 'O',
        'Ό'  => 'O',
        'Ψ'  => 'Ps',
        'Ρ'  => 'R',
        'Σ'  => 'S',
        'Τ'  => 'T',
        'Θ'  => 'Th',
        'Ω'  => 'W',
        'Ώ'  => 'W',
        'Χ'  => 'X',
        'ϒ'  => 'Y',
        'Υ'  => 'Y',
        'Ύ'  => 'Y',
        'Ϋ'  => 'Y',
        'Ζ'  => 'Z',
        'α'  => 'a',
        'ά'  => 'a',
        'β'  => 'b',
        'δ'  => 'd',
        'ε'  => 'e',
        'έ'  => 'e',
        'φ'  => 'f',
        'γ'  => 'g',
        'η'  => 'h',
        'ή'  => 'h',
        'ι'  => 'i',
        'ί'  => 'i',
        'ϊ'  => 'i',
        'ΐ'  => 'i',
        'κ'  => 'k',
        'ξ'  => 'ks',
        'λ'  => 'l',
        'μ'  => 'm',
        'ν'  => 'n',
        'ο'  => 'o',
        'ό'  => 'o',
        'π'  => 'p',
        'ψ'  => 'ps',
        'ρ'  => 'r',
        'σ'  => 's',
        'ς'  => 's',
        'τ'  => 't',
        'ϑ'  => 'th',
        'θ'  => 'th',
        'ϐ'  => 'v',
        'ω'  => 'w',
        'ώ'  => 'w',
        'χ'  => 'x',
        'υ'  => 'y',
        'ύ'  => 'y',
        'ΰ'  => 'y',
        'ϋ'  => 'y',
        'ζ'  => 'z',
    ],
    // Greek (Elláda)
    'el' => [
        'ΑΥ' => 'AU',
        'Αυ' => 'Au',
        'ΟΥ' => 'U',
        'Ου' => 'u',
        'ΕΥ' => 'EF',
        'Ευ' => 'Ef',
        'ΕΙ' => 'I',
        'Ει' => 'I',
        'ΟΙ' => 'I',
        'Οι' => 'I',
        'ΥΙ' => 'I',
        'Υι' => 'I',
        'ΑΎ' => 'AU',
        'Αύ' => 'Au',
        'ΟΎ' => 'OU',
        'Ού' => 'Ou',
        'ΕΎ' => 'EU',
        'Εύ' => 'Eu',
        'ΕΊ' => 'I',
        'Εί' => 'I',
        'ΟΊ' => 'I',
        'Οί' => 'I',
        'ΎΙ' => 'I',
        'Ύι' => 'I',
        'ΥΊ' => 'I',
        'Υί' => 'I',
        'αυ' => 'au',
        'ου' => 'u',
        'ευ' => 'ef',
        'ει' => 'i',
        'οι' => 'i',
        'υι' => 'i',
        'αύ' => 'au',
        'ού' => 'ou',
        'εύ' => 'eu',
        'εί' => 'i',
        'οί' => 'i',
        'ύι' => 'i',
        'υί' => 'i',
        'α'  => 'a',
        'β'  => 'v',
        'γ'  => 'gh',
        'δ'  => 'd',
        'ε'  => 'e',
        'ζ'  => 'z',
        'η'  => 'i',
        'θ'  => 'th',
        'ι'  => 'i',
        'κ'  => 'k',
        'λ'  => 'l',
        'μ'  => 'm',
        'ν'  => 'n',
        'ξ'  => 'ks',
        'ο'  => 'o',
        'π'  => 'p',
        'ρ'  => 'r',
        'σ'  => 's',
        'τ'  => 't',
        'υ'  => 'i',
        'φ'  => 'f',
        'χ'  => 'kh',
        'ψ'  => 'ps',
        'ω'  => 'o',
        'ά'  => 'a',
        'έ'  => 'e',
        'ί'  => 'i',
        'ό'  => 'o',
        'ϒ'  => 'Y',
        'ύ'  => 'y',
        'ή'  => 'i',
        'ώ'  => 'w',
        'ς'  => 's',
        'ϊ'  => 'i',
        'ΰ'  => 'y',
        'ϋ'  => 'y',
        'ΐ'  => 'i',
        'Α'  => 'A',
        'Β'  => 'B',
        'Γ'  => 'G',
        'Δ'  => 'D',
        'Ε'  => 'E',
        'Ζ'  => 'Z',
        'Η'  => 'H',
        'Θ'  => 'Th',
        'Ι'  => 'I',
        'Κ'  => 'K',
        'Λ'  => 'L',
        'Μ'  => 'M',
        'Ν'  => 'N',
        'Ξ'  => 'Ks',
        'Ο'  => 'O',
        'Π'  => 'P',
        'Ρ'  => 'R',
        'Σ'  => 'S',
        'Τ'  => 'T',
        'Υ'  => 'Y',
        'Φ'  => 'F',
        'Χ'  => 'X',
        'Ψ'  => 'Ps',
        'Ω'  => 'O',
        'Ά'  => 'A',
        'Έ'  => 'E',
        'Ί'  => 'I',
        'Ό'  => 'O',
        'Ύ'  => 'Y',
        'Ή'  => 'I',
        'Ώ'  => 'W',
        'Ϊ'  => 'I',
        'Ϋ'  => 'Y',
        'ϐ'  => 'v',
        'ϑ'  => 'th',
    ],
    // Hindi
    'hi' => [
        'अ'  => 'a',
        'आ'  => 'aa',
        'ए'  => 'e',
        'ई'  => 'ii',
        'ऍ'  => 'ei',
        'ऎ'  => 'ae',
        'ऐ'  => 'ai',
        'इ'  => 'i',
        'ओ'  => 'o',
        'ऑ'  => 'oi',
        'ऒ'  => 'oii',
        'ऊ'  => 'uu',
        'औ'  => 'ou',
        'उ'  => 'u',
        'ब'  => 'B',
        'भ'  => 'Bha',
        'च'  => 'Ca',
        'छ'  => 'Chha',
        'ड'  => 'Da',
        'ढ'  => 'Dha',
        'फ'  => 'Fa',
        'फ़' => 'Fi',
        'ग'  => 'Ga',
        'घ'  => 'Gha',
        'ग़' => 'Ghi',
        'ह'  => 'Ha',
        'ज'  => 'Ja',
        'झ'  => 'Jha',
        'क'  => 'Ka',
        'ख'  => 'Kha',
        'ख़' => 'Khi',
        'ल'  => 'L',
        'ळ'  => 'Li',
        'ऌ'  => 'Li',
        'ऴ'  => 'Lii',
        'ॡ'  => 'Lii',
        'म'  => 'Ma',
        'न'  => 'Na',
        'ङ'  => 'Na',
        'ञ'  => 'Nia',
        'ण'  => 'Nae',
        'ऩ'  => 'Ni',
        'ॐ'  => 'oms',
        'प'  => 'Pa',
        'क़' => 'Qi',
        'र'  => 'Ra',
        'ऋ'  => 'Ri',
        'ॠ'  => 'Ri',
        'ऱ'  => 'Ri',
        'स'  => 'Sa',
        'श'  => 'Sha',
        'ष'  => 'Shha',
        'ट'  => 'Ta',
        'त'  => 'Ta',
        'ठ'  => 'Tha',
        'द'  => 'Tha',
        'थ'  => 'Tha',
        'ध'  => 'Thha',
        'ड़' => 'ugDha',
        'ढ़' => 'ugDhha',
        'व'  => 'Va',
        'य'  => 'Ya',
        'य़' => 'Yi',
        'ज़' => 'Za',
    ],
    // Armenian
    'hy' => [
        'Ա' => 'A',
        'Բ' => 'B',
        'Գ' => 'G',
        'Դ' => 'D',
        'Ե' => 'E',
        'Զ' => 'Z',
        'Է' => 'E',
        'Ը' => 'Y',
        'Թ' => 'Th',
        'Ժ' => 'Zh',
        'Ի' => 'I',
        'Լ' => 'L',
        'Խ' => 'Kh',
        'Ծ' => 'Ts',
        'Կ' => 'K',
        'Հ' => 'H',
        'Ձ' => 'Dz',
        'Ղ' => 'Gh',
        'Ճ' => 'Tch',
        'Մ' => 'M',
        'Յ' => 'Y',
        'Ն' => 'N',
        'Շ' => 'Sh',
        'Ո' => 'Vo',
        'Չ' => 'Ch',
        'Պ' => 'P',
        'Ջ' => 'J',
        'Ռ' => 'R',
        'Ս' => 'S',
        'Վ' => 'V',
        'Տ' => 'T',
        'Ր' => 'R',
        'Ց' => 'C',
        'Ւ' => 'u',
        'Փ' => 'Ph',
        'Ք' => 'Q',
        'և' => 'ev',
        'Օ' => 'O',
        'Ֆ' => 'F',
        'ա' => 'a',
        'բ' => 'b',
        'գ' => 'g',
        'դ' => 'd',
        'ե' => 'e',
        'զ' => 'z',
        'է' => 'e',
        'ը' => 'y',
        'թ' => 'th',
        'ժ' => 'zh',
        'ի' => 'i',
        'լ' => 'l',
        'խ' => 'kh',
        'ծ' => 'ts',
        'կ' => 'k',
        'հ' => 'h',
        'ձ' => 'dz',
        'ղ' => 'gh',
        'ճ' => 'tch',
        'մ' => 'm',
        'յ' => 'y',
        'ն' => 'n',
        'շ' => 'sh',
        'ո' => 'vo',
        'չ' => 'ch',
        'պ' => 'p',
        'ջ' => 'j',
        'ռ' => 'r',
        'ս' => 's',
        'վ' => 'v',
        'տ' => 't',
        'ր' => 'r',
        'ց' => 'c',
        'ւ' => 'u',
        'փ' => 'ph',
        'ք' => 'q',
        'օ' => 'o',
        'ֆ' => 'f',
    ],
    // Swedish
    'sv' => [
        'Ä' => 'A',
        'ä' => 'a',
        'Å' => 'A',
        'å' => 'a',
        'Ö' => 'O',
        'ö' => 'o',
    ],
    // Turkmen
    'tk' => [
        'Ç' => 'C',
        'Ä' => 'A',
        'Ž' => 'Z',
        'Ň' => 'N',
        'Ö' => 'O',
        'Ş' => 'S',
        'Ü' => 'U',
        'Ý' => 'Y',
        'ç' => 'c',
        'ä' => 'a',
        'ž' => 'z',
        'ň' => 'n',
        'ö' => 'o',
        'ş' => 's',
        'ü' => 'u',
        'ý' => 'y',
    ],
    // Turkish
    'tr' => [
        'ň' => 'n',
        'Ň' => 'N',
        'ş' => 's',
        'Ş' => 'S',
        'ı' => 'i',
        'İ' => 'I',
        'ç' => 'c',
        'Ç' => 'C',
        'ä' => 'a',
        'Ä' => 'A',
        'ü' => 'u',
        'Ü' => 'U',
        'ö' => 'o',
        'Ö' => 'O',
        'ğ' => 'g',
        'Ğ' => 'G',
        'ý' => 'y',
        'Ý' => 'Y',
        'ž' => 'z',
        'Ž' => 'Z',
    ],
    // Bulgarian
    'bg' => [
        'ьо' => 'yo',
        'А'  => 'A',
        'Б'  => 'B',
        'В'  => 'V',
        'Г'  => 'G',
        'Д'  => 'D',
        'Е'  => 'E',
        'Ж'  => 'Zh',
        'З'  => 'Z',
        'И'  => 'I',
        'Й'  => 'Y',
        'К'  => 'K',
        'Л'  => 'L',
        'М'  => 'M',
        'Н'  => 'N',
        'О'  => 'O',
        'П'  => 'P',
        'Р'  => 'R',
        'С'  => 'S',
        'Т'  => 'T',
        'У'  => 'U',
        'Ф'  => 'F',
        'Х'  => 'H',
        'Ц'  => 'C',
        'Ч'  => 'Ch',
        'Ш'  => 'Sh',
        'Щ'  => 'Sht',
        'Ъ'  => 'A',
        'Ь'  => '',
        'Ю'  => 'Yu',
        'Я'  => 'Ya',
        'а'  => 'a',
        'б'  => 'b',
        'в'  => 'v',
        'г'  => 'g',
        'д'  => 'd',
        'е'  => 'e',
        'ж'  => 'zh',
        'з'  => 'z',
        'и'  => 'i',
        'й'  => 'y',
        'к'  => 'k',
        'л'  => 'l',
        'м'  => 'm',
        'н'  => 'n',
        'о'  => 'o',
        'п'  => 'p',
        'р'  => 'r',
        'с'  => 's',
        'т'  => 't',
        'у'  => 'u',
        'ф'  => 'f',
        'х'  => 'h',
        'ц'  => 'c',
        'ч'  => 'ch',
        'ш'  => 'sh',
        'щ'  => 'sht',
        'ъ'  => 'a',
        'ь'  => '',
        'ю'  => 'yu',
        'я'  => 'ya',
    ],
    // Hungarian
    'hu' => [
        'Á' => 'A',
        'Ē' => 'E',
        'É' => 'E',
        'Í' => 'I',
        'Ó' => 'O',
        'Ö' => 'O',
        'Ő' => 'O',
        'Ú' => 'U',
        'Ü' => 'U',
        'Ű' => 'U',
        'á' => 'a',
        'ē' => 'e',
        'é' => 'e',
        'í' => 'i',
        'ó' => 'o',
        'ö' => 'o',
        'ő' => 'o',
        'ú' => 'u',
        'ü' => 'u',
        'ű' => 'u',
    ],
    // Myanmar (Burmese)
    'my' => [
        'န်ုပ်' => 'nub',
        'ောင်'  => 'aung',
        'ိုက်'  => 'aik',
        'ိုဒ်'  => 'ok',
        'ိုင်'  => 'aing',
        'ိုလ်'  => 'ol',
        'ေါင်'  => 'aung',
        'သြော'  => 'aw',
        'ောက်'  => 'auk',
        'ိတ်'   => 'eik',
        'ုတ်'   => 'ok',
        'ုန်'   => 'on',
        'ေတ်'   => 'it',
        'ုဒ်'   => 'ait',
        'ာန်'   => 'an',
        'ိန်'   => 'ein',
        'ွတ်'   => 'ut',
        'ေါ်'   => 'aw',
        'ွန်'   => 'un',
        'ိပ်'   => 'eik',
        'ုပ်'   => 'ok',
        'ွပ်'   => 'ut',
        'ိမ်'   => 'ein',
        'ုမ်'   => 'on',
        'ော်'   => 'aw',
        'ွမ်'   => 'un',
        'က်'    => 'et',
        'ေါ'    => 'aw',
        'ော'    => 'aw',
        'ျွ'    => 'ywa',
        'ြွ'    => 'yw',
        'ို'    => 'o',
        'ုံ'    => 'on',
        'တ်'    => 'at',
        'င်'    => 'in',
        'ည်'    => 'i',
        'ဒ်'    => 'd',
        'န်'    => 'an',
        'ပ်'    => 'at',
        'မ်'    => 'an',
        'စျ'    => 'za',
        'ယ်'    => 'e',
        'ဉ်'    => 'in',
        'စ်'    => 'it',
        'ိံ'    => 'ein',
        'ဲ'     => 'e',
        'း'     => '',
        'ာ'     => 'a',
        'ါ'     => 'a',
        'ေ'     => 'e',
        'ံ'     => 'an',
        'ိ'     => 'i',
        'ီ'     => 'i',
        'ု'     => 'u',
        'ူ'     => 'u',
        '်'     => 'at',
        '္'     => '',
        '့'     => '',
        'က'     => 'k',
        '၉'     => '9',
        'တ'     => 't',
        'ရ'     => 'ya',
        'ယ'     => 'y',
        'မ'     => 'm',
        'ဘ'     => 'ba',
        'ဗ'     => 'b',
        'ဖ'     => 'pa',
        'ပ'     => 'p',
        'န'     => 'n',
        'ဓ'     => 'da',
        'ဒ'     => 'd',
        'ထ'     => 'ta',
        'ဏ'     => 'na',
        'ဝ'     => 'w',
        'ဎ'     => 'da',
        'ဍ'     => 'd',
        'ဌ'     => 'ta',
        'ဋ'     => 't',
        'ည'     => 'ny',
        'ဇ'     => 'z',
        'ဆ'     => 'sa',
        'စ'     => 's',
        'င'     => 'ng',
        'ဃ'     => 'ga',
        'ဂ'     => 'g',
        'လ'     => 'l',
        'သ'     => 'th',
        '၈'     => '8',
        'ဩ'     => 'aw',
        'ခ'     => 'kh',
        '၆'     => '6',
        '၅'     => '5',
        '၄'     => '4',
        '၃'     => '3',
        '၂'     => '2',
        '၁'     => '1',
        '၀'     => '0',
        '၌'     => 'hnaik',
        '၍'     => 'ywae',
        'ဪ'     => 'aw',
        'ဦ'     => '-u',
        'ဟ'     => 'h',
        'ဉ'     => 'u',
        'ဤ'     => '-i',
        'ဣ'     => 'i',
        '၏'     => '-e',
        'ဧ'     => 'e',
        'ှ'     => 'h',
        'ွ'     => 'w',
        'ျ'     => 'ya',
        'ြ'     => 'y',
        'အ'     => 'a',
        'ဠ'     => 'la',
        '၇'     => '7',
    ],
    // Croatian (Hrvatska)
    'hr' => [
        'DŽ' => 'DZ',
        'Dž' => 'Dz',
        'dž' => 'dz',
        'Ǳ'  => 'DZ',
        'ǲ'  => 'Dz',
        'ǳ'  => 'dz',
        'Ĳ'  => 'IJ',
        'ĳ'  => 'ij',
        'Ǉ'  => 'LJ',
        'ǈ'  => 'Lj',
        'ǉ'  => 'lj',
        'Ǌ'  => 'NJ',
        'ǋ'  => 'Nj',
        'ǌ'  => 'nj',
        'ž'  => 'z',
        'Ž'  => 'Z',
        'đ'  => 'dj',
        'Đ'  => 'Dj',
        'č'  => 'c',
        'Č'  => 'C',
        'ć'  => 'c',
        'Ć'  => 'C',
        'š'  => 's',
        'Š'  => 'S',
    ],
    // Finnish
    'fi' => [
        'Ä' => 'A',
        'Ö' => 'O',
        'ä' => 'a',
        'ö' => 'o',
    ],
    // Georgian (Kartvelian)
    'ka' => [
        'ა' => 'a',
        'ბ' => 'b',
        'გ' => 'g',
        'დ' => 'd',
        'ე' => 'e',
        'ვ' => 'v',
        'ზ' => 'z',
        'თ' => 't',
        'ი' => 'i',
        'კ' => 'k',
        'ლ' => 'l',
        'მ' => 'm',
        'ნ' => 'n',
        'ო' => 'o',
        'პ' => 'p',
        'ჟ' => 'zh',
        'რ' => 'r',
        'ს' => 's',
        'ტ' => 't',
        'უ' => 'u',
        'ფ' => 'f',
        'ქ' => 'q',
        'ღ' => 'gh',
        'ყ' => 'y',
        'შ' => 'sh',
        'ჩ' => 'ch',
        'ც' => 'ts',
        'ძ' => 'dz',
        'წ' => 'ts',
        'ჭ' => 'ch',
        'ხ' => 'kh',
        'ჯ' => 'j',
        'ჰ' => 'h',
    ],
    // Russian
    'ru' => [
        'А' => 'A',
        'а' => 'a',
        'Б' => 'B',
        'б' => 'b',
        'В' => 'V',
        'в' => 'v',
        'Г' => 'G',
        'г' => 'g',
        'Д' => 'D',
        'д' => 'd',
        'Е' => 'E',
        'е' => 'e',
        'Ё' => 'Yo',
        'ё' => 'yo',
        'Ж' => 'Zh',
        'ж' => 'zh',
        'З' => 'Z',
        'з' => 'z',
        'И' => 'I',
        'и' => 'i',
        'Й' => 'Y',
        'й' => 'y',
        'К' => 'K',
        'к' => 'k',
        'Л' => 'L',
        'л' => 'l',
        'М' => 'M',
        'м' => 'm',
        'Н' => 'N',
        'н' => 'n',
        'О' => 'O',
        'о' => 'o',
        'П' => 'P',
        'п' => 'p',
        'Р' => 'R',
        'р' => 'r',
        'С' => 'S',
        'с' => 's',
        'Т' => 'T',
        'т' => 't',
        'У' => 'U',
        'у' => 'u',
        'Ф' => 'F',
        'ф' => 'f',
        'Х' => 'H',
        'х' => 'h',
        'Ц' => 'Ts',
        'ц' => 'ts',
        'Ч' => 'Ch',
        'ч' => 'ch',
        'ш' => 'sh',
        'Ш' => 'Sh',
        'Щ' => 'Sch',
        'щ' => 'sch',
        'Ъ' => '',
        'ъ' => '',
        'Ы' => 'Y',
        'ы' => 'y',
        'Ь' => '',
        'ь' => '',
        'Э' => 'E',
        'э' => 'e',
        'Ю' => 'Yu',
        'ю' => 'yu',
        'Я' => 'Ya',
        'я' => 'ya',
    ],
    // Russian - GOST 7.79-2000(B)
    // -> https://en.m.wikipedia.org/wiki/Romanization_of_Russian#content-collapsible-block-1
    'ru__gost_2000_b' => [
        'А' => 'A',
        'а' => 'a',
        'Б' => 'B',
        'б' => 'b',
        'В' => 'V',
        'в' => 'v',
        'Г' => 'G',
        'г' => 'g',
        'Д' => 'D',
        'д' => 'd',
        'Е' => 'E',
        'е' => 'e',
        'Ё' => 'Yo',
        'ё' => 'yo',
        'Ж' => 'Zh',
        'ж' => 'zh',
        'З' => 'Z',
        'з' => 'z',
        'И' => 'i',
        'и' => 'i',
        'Й' => 'i',
        'й' => 'i',
        'К' => 'K',
        'к' => 'k',
        'Л' => 'L',
        'л' => 'l',
        'М' => 'M',
        'м' => 'm',
        'Н' => 'N',
        'н' => 'n',
        'О' => 'O',
        'о' => 'o',
        'П' => 'P',
        'п' => 'p',
        'Р' => 'R',
        'р' => 'r',
        'С' => 'S',
        'с' => 's',
        'Т' => 'T',
        'т' => 't',
        'У' => 'U',
        'у' => 'u',
        'Ф' => 'F',
        'ф' => 'f',
        'Х' => 'X',
        'х' => 'x',
        'Ц' => 'Cz',
        'ц' => 'cz',
        'Ч' => 'Ch',
        'ч' => 'ch',
        'ш' => 'sh',
        'Ш' => 'Sh',
        'Щ' => 'Shh',
        'щ' => 'shh',
        'Ъ' => '',
        'ъ' => '',
        'Ы' => 'Y\'',
        'ы' => 'y\'',
        'Ь' => '',
        'ь' => '',
        'Э' => 'E\'',
        'э' => 'e\'',
        'Ю' => 'Yu',
        'ю' => 'yu',
        'Я' => 'Ya',
        'я' => 'ya',
        'І' => 'I',
        'і' => 'i',
        'Ѳ' => 'Fh',
        'ѳ' => 'fh',
        'Ѣ' => 'Ye',
        'ѣ' => 'ye',
        'Ѵ' => 'Yh',
        'ѵ' => 'yh',
        'Є' => '',
        'є' => '',
        'Ѥ' => '',
        'ѥ' => '',
        'Ѕ' => 'Js',
        'ѕ' => 'js',
        'Ꙋ' => '',
        'ꙋ' => '',
        'Ѡ' => '',
        'ѡ' => '',
        'Ѿ' => '',
        'ѿ' => '',
        'Ѫ' => '',
        'ѫ' => '',
        'Ѧ' => '',
        'ѧ' => '',
        'Ѭ' => '',
        'ѭ' => '',
        'Ѩ' => '',
        'ѩ' => '',
        'Ѯ' => '',
        'ѯ' => '',
        'Ѱ' => '',
        'ѱ' => '',
    ],
    // Russian - Passport (2013), ICAO
    // -> https://en.m.wikipedia.org/wiki/Romanization_of_Russian#content-collapsible-block-1
    'ru__passport_2013' => [
        'А' => 'A',
        'а' => 'a',
        'Б' => 'B',
        'б' => 'b',
        'В' => 'V',
        'в' => 'v',
        'Г' => 'G',
        'г' => 'g',
        'Д' => 'D',
        'д' => 'd',
        'Е' => 'E',
        'е' => 'e',
        'Ё' => 'E',
        'ё' => 'e',
        'Ж' => 'Zh',
        'ж' => 'zh',
        'З' => 'Z',
        'з' => 'z',
        'И' => 'i',
        'и' => 'i',
        'Й' => 'i',
        'й' => 'i',
        'К' => 'K',
        'к' => 'k',
        'Л' => 'L',
        'л' => 'l',
        'М' => 'M',
        'м' => 'm',
        'Н' => 'N',
        'н' => 'n',
        'О' => 'O',
        'о' => 'o',
        'П' => 'P',
        'п' => 'p',
        'Р' => 'R',
        'р' => 'r',
        'С' => 'S',
        'с' => 's',
        'Т' => 'T',
        'т' => 't',
        'У' => 'U',
        'у' => 'u',
        'Ф' => 'F',
        'ф' => 'f',
        'Х' => 'Kh',
        'х' => 'kh',
        'Ц' => 'Ts',
        'ц' => 'ts',
        'Ч' => 'Ch',
        'ч' => 'ch',
        'ш' => 'sh',
        'Ш' => 'Sh',
        'Щ' => 'Shch',
        'щ' => 'shch',
        'Ъ' => 'Ie',
        'ъ' => 'ie',
        'Ы' => 'Y',
        'ы' => 'y',
        'Ь' => '',
        'ь' => '',
        'Э' => 'E',
        'э' => 'e',
        'Ю' => 'Iu',
        'ю' => 'iu',
        'Я' => 'Ia',
        'я' => 'ia',
        'І' => '',
        'і' => '',
        'Ѳ' => '',
        'ѳ' => '',
        'Ѣ' => '',
        'ѣ' => '',
        'Ѵ' => '',
        'ѵ' => '',
        'Є' => '',
        'є' => '',
        'Ѥ' => '',
        'ѥ' => '',
        'Ѕ' => '',
        'ѕ' => '',
        'Ꙋ' => '',
        'ꙋ' => '',
        'Ѡ' => '',
        'ѡ' => '',
        'Ѿ' => '',
        'ѿ' => '',
        'Ѫ' => '',
        'ѫ' => '',
        'Ѧ' => '',
        'ѧ' => '',
        'Ѭ' => '',
        'ѭ' => '',
        'Ѩ' => '',
        'ѩ' => '',
        'Ѯ' => '',
        'ѯ' => '',
        'Ѱ' => '',
        'ѱ' => '',
    ],
    // Ukrainian
    // -> https://zakon.rada.gov.ua/laws/show/55-2010-%D0%BF?lang=en
    'uk' => [
        'Г' => 'H',
        'г' => 'h',
        'Ґ' => 'G',
        'ґ' => 'g',
        'Є' => 'Ye',
        'є' => 'ye',
        'И' => 'Y',
        'и' => 'y',
        'І' => 'I',
        'і' => 'i',
        'Ї' => 'Yi',
        'ї' => 'yi',
        'Й' => 'Y',
        'й' => 'y',
        'Х' => 'Kh',
        'х' => 'kh',
        'Ц' => 'Ts',
        'ц' => 'ts',
        'Ч' => 'Ch',
        'ч' => 'ch',
        'Ш' => 'Sh',
        'ш' => 'sh',
        'Щ' => 'Shch',
        'щ' => 'shch',
    ],
    // Kazakh
    'kk' => [
        'Ә' => 'A',
        'Ғ' => 'G',
        'Қ' => 'Q',
        'Ң' => 'N',
        'Ө' => 'O',
        'Ұ' => 'U',
        'Ү' => 'U',
        'Һ' => 'H',
        'ә' => 'a',
        'ғ' => 'g',
        'қ' => 'q',
        'ң' => 'n',
        'ө' => 'o',
        'ұ' => 'u',
        'ү' => 'u',
        'һ' => 'h',
    ],
    // Czech
    'cs' => [
        'á' => 'a',
        'Á' => 'A',
        'č' => 'c',
        'Č' => 'C',
        'ď' => 'd',
        'Ď' => 'D',
        'é' => 'e',
        'É' => 'E',
        'ě' => 'e',
        'Ě' => 'E',
        'í' => 'i',
        'Í' => 'I',
        'ň' => 'n',
        'Ň' => 'N',
        'ó' => 'o',
        'Ó' => 'O',
        'ř' => 'r',
        'Ř' => 'R',
        'š' => 's',
        'Š' => 'S',
        'ť' => 't',
        'Ť' => 'T',
        'ú' => 'u',
        'Ú' => 'U',
        'ů' => 'u',
        'Ů' => 'U',
        'ý' => 'y',
        'Ý' => 'Y',
        'ž' => 'z',
        'Ž' => 'Z',
    ],
    // Danish
    'da' => [
        'Æ' => 'Ae',
        'æ' => 'ae',
        'Ø' => 'Oe',
        'ø' => 'oe',
        'Å' => 'Aa',
        'å' => 'aa',
        'É' => 'E',
        'é' => 'e',
    ],
    // Polish
    'pl' => [
        'ą' => 'a',
        'ć' => 'c',
        'ę' => 'e',
        'ł' => 'l',
        'ń' => 'n',
        'ó' => 'o',
        'ś' => 's',
        'ź' => 'z',
        'ż' => 'z',
        'Ą' => 'A',
        'Ć' => 'C',
        'Ę' => 'E',
        'Ł' => 'L',
        'Ń' => 'N',
        'Ó' => 'O',
        'Ś' => 'S',
        'Ź' => 'Z',
        'Ż' => 'Z',
    ],
    // Romanian
    'ro' => [
        'ă' => 'a',
        'â' => 'a',
        'Ă' => 'A',
        'Â' => 'A',
        'î' => 'i',
        'Î' => 'I',
        'ș' => 's',
        'ş' => 's',
        'Ş' => 'S',
        'Ș' => 'S',
        'ț' => 't',
        'ţ' => 't',
        'Ţ' => 'T',
        'Ț' => 'T',
    ],
    // Esperanto
    'eo' => [
        'ĉ' => 'cx',
        'ĝ' => 'gx',
        'ĥ' => 'hx',
        'ĵ' => 'jx',
        'ŝ' => 'sx',
        'ŭ' => 'ux',
        'Ĉ' => 'CX',
        'Ĝ' => 'GX',
        'Ĥ' => 'HX',
        'Ĵ' => 'JX',
        'Ŝ' => 'SX',
        'Ŭ' => 'UX',
    ],
    // Estonian
    'et' => [
        'Š' => 'S',
        'Ž' => 'Z',
        'Õ' => 'O',
        'Ä' => 'A',
        'Ö' => 'O',
        'Ü' => 'U',
        'š' => 's',
        'ž' => 'z',
        'õ' => 'o',
        'ä' => 'a',
        'ö' => 'o',
        'ü' => 'u',
    ],
    // Latvian
    'lv' => [
        'ā' => 'a',
        'č' => 'c',
        'ē' => 'e',
        'ģ' => 'g',
        'ī' => 'i',
        'ķ' => 'k',
        'ļ' => 'l',
        'ņ' => 'n',
        'š' => 's',
        'ū' => 'u',
        'ž' => 'z',
        'Ā' => 'A',
        'Č' => 'C',
        'Ē' => 'E',
        'Ģ' => 'G',
        'Ī' => 'i',
        'Ķ' => 'k',
        'Ļ' => 'L',
        'Ņ' => 'N',
        'Š' => 'S',
        'Ū' => 'u',
        'Ž' => 'Z',
    ],
    // Lithuanian
    'lt' => [
        'ą' => 'a',
        'č' => 'c',
        'ę' => 'e',
        'ė' => 'e',
        'į' => 'i',
        'š' => 's',
        'ų' => 'u',
        'ū' => 'u',
        'ž' => 'z',
        'Ą' => 'A',
        'Č' => 'C',
        'Ę' => 'E',
        'Ė' => 'E',
        'Į' => 'I',
        'Š' => 'S',
        'Ų' => 'U',
        'Ū' => 'U',
        'Ž' => 'Z',
    ],
    // Norwegian
    'no' => [
        'Æ' => 'AE',
        'æ' => 'ae',
        'Ø' => 'OE',
        'ø' => 'oe',
        'Å' => 'AA',
        'å' => 'aa',
    ],
    // Vietnamese
    'vi' => [
        'Á' => 'A',
        'À' => 'A',
        'Ả' => 'A',
        'Ã' => 'A',
        'Ạ' => 'A',
        'Ă' => 'A',
        'Ắ' => 'A',
        'Ằ' => 'A',
        'Ẳ' => 'A',
        'Ẵ' => 'A',
        'Ặ' => 'A',
        'Â' => 'A',
        'Ấ' => 'A',
        'Ầ' => 'A',
        'Ẩ' => 'A',
        'Ẫ' => 'A',
        'Ậ' => 'A',
        'á' => 'a',
        'à' => 'a',
        'ả' => 'a',
        'ã' => 'a',
        'ạ' => 'a',
        'ă' => 'a',
        'ắ' => 'a',
        'ằ' => 'a',
        'ẳ' => 'a',
        'ẵ' => 'a',
        'ặ' => 'a',
        'â' => 'a',
        'ấ' => 'a',
        'ầ' => 'a',
        'ẩ' => 'a',
        'ẫ' => 'a',
        'ậ' => 'a',
        'É' => 'E',
        'È' => 'E',
        'Ẻ' => 'E',
        'Ẽ' => 'E',
        'Ẹ' => 'E',
        'Ê' => 'E',
        'Ế' => 'E',
        'Ề' => 'E',
        'Ể' => 'E',
        'Ễ' => 'E',
        'Ệ' => 'E',
        'é' => 'e',
        'è' => 'e',
        'ẻ' => 'e',
        'ẽ' => 'e',
        'ẹ' => 'e',
        'ê' => 'e',
        'ế' => 'e',
        'ề' => 'e',
        'ể' => 'e',
        'ễ' => 'e',
        'ệ' => 'e',
        'Í' => 'I',
        'Ì' => 'I',
        'Ỉ' => 'I',
        'Ĩ' => 'I',
        'Ị' => 'I',
        'í' => 'i',
        'ì' => 'i',
        'ỉ' => 'i',
        'ĩ' => 'i',
        'ị' => 'i',
        'Ó' => 'O',
        'Ò' => 'O',
        'Ỏ' => 'O',
        'Õ' => 'O',
        'Ọ' => 'O',
        'Ô' => 'O',
        'Ố' => 'O',
        'Ồ' => 'O',
        'Ổ' => 'O',
        'Ỗ' => 'O',
        'Ộ' => 'O',
        'Ơ' => 'O',
        'Ớ' => 'O',
        'Ờ' => 'O',
        'Ở' => 'O',
        'Ỡ' => 'O',
        'Ợ' => 'O',
        'ó' => 'o',
        'ò' => 'o',
        'ỏ' => 'o',
        'õ' => 'o',
        'ọ' => 'o',
        'ô' => 'o',
        'ố' => 'o',
        'ồ' => 'o',
        'ổ' => 'o',
        'ỗ' => 'o',
        'ộ' => 'o',
        'ơ' => 'o',
        'ớ' => 'o',
        'ờ' => 'o',
        'ở' => 'o',
        'ỡ' => 'o',
        'ợ' => 'o',
        'Ú' => 'U',
        'Ù' => 'U',
        'Ủ' => 'U',
        'Ũ' => 'U',
        'Ụ' => 'U',
        'Ư' => 'U',
        'Ứ' => 'U',
        'Ừ' => 'U',
        'Ử' => 'U',
        'Ữ' => 'U',
        'Ự' => 'U',
        'ú' => 'u',
        'ù' => 'u',
        'ủ' => 'u',
        'ũ' => 'u',
        'ụ' => 'u',
        'ư' => 'u',
        'ứ' => 'u',
        'ừ' => 'u',
        'ử' => 'u',
        'ữ' => 'u',
        'ự' => 'u',
        'Ý' => 'Y',
        'Ỳ' => 'Y',
        'Ỷ' => 'Y',
        'Ỹ' => 'Y',
        'Ỵ' => 'Y',
        'ý' => 'y',
        'ỳ' => 'y',
        'ỷ' => 'y',
        'ỹ' => 'y',
        'ỵ' => 'y',
        'Đ' => 'D',
        'đ' => 'd',
    ],
    // Persian (Farsi)
    'fa' => [
        'ا' => 'a',
        'ب' => 'b',
        'پ' => 'p',
        'ت' => 't',
        'ث' => 's',
        'ج' => 'j',
        'چ' => 'ch',
        'ح' => 'h',
        'خ' => 'kh',
        'د' => 'd',
        'ذ' => 'z',
        'ر' => 'r',
        'ز' => 'z',
        'س' => 's',
        'ش' => 'sh',
        'ص' => 's',
        'ض' => 'z',
        'ط' => 't',
        'ظ' => 'z',
        'ع' => 'a',
        'غ' => 'gh',
        'ف' => 'f',
        'ق' => 'gh',
        'ک' => 'k',
        'گ' => 'g',
        'ل' => 'l',
        'ژ' => 'zh',
        'ك' => 'k',
        'م' => 'm',
        'ن' => 'n',
        'ه' => 'h',
        'و' => 'o',
        'ی' => 'y',
        'آ' => 'a',
        '٠' => '0',
        '١' => '1',
        '٢' => '2',
        '٣' => '3',
        '٤' => '4',
        '٥' => '5',
        '٦' => '6',
        '٧' => '7',
        '٨' => '8',
        '٩' => '9',
    ],
    // Arabic
    'ar' => [
        'أ' => 'a',
        'ب' => 'b',
        'ت' => 't',
        'ث' => 'th',
        'ج' => 'g',
        'ح' => 'h',
        'خ' => 'kh',
        'د' => 'd',
        'ذ' => 'th',
        'ر' => 'r',
        'ز' => 'z',
        'س' => 's',
        'ش' => 'sh',
        'ص' => 's',
        'ض' => 'd',
        'ط' => 't',
        'ظ' => 'th',
        'ع' => 'aa',
        'غ' => 'gh',
        'ف' => 'f',
        'ق' => 'k',
        'ك' => 'k',
        'ل' => 'l',
        'م' => 'm',
        'ن' => 'n',
        'ه' => 'h',
        'و' => 'o',
        'ي' => 'y',
        'ا' => 'a',
        'إ' => 'a',
        'آ' => 'a',
        'ؤ' => 'o',
        'ئ' => 'y',
        'ء' => 'aa',
        '٠' => '0',
        '١' => '1',
        '٢' => '2',
        '٣' => '3',
        '٤' => '4',
        '٥' => '5',
        '٦' => '6',
        '٧' => '7',
        '٨' => '8',
        '٩' => '9',
    ],
    // Serbian
    'sr' => [
        'đ' => 'dj',
        'ž' => 'z',
        'ć' => 'c',
        'č' => 'c',
        'š' => 's',
        'Đ' => 'Dj',
        'Ž' => 'Z',
        'Ć' => 'C',
        'Č' => 'C',
        'Š' => 'S',
        'а' => 'a',
        'б' => 'b',
        'в' => 'v',
        'г' => 'g',
        'д' => 'd',
        'ђ' => 'dj',
        'е' => 'e',
        'ж' => 'z',
        'з' => 'z',
        'и' => 'i',
        'ј' => 'j',
        'к' => 'k',
        'л' => 'l',
        'љ' => 'lj',
        'м' => 'm',
        'н' => 'n',
        'њ' => 'nj',
        'о' => 'o',
        'п' => 'p',
        'р' => 'r',
        'с' => 's',
        'т' => 't',
        'ћ' => 'c',
        'у' => 'u',
        'ф' => 'f',
        'х' => 'h',
        'ц' => 'c',
        'ч' => 'c',
        'џ' => 'dz',
        'ш' => 's',
        'А' => 'A',
        'Б' => 'B',
        'В' => 'V',
        'Г' => 'G',
        'Д' => 'D',
        'Ђ' => 'Dj',
        'Е' => 'E',
        'Ж' => 'Z',
        'З' => 'Z',
        'И' => 'I',
        'Ј' => 'j',
        'К' => 'K',
        'Л' => 'L',
        'Љ' => 'Lj',
        'М' => 'M',
        'Н' => 'N',
        'Њ' => 'Nj',
        'О' => 'O',
        'П' => 'P',
        'Р' => 'R',
        'С' => 'S',
        'Т' => 'T',
        'Ћ' => 'C',
        'У' => 'U',
        'Ф' => 'F',
        'Х' => 'H',
        'Ц' => 'C',
        'Ч' => 'C',
        'Џ' => 'Dz',
        'Ш' => 'S',
    ],
    // Serbian - Cyrillic
    'sr__cyr' => [
        'а' => 'a',
        'б' => 'b',
        'в' => 'v',
        'г' => 'g',
        'д' => 'd',
        'ђ' => 'dj',
        'е' => 'e',
        'ж' => 'z',
        'з' => 'z',
        'и' => 'i',
        'ј' => 'j',
        'к' => 'k',
        'л' => 'l',
        'љ' => 'lj',
        'м' => 'm',
        'н' => 'n',
        'њ' => 'nj',
        'о' => 'o',
        'п' => 'p',
        'р' => 'r',
        'с' => 's',
        'т' => 't',
        'ћ' => 'c',
        'у' => 'u',
        'ф' => 'f',
        'х' => 'h',
        'ц' => 'c',
        'ч' => 'c',
        'џ' => 'dz',
        'ш' => 's',
        'А' => 'A',
        'Б' => 'B',
        'В' => 'V',
        'Г' => 'G',
        'Д' => 'D',
        'Ђ' => 'Dj',
        'Е' => 'E',
        'Ж' => 'Z',
        'З' => 'Z',
        'И' => 'I',
        'Ј' => 'j',
        'К' => 'K',
        'Л' => 'L',
        'Љ' => 'Lj',
        'М' => 'M',
        'Н' => 'N',
        'Њ' => 'Nj',
        'О' => 'O',
        'П' => 'P',
        'Р' => 'R',
        'С' => 'S',
        'Т' => 'T',
        'Ћ' => 'C',
        'У' => 'U',
        'Ф' => 'F',
        'Х' => 'H',
        'Ц' => 'C',
        'Ч' => 'C',
        'Џ' => 'Dz',
        'Ш' => 'S',
    ],
    // Serbian - Latin
    'sr__lat' => [
        'đ' => 'dj',
        'ž' => 'z',
        'ć' => 'c',
        'č' => 'c',
        'š' => 's',
        'Đ' => 'Dj',
        'Ž' => 'Z',
        'Ć' => 'C',
        'Č' => 'C',
        'Š' => 'S',
    ],
    // Azerbaijani
    'az' => [
        'ç' => 'c',
        'ə' => 'e',
        'ğ' => 'g',
        'ı' => 'i',
        'ö' => 'o',
        'ş' => 's',
        'ü' => 'u',
        'Ç' => 'C',
        'Ə' => 'E',
        'Ğ' => 'G',
        'İ' => 'I',
        'Ö' => 'O',
        'Ş' => 'S',
        'Ü' => 'U',
    ],
    // Slovak
    'sk' => [
        'á' => 'a',
        'ä' => 'a',
        'č' => 'c',
        'ď' => 'd',
        'é' => 'e',
        'í' => 'i',
        'ľ' => 'l',
        'ĺ' => 'l',
        'ň' => 'n',
        'ó' => 'o',
        'ô' => 'o',
        'ŕ' => 'r',
        'š' => 's',
        'ť' => 't',
        'ú' => 'u',
        'ý' => 'y',
        'ž' => 'z',
        'Á' => 'A',
        'Ä' => 'A',
        'Č' => 'C',
        'Ď' => 'D',
        'É' => 'E',
        'Í' => 'I',
        'Ľ' => 'L',
        'Ĺ' => 'L',
        'Ň' => 'N',
        'Ó' => 'O',
        'Ô' => 'O',
        'Ŕ' => 'R',
        'Š' => 'S',
        'Ť' => 'T',
        'Ú' => 'U',
        'Ý' => 'Y',
        'Ž' => 'Z',
    ],
    // French
    'fr' => [
        'Æ' => 'AE',
        'æ' => 'ae',
        'Œ' => 'OE',
        'œ' => 'oe',
        'â' => 'a',
        'Â' => 'A',
        'à' => 'a',
        'À' => 'A',
        'ä' => 'a',
        'Ä' => 'A',
        'ç' => 'c',
        'Ç' => 'C',
        'é' => 'e',
        'É' => 'E',
        'ê' => 'e',
        'Ê' => 'E',
        'ë' => 'e',
        'Ë' => 'E',
        'è' => 'e',
        'È' => 'E',
        'ï' => 'i',
        'î' => 'i',
        'Ï' => 'I',
        'Î' => 'I',
        'ÿ' => 'y',
        'Ÿ' => 'Y',
        'ô' => 'o',
        'Ô' => 'O',
        'ö' => 'o',
        'Ö' => 'O',
        'û' => 'u',
        'Û' => 'U',
        'ù' => 'u',
        'Ù' => 'U',
        'ü' => 'u',
        'Ü' => 'U',
    ],
    // Austrian (French)
    'fr_at' => [
        'ß' => 'sz',
        'ẞ' => 'SZ',
        'Æ' => 'AE',
        'æ' => 'ae',
        'Œ' => 'OE',
        'œ' => 'oe',
        'â' => 'a',
        'Â' => 'A',
        'à' => 'a',
        'À' => 'A',
        'ä' => 'a',
        'Ä' => 'A',
        'ç' => 'c',
        'Ç' => 'C',
        'é' => 'e',
        'É' => 'E',
        'ê' => 'e',
        'Ê' => 'E',
        'ë' => 'e',
        'Ë' => 'E',
        'è' => 'e',
        'È' => 'E',
        'ï' => 'i',
        'î' => 'i',
        'Ï' => 'I',
        'Î' => 'I',
        'ÿ' => 'y',
        'Ÿ' => 'Y',
        'ô' => 'o',
        'Ô' => 'O',
        'ö' => 'o',
        'Ö' => 'O',
        'û' => 'u',
        'Û' => 'U',
        'ù' => 'u',
        'Ù' => 'U',
        'ü' => 'u',
        'Ü' => 'U',
    ],
    // Switzerland (French)
    'fr_ch' => [
        'ß' => 'ss',
        'ẞ' => 'SS',
        'Æ' => 'AE',
        'æ' => 'ae',
        'Œ' => 'OE',
        'œ' => 'oe',
        'â' => 'a',
        'Â' => 'A',
        'à' => 'a',
        'À' => 'A',
        'ä' => 'a',
        'Ä' => 'A',
        'ç' => 'c',
        'Ç' => 'C',
        'é' => 'e',
        'É' => 'E',
        'ê' => 'e',
        'Ê' => 'E',
        'ë' => 'e',
        'Ë' => 'E',
        'è' => 'e',
        'È' => 'E',
        'ï' => 'i',
        'î' => 'i',
        'Ï' => 'I',
        'Î' => 'I',
        'ÿ' => 'y',
        'Ÿ' => 'Y',
        'ô' => 'o',
        'Ô' => 'O',
        'ö' => 'o',
        'Ö' => 'O',
        'û' => 'u',
        'Û' => 'U',
        'ù' => 'u',
        'Ù' => 'U',
        'ü' => 'u',
        'Ü' => 'U',
    ],
    // German
    'de' => [
        'Ä' => 'Ae',
        'Ö' => 'Oe',
        'Ü' => 'Ue',
        'ä' => 'ae',
        'ö' => 'oe',
        'ü' => 'ue',
        'ß' => 'ss',
        'ẞ' => 'SS',
    ],
    // Austrian (German)
    'de_at' => [
        'Ä' => 'Ae',
        'Ö' => 'Oe',
        'Ü' => 'Ue',
        'ä' => 'ae',
        'ö' => 'oe',
        'ü' => 'ue',
        'ß' => 'sz',
        'ẞ' => 'SZ',
    ],
    // Switzerland (German)
    'de_ch' => [
        'Ä' => 'Ae',
        'Ö' => 'Oe',
        'Ü' => 'Ue',
        'ä' => 'ae',
        'ö' => 'oe',
        'ü' => 'ue',
        'ß' => 'ss',
        'ẞ' => 'SS',
    ],
    // Bengali (Bangla)
    'bn' => [
        'ভ্ল'   => 'vl',
        'পশ'    => 'psh',
        'ব্ধ'   => 'bdh',
        'ব্জ'   => 'bj',
        'ব্দ'   => 'bd',
        'ব্ব'   => 'bb',
        'ব্ল'   => 'bl',
        'ভ'     => 'v',
        'ব'     => 'b',
        'চ্ঞ'   => 'cNG',
        'চ্ছ'   => 'cch',
        'চ্চ'   => 'cc',
        'ছ'     => 'ch',
        'চ'     => 'c',
        'ধ্ন'   => 'dhn',
        'ধ্ম'   => 'dhm',
        'দ্ঘ'   => 'dgh',
        'দ্ধ'   => 'ddh',
        'দ্ভ'   => 'dv',
        'দ্ম'   => 'dm',
        'ড্ড'   => 'DD',
        'ঢ'     => 'Dh',
        'ধ'     => 'dh',
        'দ্গ'   => 'dg',
        'দ্দ'   => 'dd',
        'ড'     => 'D',
        'দ'     => 'd',
        '।'     => '.',
        'ঘ্ন'   => 'Ghn',
        'গ্ধ'   => 'Gdh',
        'গ্ণ'   => 'GN',
        'গ্ন'   => 'Gn',
        'গ্ম'   => 'Gm',
        'গ্ল'   => 'Gl',
        'জ্ঞ'   => 'jNG',
        'ঘ'     => 'Gh',
        'গ'     => 'g',
        'হ্ণ'   => 'hN',
        'হ্ন'   => 'hn',
        'হ্ম'   => 'hm',
        'হ্ল'   => 'hl',
        'হ'     => 'h',
        'জ্ঝ'   => 'jjh',
        'ঝ'     => 'jh',
        'জ্জ'   => 'jj',
        'জ'     => 'j',
        'ক্ষ্ণ' => 'kxN',
        'ক্ষ্ম' => 'kxm',
        'ক্ষ'   => 'ksh',
        'কশ'    => 'ksh',
        'ক্ক'   => 'kk',
        'ক্ট'   => 'kT',
        'ক্ত'   => 'kt',
        'ক্ল'   => 'kl',
        'ক্স'   => 'ks',
        'খ'     => 'kh',
        'ক'     => 'k',
        'ল্ভ'   => 'lv',
        'ল্ধ'   => 'ldh',
        'লখ'    => 'lkh',
        'লঘ'    => 'lgh',
        'লফ'    => 'lph',
        'ল্ক'   => 'lk',
        'ল্গ'   => 'lg',
        'ল্ট'   => 'lT',
        'ল্ড'   => 'lD',
        'ল্প'   => 'lp',
        'ল্ম'   => 'lm',
        'ল্ল'   => 'll',
        'ল্ব'   => 'lb',
        'ল'     => 'l',
        'ম্থ'   => 'mth',
        'ম্ফ'   => 'mf',
        'ম্ভ'   => 'mv',
        'মপ্ল'  => 'mpl',
        'ম্ন'   => 'mn',
        'ম্প'   => 'mp',
        'ম্ম'   => 'mm',
        'ম্ল'   => 'ml',
        'ম্ব'   => 'mb',
        'ম'     => 'm',
        '০'     => '0',
        '১'     => '1',
        '২'     => '2',
        '৩'     => '3',
        '৪'     => '4',
        '৫'     => '5',
        '৬'     => '6',
        '৭'     => '7',
        '৮'     => '8',
        '৯'     => '9',
        'ঙ্ক্ষ' => 'Ngkx',
        'ঞ্ছ'   => 'nch',
        'ঙ্ঘ'   => 'ngh',
        'ঙ্খ'   => 'nkh',
        'ঞ্ঝ'   => 'njh',
        'ঙ্গৌ'  => 'ngOU',
        'ঙ্গৈ'  => 'ngOI',
        'ঞ্চ'   => 'nc',
        'ঙ্ক'   => 'nk',
        'ঙ্ষ'   => 'Ngx',
        'ঙ্গ'   => 'ngo',
        'ঙ্ম'   => 'Ngm',
        'ঞ্জ'   => 'nj',
        'ন্ধ'   => 'ndh',
        'ন্ঠ'   => 'nTh',
        'ণ্ঠ'   => 'NTh',
        'ন্থ'   => 'nth',
        'ঙ্গা'  => 'nga',
        'ঙ্গি'  => 'ngi',
        'ঙ্গী'  => 'ngI',
        'ঙ্গু'  => 'ngu',
        'ঙ্গূ'  => 'ngU',
        'ঙ্গে'  => 'nge',
        'ঙ্গো'  => 'ngO',
        'ণ্ঢ'   => 'NDh',
        'নশ'    => 'nsh',
        'ঙর'    => 'Ngr',
        'ঞর'    => 'NGr',
        'ংর'    => 'ngr',
        'ঙ'     => 'Ng',
        'ঞ'     => 'NG',
        'ং'     => 'ng',
        'ন্ন'   => 'nn',
        'ণ্ণ'   => 'NN',
        'ণ্ন'   => 'Nn',
        'ন্ম'   => 'nm',
        'ণ্ম'   => 'Nm',
        'ন্দ'   => 'nd',
        'ন্ট'   => 'nT',
        'ণ্ট'   => 'NT',
        'ন্ড'   => 'nD',
        'ণ্ড'   => 'ND',
        'ন্ত'   => 'nt',
        'ন্স'   => 'ns',
        'ন'     => 'n',
        'ণ'     => 'N',
        'ৈ'     => 'OI',
        'ৌ'     => 'OU',
        'ো'     => 'O',
        'ঐ'     => 'OI',
        'ঔ'     => 'OU',
        'অ'     => 'o',
        'ও'     => 'oo',
        'ফ্ল'   => 'fl',
        'প্ট'   => 'pT',
        'প্ত'   => 'pt',
        'প্ন'   => 'pn',
        'প্প'   => 'pp',
        'প্ল'   => 'pl',
        'প্স'   => 'ps',
        'ফ'     => 'f',
        'প'     => 'p',
        'ৃ'     => 'rri',
        'ঋ'     => 'rri',
        'রর‍্য' => 'rry',
        '্র্য'  => 'ry',
        '্রর'   => 'rr',
        'ড়্গ'   => 'Rg',
        'ঢ়'     => 'Rh',
        'ড়'     => 'R',
        'র'     => 'r',
        '্র'    => 'r',
        'শ্ছ'   => 'Sch',
        'ষ্ঠ'   => 'ShTh',
        'ষ্ফ'   => 'Shf',
        'স্ক্ল' => 'skl',
        'স্খ'   => 'skh',
        'স্থ'   => 'sth',
        'স্ফ'   => 'sf',
        'শ্চ'   => 'Sc',
        'শ্ত'   => 'St',
        'শ্ন'   => 'Sn',
        'শ্ম'   => 'Sm',
        'শ্ল'   => 'Sl',
        'ষ্ক'   => 'Shk',
        'ষ্ট'   => 'ShT',
        'ষ্ণ'   => 'ShN',
        'ষ্প'   => 'Shp',
        'ষ্ম'   => 'Shm',
        'স্প্ল' => 'spl',
        'স্ক'   => 'sk',
        'স্ট'   => 'sT',
        'স্ত'   => 'st',
        'স্ন'   => 'sn',
        'স্প'   => 'sp',
        'স্ম'   => 'sm',
        'স্ল'   => 'sl',
        'শ'     => 'S',
        'ষ'     => 'Sh',
        'স'     => 's',
        'ু'     => 'u',
        'উ'     => 'u',
        'অ্য'   => 'oZ',
        'ত্থ'   => 'tth',
        'ৎ'     => 'tt',
        'ট্ট'   => 'TT',
        'ট্ম'   => 'Tm',
        'ঠ'     => 'Th',
        'ত্ন'   => 'tn',
        'ত্ম'   => 'tm',
        'থ'     => 'th',
        'ত্ত'   => 'tt',
        'ট'     => 'T',
        'ত'     => 't',
        'অ্যা'  => 'AZ',
        'া'     => 'a',
        'আ'     => 'a',
        'য়া'    => 'ya',
        'য়'     => 'y',
        'ি'     => 'i',
        'ই'     => 'i',
        'ী'     => 'ee',
        'ঈ'     => 'ee',
        'ূ'     => 'uu',
        'ঊ'     => 'uu',
        'ে'     => 'e',
        'এ'     => 'e',
        'য'     => 'z',
        '্য'    => 'Z',
        'ইয়'    => 'y',
        'ওয়'    => 'w',
        '্ব'    => 'w',
        'এক্স'  => 'x',
        'ঃ'     => ':',
        'ঁ'     => 'nn',
        '্‌'    => '',
    ],
    // English
    'en' => [
    ],
    // Latin (+ Cyrillic ?) chars
    //
    // -> Mix of languages, but we need to keep this here, so that different languages can handle there own behavior.
    'latin' => [
        '˚'   => '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',
        '௰'   => '10',
        '௱'   => '100',
        '௲'   => '1000',
        'Ꜳ'   => 'AA',
        'ꜳ'   => 'aa',
        'Æ'   => 'AE',
        'æ'   => 'ae',
        'Ǽ'   => 'AE',
        'ǽ'   => 'ae',
        'Ꜵ'   => 'AO',
        'ꜵ'   => 'ao',
        'Ꜷ'   => 'AU',
        'ꜷ'   => 'au',
        'Ꜹ'   => 'AV',
        'ꜹ'   => 'av',
        'Ꜻ'   => 'av',
        'ꜻ'   => 'av',
        'Ꜽ'   => 'AY',
        'ꜽ'   => 'ay',
        'ȸ'   => 'db',
        'ʣ'   => 'dz',
        'ʥ'   => 'dz',
        'ʤ'   => 'dezh',
        '🙰'   => 'et',
        'ﬀ'   => 'ff',
        'ﬃ'   => 'ffi',
        'ﬄ'   => 'ffl',
        'ﬁ'   => 'fi',
        'ﬂ'   => 'fl',
        'ʩ'   => 'feng',
        'Ĳ'   => 'IJ',
        'ĳ'   => 'ij',
        'ʪ'   => 'ls',
        'ʫ'   => 'lz',
        'ɮ'   => 'lezh',
        'ȹ'   => 'qp',
        'ʨ'   => 'tc',
        'ʦ'   => 'ts',
        'ʧ'   => 'tesh',
        'Œ'   => 'OE',
        'œ'   => 'oe',
        'Ꝏ'   => 'OO',
        'ꝏ'   => 'oo',
        'ẞ'   => 'SS',
        'ß'   => 'ss',
        'ﬆ'   => 'st',
        'ﬅ'   => 'st',
        'Ꜩ'   => 'TZ',
        'ꜩ'   => 'tz',
        'ᵫ'   => 'ue',
        'Aι'  => 'Ai',
        'αι'  => 'ai',
        'Ει'  => 'Ei',
        'ει'  => 'ei',
        'Οι'  => 'Oi',
        'οι'  => 'oi',
        'Ου'  => 'Oy',
        'ου'  => 'oy',
        'Υι'  => 'Yi',
        'υι'  => 'yi',
        'ἀ'   => 'a',
        'ἁ'   => 'a',
        'ἂ'   => 'a',
        'ἃ'   => 'a',
        'ἄ'   => 'a',
        'ἅ'   => 'a',
        'ἆ'   => 'a',
        'ἇ'   => 'a',
        'Ἀ'   => 'A',
        'Ἁ'   => 'A',
        'Ἂ'   => 'A',
        'Ἃ'   => 'A',
        'Ἄ'   => 'A',
        'Ἅ'   => 'A',
        'Ἆ'   => 'A',
        'Ἇ'   => 'A',
        'ᾰ'   => 'a',
        'ᾱ'   => 'a',
        'ᾲ'   => 'a',
        'ᾳ'   => 'a',
        'ᾴ'   => 'a',
        'ᾶ'   => 'a',
        'ᾷ'   => 'a',
        'Ᾰ'   => 'A',
        'Ᾱ'   => 'A',
        'Ὰ'   => 'A',
        'Ά'   => 'A',
        'ᾼ'   => 'A',
        'Ä'   => 'A',
        'ä'   => 'a',
        'À'   => 'A',
        'à'   => 'a',
        'Á'   => 'A',
        'á'   => 'a',
        'Â'   => 'A',
        'â'   => 'a',
        'Ã'   => 'A',
        'ã'   => 'a',
        'A̧'  => 'A',
        'a̧'  => 'a',
        'Ą'   => 'A',
        'ą'   => 'a',
        'Ⱥ'   => 'A',
        'ⱥ'   => 'a',
        'Å'   => 'A',
        'å'   => 'a',
        'Ǻ'   => 'A',
        'ǻ'   => 'a',
        'Ă'   => 'A',
        'ă'   => 'a',
        'Ǎ'   => 'A',
        'ǎ'   => 'a',
        'Ȧ'   => 'A',
        'ȧ'   => 'a',
        'Ạ'   => 'A',
        'ạ'   => 'a',
        'Ā'   => 'A',
        'ā'   => 'a',
        'ª'   => 'a',
        'Ɓ'   => 'B',
        'Ѣ'   => 'E',
        'ѣ'   => 'e',
        'Ç'   => 'C',
        'ç'   => 'c',
        'Ĉ'   => 'C',
        'ĉ'   => 'c',
        'C̈'  => 'C',
        'c̈'  => 'c',
        'C̨'  => 'C',
        'c̨'  => 'c',
        'Ȼ'   => 'C',
        'ȼ'   => 'c',
        'Č'   => 'C',
        'č'   => 'c',
        'Ć'   => 'C',
        'ć'   => 'c',
        'C̀'  => 'C',
        'c̀'  => 'c',
        'Ċ'   => 'C',
        'ċ'   => 'c',
        'C̣'  => 'C',
        'c̣'  => 'c',
        'C̄'  => 'C',
        'c̄'  => 'c',
        'C̃'  => 'C',
        'c̃'  => 'c',
        'Ð'   => 'D',
        'Đ'   => 'D',
        'ð'   => 'd',
        'đ'   => 'd',
        'È'   => 'E',
        'É'   => 'E',
        'Ê'   => 'E',
        'Ë'   => 'E',
        'Ĕ'   => 'E',
        'Ė'   => 'E',
        'Ȩ'   => 'E',
        'ȩ'   => 'e',
        'Ę'   => 'E',
        'ę'   => 'e',
        'Ɇ'   => 'E',
        'ɇ'   => 'e',
        'Ě'   => 'E',
        'ě'   => 'e',
        'Ẹ'   => 'E',
        'ẹ'   => 'e',
        'Ē'   => 'E',
        'ē'   => 'e',
        'Ẽ'   => 'E',
        'ẽ'   => 'e',
        'è'   => 'e',
        'é'   => 'e',
        'ê'   => 'e',
        'ë'   => 'e',
        'ĕ'   => 'e',
        'ė'   => 'e',
        'ƒ'   => 'f',
        'Ѳ'   => 'F',
        'ѳ'   => 'f',
        'Ĝ'   => 'G',
        'Ġ'   => 'G',
        'ĝ'   => 'g',
        'ġ'   => 'g',
        'Ĥ'   => 'H',
        'Ħ'   => 'H',
        'ĥ'   => 'h',
        'ħ'   => 'h',
        'Ì'   => 'I',
        'Í'   => 'I',
        'Î'   => 'I',
        'Ï'   => 'I',
        'Ĩ'   => 'I',
        'Ĭ'   => 'I',
        'Ǐ'   => 'I',
        'Į'   => 'I',
        'ì'   => 'i',
        'í'   => 'i',
        'î'   => 'i',
        'ï'   => 'i',
        'ĩ'   => 'i',
        'ĭ'   => 'i',
        'ǐ'   => 'i',
        'į'   => 'i',
        'І'   => 'I',
        'і'   => 'i',
        'I̧'  => 'I',
        'i̧'  => 'i',
        'Ɨ'   => 'I',
        'ɨ'   => 'i',
        'İ'   => 'I',
        'i'   => 'i',
        'Ị'   => 'I',
        'ị'   => 'i',
        'Ī'   => 'I',
        'ī'   => 'i',
        'Ĵ'   => 'J',
        'ĵ'   => 'j',
        'J́́' => 'J',
        'j́'  => 'j',
        'J̀̀' => 'J',
        'j̀'  => 'j',
        'J̈'  => 'J',
        'j̈'  => 'j',
        'J̧'  => 'J',
        'j̧'  => 'j',
        'J̨'  => 'J',
        'j̨'  => 'j',
        'Ɉ'   => 'J',
        'ɉ'   => 'j',
        'J̌'  => 'J',
        'ǰ'   => 'j',
        'J̇'  => 'J',
        'j'   => 'j',
        'J̣'  => 'J',
        'j̣'  => 'j',
        'J̄'  => 'J',
        'j̄'  => 'j',
        'J̃'  => 'J',
        'j̃'  => 'j',
        'Й' => 'i',
        'й' => 'i',
        'ĸ'   => 'k',
        'Ĺ'   => 'L',
        'Ľ'   => 'L',
        'Ŀ'   => 'L',
        'ĺ'   => 'l',
        'ľ'   => 'l',
        'ŀ'   => 'l',
        'L̀'  => 'L',
        'l̀'  => 'l',
        'L̂'  => 'L',
        'l̂'  => 'l',
        'L̈'  => 'L',
        'l̈'  => 'l',
        'Ļ'   => 'L',
        'ļ'   => 'l',
        'L̨'  => 'L',
        'l̨'  => 'l',
        'Ł'   => 'L',
        'ł'   => 'l',
        'Ƚ'   => 'L',
        'ƚ'   => 'l',
        'L̇'  => 'L',
        'l̇'  => 'l',
        'Ḷ'   => 'L',
        'ḷ'   => 'l',
        'L̄'  => 'L',
        'l̄'  => 'l',
        'L̃'  => 'L',
        'l̃'  => 'l',
        'Ñ'   => 'N',
        'ñ'   => 'n',
        'Ŋ'   => 'N',
        'ŋ'   => 'n',
        'ŉ'   => 'n',
        'Ń'   => 'N',
        'ń'   => 'n',
        'Ǹ'   => 'N',
        'ǹ'   => 'n',
        'N̂'  => 'N',
        'n̂'  => 'n',
        'N̈'  => 'N',
        'n̈'  => 'n',
        'Ņ'   => 'N',
        'ņ'   => 'n',
        'N̨'  => 'N',
        'n̨'  => 'n',
        'Ꞥ'   => 'N',
        'ꞥ'   => 'n',
        'Ň'   => 'N',
        'ň'   => 'n',
        'Ṅ'   => 'N',
        'ṅ'   => 'n',
        'Ṇ'   => 'N',
        'ṇ'   => 'n',
        'N̄'  => 'N',
        'n̄'  => 'n',
        'Ö'   => 'O',
        'Ò'   => 'O',
        'Ó'   => 'O',
        'Ô'   => 'O',
        'Õ'   => 'O',
        'Ō'   => 'O',
        'Ŏ'   => 'O',
        'Ǒ'   => 'O',
        'Ő'   => 'O',
        'Ơ'   => 'O',
        'Ø'   => 'O',
        'Ǿ'   => 'O',
        'ö'   => 'o',
        'ò'   => 'o',
        'ó'   => 'o',
        'ô'   => 'o',
        'õ'   => 'o',
        'ō'   => 'o',
        'ŏ'   => 'o',
        'ǒ'   => 'o',
        'ő'   => 'o',
        'ơ'   => 'o',
        'ø'   => 'o',
        'ǿ'   => 'o',
        'º'   => 'o',
        'O̧'  => 'O',
        'o̧'  => 'o',
        'Ǫ'   => 'O',
        'ǫ'   => 'o',
        'Ɵ'   => 'O',
        'ɵ'   => 'o',
        'Ȯ'   => 'O',
        'ȯ'   => 'o',
        'Ọ'   => 'O',
        'ọ'   => 'o',
        'Ŕ'   => 'R',
        'Ŗ'   => 'R',
        'ŕ'   => 'r',
        'ŗ'   => 'r',
        'Ŝ'   => 'S',
        'Ș'   => 'S',
        'ș'   => 's',
        'Ś'   => 'S',
        'ś'   => 's',
        'S̀'  => 'S',
        's̀'  => 's',
        'Ŝ̀'  => 'S',
        'ŝ'   => 's',
        'S̈'  => 'S',
        's̈'  => 's',
        'Ş'   => 'S',
        'ş'   => 's',
        'S̨'  => 'S',
        's̨'  => 's',
        'Ꞩ'   => 'S',
        'ꞩ'   => 's',
        'Š'   => 'S',
        'š'   => 's',
        'Ṡ'   => 'S',
        'ṡ'   => 's',
        'Ṣ'   => 'S',
        'ṣ'   => 's',
        'S̄'  => 'S',
        's̄'  => 's',
        'S̃'  => 'S',
        's̃'  => 's',
        'ſ'   => 's',
        'Ţ'   => 'T',
        'Ț'   => 'T',
        'Ŧ'   => 'T',
        'Þ'   => 'TH',
        'ţ'   => 't',
        'ț'   => 't',
        'ŧ'   => 't',
        'þ'   => 'th',
        'T́'  => 'T',
        't́'  => 't',
        'T̀'  => 'T',
        't̀'  => 't',
        'T̂'  => 'T',
        't̂'  => 't',
        'T̈'  => 'T',
        'ẗ'   => 't',
        'T̨'  => 'T',
        't̨'  => 't',
        'Ⱦ'   => 'T',
        'ⱦ'   => 't',
        'Ť'   => 'T',
        'ť'   => 't',
        'Ṫ'   => 'T',
        'ṫ'   => 't',
        'Ṭ'   => 'T',
        'ṭ'   => 't',
        'T̄'  => 'T',
        't̄'  => 't',
        'T̃'  => 'T',
        't̃'  => 't',
        'Ü'   => 'U',
        'Ù'   => 'U',
        'Ú'   => 'U',
        'Û'   => 'U',
        'Ũ'   => 'U',
        'Ŭ'   => 'U',
        'Ű'   => 'U',
        'Ų'   => 'U',
        'Ư'   => 'U',
        'Ǔ'   => 'U',
        'Ǖ'   => 'U',
        'Ǘ'   => 'U',
        'Ǚ'   => 'U',
        'Ǜ'   => 'U',
        'ü'   => 'u',
        'ù'   => 'u',
        'ú'   => 'u',
        'û'   => 'u',
        'ũ'   => 'u',
        'ŭ'   => 'u',
        'ű'   => 'u',
        'ų'   => 'u',
        'ư'   => 'u',
        'ǔ'   => 'u',
        'ǖ'   => 'u',
        'ǘ'   => 'u',
        'ǚ'   => 'u',
        'ǜ'   => 'u',
        'U̧'  => 'U',
        'u̧'  => 'u',
        'Ʉ'   => 'U',
        'ʉ'   => 'u',
        'U̇'  => 'U',
        'u̇'  => 'u',
        'Ụ'   => 'U',
        'ụ'   => 'u',
        'Ū'   => 'U',
        'ū'   => 'u',
        'Ʊ'   => 'U',
        'ʊ'   => 'u',
        'Ŵ'   => 'W',
        'ŵ'   => 'w',
        'Ẁ'   => 'W',
        'ẁ'   => 'w',
        'Ẃ'   => 'W',
        'ẃ'   => 'w',
        'Ẅ'   => 'W',
        'ẅ'   => 'w',
        'Ѵ'   => 'I',
        'ѵ'   => 'i',
        'Ꙗ'   => 'Ja',
        'ꙗ'   => 'ja',
        'Є'   => 'Je',
        'є'   => 'je',
        'Ѥ'   => 'Je',
        'ѥ'   => 'je',
        'Ѕ'   => 'Dz',
        'ѕ'   => 'dz',
        'Ꙋ'   => 'U',
        'ꙋ'   => 'u',
        'Ѡ'   => 'O',
        'ѡ'   => 'o',
        'Ѿ'   => 'Ot',
        'ѿ'   => 'ot',
        'Ѫ'   => 'U',
        'ѫ'   => 'u',
        'Ѧ'   => 'Ja',
        'ѧ'   => 'ja',
        'Ѭ'   => 'Ju',
        'ѭ'   => 'ju',
        'Ѩ'   => 'Ja',
        'ѩ'   => 'Ja',
        'Ѯ'   => 'Ks',
        'ѯ'   => 'ks',
        'Ѱ'   => 'Ps',
        'ѱ'   => 'ps',
        'Х'   => 'X',
        'х'   => 'x',
        'Ý'   => 'Y',
        'Ÿ'   => 'Y',
        'Ŷ'   => 'Y',
        'ý'   => 'y',
        'ÿ'   => 'y',
        'ŷ'   => 'y',
        'Ỳ'   => 'Y',
        'ỳ'   => 'y',
        'Y̧'  => 'Y',
        'y̧'  => 'y',
        'Y̨'  => 'Y',
        'y̨'  => 'y',
        'Ɏ'   => 'Y',
        'ɏ'   => 'y',
        'Y̌'  => 'Y',
        'y̌'  => 'y',
        'Ẏ'   => 'Y',
        'ẏ'   => 'y',
        'Ỵ'   => 'Y',
        'ỵ'   => 'y',
        'Ȳ'   => 'Y',
        'ȳ'   => 'y',
        'Ỹ'   => 'Y',
        'ỹ'   => 'y',
        'Щ' => 'Shh',
        'щ' => 'shh',
        'Ź'   => 'Z',
        'ź'   => 'z',
        'Z̀'  => 'Z',
        'z̀'  => 'z',
        'Ẑ'   => 'Z',
        'ẑ'   => 'z',
        'Z̈'  => 'Z',
        'z̈'  => 'z',
        'Z̧'  => 'Z',
        'z̧'  => 'z',
        'Z̨'  => 'Z',
        'z̨'  => 'z',
        'Ƶ'   => 'Z',
        'ƶ'   => 'z',
        'Ž'   => 'Z',
        'ž'   => 'z',
        'Ż'   => 'Z',
        'ż'   => 'z',
        'Ẓ'   => 'Z',
        'ẓ'   => 'z',
        'Z̄'  => 'Z',
        'z̄'  => 'z',
        'Z̃'  => 'Z',
        'z̃'  => 'z',
    ],
    // whitespace chars
    ' ' => [
        "\xc2\xa0"     => ' ', // 'NO-BREAK SPACE'
        "\xe1\x9a\x80" => ' ', // 'OGHAM SPACE MARK'
        "\xe2\x80\x80" => ' ', // 'EN QUAD'
        "\xe2\x80\x81" => ' ', // 'EM QUAD'
        "\xe2\x80\x82" => ' ', // 'EN SPACE'
        "\xe2\x80\x83" => ' ', // 'EM SPACE'
        "\xe2\x80\x84" => ' ', // 'THREE-PER-EM SPACE'
        "\xe2\x80\x85" => ' ', // 'FOUR-PER-EM SPACE'
        "\xe2\x80\x86" => ' ', // 'SIX-PER-EM SPACE'
        "\xe2\x80\x87" => ' ', // 'FIGURE SPACE'
        "\xe2\x80\x88" => ' ', // 'PUNCTUATION SPACE'
        "\xe2\x80\x89" => ' ', // 'THIN SPACE'
        "\xe2\x80\x8a" => ' ', // 'HAIR SPACE'
        "\xe2\x80\xa8" => ' ', // 'LINE SEPARATOR'
        "\xe2\x80\xa9" => ' ', // 'PARAGRAPH SEPARATOR'
        "\xe2\x80\x8b" => ' ', // 'ZERO WIDTH SPACE'
        "\xe2\x80\xaf" => ' ', // 'NARROW NO-BREAK SPACE'
        "\xe2\x81\x9f" => ' ', // 'MEDIUM MATHEMATICAL SPACE'
        "\xe3\x80\x80" => ' ', // 'IDEOGRAPHIC SPACE'
        "\xef\xbe\xa0" => ' ', // 'HALFWIDTH HANGUL FILLER'
    ],
    // commonly used in Word documents
    'msword' => [
        "\xc2\xab"     => '<<', // « (U+00AB) in UTF-8
        "\xc2\xbb"     => '>>', // » (U+00BB) in UTF-8
        "\xe2\x80\x98" => "'", // ‘ (U+2018) in UTF-8
        "\xe2\x80\x99" => "'", // ’ (U+2019) in UTF-8
        "\xe2\x80\x9a" => "'", // ‚ (U+201A) in UTF-8
        "\xe2\x80\x9b" => "'", // ‛ (U+201B) in UTF-8
        "\xe2\x80\x9c" => '"', // “ (U+201C) in UTF-8
        "\xe2\x80\x9d" => '"', // ” (U+201D) in UTF-8
        "\xe2\x80\x9e" => '"', // „ (U+201E) in UTF-8
        "\xe2\x80\x9f" => '"', // ‟ (U+201F) in UTF-8
        "\xe2\x80\xb9" => "'", // ‹ (U+2039) in UTF-8
        "\xe2\x80\xba" => "'", // › (U+203A) in UTF-8
        "\xe2\x80\x93" => '-', // – (U+2013) in UTF-8
        "\xe2\x80\x94" => '-', // — (U+2014) in UTF-8
        "\xe2\x80\xa6" => '...', // … (U+2026) in UTF-8
    ],
    // Currency
    //
    // url => https://en.wikipedia.org/wiki/Currency_symbol
    'currency_short' => [
        '€'  => 'EUR',
        '$'  => '$',
        '₢'  => 'Cr',
        '₣'  => 'Fr.',
        '£'  => 'PS',
        '₤'  => 'L.',
        'ℳ'  => 'M',
        '₥'  => 'mil',
        '₦'  => 'N',
        '₧'  => 'Pts',
        '₨'  => 'Rs',
        'රු' => 'LKR',
        'ரூ' => 'LKR',
        '௹'  => 'Rs',
        'रू' => 'NPR',
        '₹'  => 'Rs',
        '૱'  => 'Rs',
        '₩'  => 'W',
        '₪'  => 'NS',
        '₸'  => 'KZT',
        '₫'  => 'D',
        '֏'  => 'AMD',
        '₭'  => 'K',
        '₺'  => 'TL',
        '₼'  => 'AZN',
        '₮'  => 'T',
        '₯'  => 'Dr',
        '₲'  => 'PYG',
        '₾'  => 'GEL',
        '₳'  => 'ARA',
        '₴'  => 'UAH',
        '₽'  => 'RUB',
        '₵'  => 'GHS',
        '₡'  => 'CL',
        '¢'  => 'c',
        '¥'  => 'YEN',
        '円'  => 'JPY',
        '৳'  => 'BDT',
        '元'  => 'CNY',
        '﷼'  => 'SAR',
        '៛'  => 'KR',
        '₠'  => 'ECU',
        '¤'  => '$?',
        '฿'  => 'THB',
        '؋'  => 'AFN',
    ],
];
<?php

return [
    // Dutch (Flemish)
    'nl' => [
        '=' => ' gelijk ',
        '%' => ' procent ',
        '∑' => ' som ',
        '∆' => ' delta ',
        '∞' => ' oneindig ',
        '♥' => ' love ',
        '&' => ' en ',
        '+' => ' plus ',
    ],
    // Italian
    'it' => [
        '=' => ' uguale ',
        '%' => ' percent ',
        '∑' => ' somma ',
        '∆' => ' delta ',
        '∞' => ' infinito ',
        '♥' => ' amore ',
        '&' => ' e ',
        '+' => ' piu ',
    ],
    // Macedonian
    'mk' => [
        '=' => ' ednakva ',
        '%' => ' procenti ',
        '∑' => ' zbir ',
        '∆' => ' delta ',
        '∞' => ' beskonecnost ',
        '♥' => ' loveubov ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Portuguese (Brazil)
    'pt' => [
        '=' => ' igual ',
        '%' => ' por cento ',
        '∑' => ' soma ',
        '∆' => ' delta ',
        '∞' => ' infinito ',
        '♥' => ' amor ',
        '&' => ' e ',
        '+' => ' mais ',
    ],
    // Greek(lish) (Elláda)
    'el__greeklish' => [
        '=' => ' isos ',
        '%' => ' tois ekato ',
        '∑' => ' athroisma ',
        '∆' => ' delta ',
        '∞' => ' apeiro ',
        '♥' => ' agape ',
        '&' => ' kai ',
        '+' => ' syn ',
    ],
    // Greek (Elláda)
    'el' => [
        '=' => ' isos ',
        '%' => ' tois ekato ',
        '∑' => ' athroisma ',
        '∆' => ' delta ',
        '∞' => ' apeiro ',
        '♥' => ' agape ',
        '&' => ' kai ',
        '+' => ' syn ',
    ],
    // Hindi
    'hi' => [
        '=' => ' samana ',
        '%' => ' paratisata ',
        '∑' => ' yoga ',
        '∆' => ' dalata ',
        '∞' => ' anata ',
        '♥' => ' payara ',
        '&' => ' aura ',
        '+' => ' palasa ',
    ],
    // Armenian
    'hy' => [
        '=' => ' havasar ',
        '%' => ' tvokvos ',
        '∑' => ' gvoumar ',
        '∆' => ' delta ',
        '∞' => ' ansahmanvouthyvoun ',
        '♥' => ' ser ',
        '&' => ' ev ',
        '+' => ' gvoumarats ',
    ],
    // Swedish
    'sv' => [
        '=' => ' lika ',
        '%' => ' procent ',
        '∑' => ' summa ',
        '∆' => ' delta ',
        '∞' => ' oandlighet ',
        '♥' => ' alskar ',
        '&' => ' och ',
        '+' => ' plus ',
    ],
    // Turkmen
    'tk' => [
        '=' => ' den ',
        '%' => ' yuzde ',
        '∑' => ' jem ',
        '∆' => ' delta ',
        '∞' => ' mudimilik ',
        '♥' => ' soygi ',
        '&' => ' we ',
        '+' => ' yzy ',
    ],
    // Turkish
    'tr' => [
        '=' => ' esit ',
        '%' => ' yuzde ',
        '∑' => ' Toplam ',
        '∆' => ' delta ',
        '∞' => ' sonsuzluk ',
        '♥' => ' ask ',
        '&' => ' ve ',
        '+' => ' arti ',
    ],
    // Bulgarian
    'bg' => [
        '=' => ' raven ',
        '%' => ' na sto ',
        '∑' => ' suma ',
        '∆' => ' delta ',
        '∞' => ' bezkrajnost ',
        '♥' => ' obicam ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Hungarian
    'hu' => [
        '=' => ' Egyenlo ',
        '%' => ' Szazalek ',
        '∑' => ' osszeg ',
        '∆' => ' delta ',
        '∞' => ' vegtelenitett ',
        '♥' => ' love ',
        '&' => ' Es ',
        '+' => ' Plusz ',
    ],
    // Myanmar (Burmese)
    'my' => [
        '=' => ' ttn:ttnnym? ',
        '%' => ' raakhngnn:k ',
        '∑' => ' ld ',
        '∆' => ' m?cwk?n:pe? ',
        '∞' => ' ach:m ',
        '♥' => ' mettttaa ',
        '&' => ' n ',
        '+' => ' ape?ng: ',
    ],
    // Croatian (Hrvatska)
    'hr' => [
        '=' => ' Jednaki ',
        '%' => ' Posto ',
        '∑' => ' zbroj ',
        '∆' => ' Delta ',
        '∞' => ' beskonacno ',
        '♥' => ' ljubav ',
        '&' => ' I ',
        '+' => ' Plus ',
    ],
    // Finnish
    'fi' => [
        '=' => ' Sama ',
        '%' => ' Prosenttia ',
        '∑' => ' sum ',
        '∆' => ' delta ',
        '∞' => ' aareton ',
        '♥' => ' rakkautta ',
        '&' => ' Ja ',
        '+' => ' Plus ',
    ],
    // Georgian (Kartvelian)
    'ka' => [
        '=' => ' tanasts\'ori ',
        '%' => ' p\'rotsent\'i ',
        '∑' => ' tankha ',
        '∆' => ' delt\'a ',
        '∞' => ' usasrulo ',
        '♥' => ' siq\'varuli ',
        '&' => ' da ',
        '+' => ' p\'lus ',
    ],
    // Russian
    'ru' => [
        '=' => ' ravnyj ',
        '%' => ' procent ',
        '∑' => ' summa ',
        '∆' => ' del\'ta ',
        '∞' => ' beskonecnost\' ',
        '♥' => ' lublu ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Russian - GOST 7.79-2000(B)
    'ru__gost_2000_b' => [
        '=' => ' ravnyj ',
        '%' => ' procent ',
        '∑' => ' summa ',
        '∆' => ' del\'ta ',
        '∞' => ' beskonecnost\' ',
        '♥' => ' lublu ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Russian - Passport (2013), ICAO
    'ru__passport_2013' => [
        '=' => ' ravnyj ',
        '%' => ' procent ',
        '∑' => ' summa ',
        '∆' => ' del\'ta ',
        '∞' => ' beskonecnost\' ',
        '♥' => ' lublu ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Ukrainian
    'uk' => [
        '=' => ' rivnij ',
        '%' => ' vidsotkiv ',
        '∑' => ' suma ',
        '∆' => ' del\'ta ',
        '∞' => ' neskincennist\' ',
        '♥' => ' lubov ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Kazakh
    'kk' => [
        '=' => ' ten\' ',
        '%' => ' Pajyzdar ',
        '∑' => ' zalpy ',
        '∆' => ' ajyrmasylyk, ',
        '∞' => ' seksiz ',
        '♥' => ' mahabbat ',
        '&' => ' z@ne ',
        '+' => ' plus ',
    ],
    // Czech
    'cs' => [
        '=' => ' rovnat se ',
        '%' => ' procento ',
        '∑' => ' soucet ',
        '∆' => ' delta ',
        '∞' => ' nekonecno ',
        '♥' => ' laska ',
        '&' => ' a ',
        '+' => ' plus ',
    ],
    // Danish
    'da' => [
        '=' => ' Lige ',
        '%' => ' Prozent ',
        '∑' => ' sum ',
        '∆' => ' delta ',
        '∞' => ' uendelig ',
        '♥' => ' kaerlighed ',
        '&' => ' Og ',
        '+' => ' Plus ',
    ],
    // Polish
    'pl' => [
        '=' => ' rowny ',
        '%' => ' procent ',
        '∑' => ' suma ',
        '∆' => ' delta ',
        '∞' => ' nieskonczonosc ',
        '♥' => ' milosc ',
        '&' => ' i ',
        '+' => ' plus ',
    ],
    // Romanian
    'ro' => [
        '=' => ' egal ',
        '%' => ' la suta ',
        '∑' => ' suma ',
        '∆' => ' delta ',
        '∞' => ' infinit ',
        '♥' => ' dragoste ',
        '&' => ' si ',
        '+' => ' la care se adauga ',
    ],
    // Esperanto
    'eo' => [
        '=' => ' Egalaj ',
        '%' => ' Procento ',
        '∑' => ' sumo ',
        '∆' => ' delto ',
        '∞' => ' senfina ',
        '♥' => ' amo ',
        '&' => ' Kaj ',
        '+' => ' Pli ',
    ],
    // Estonian
    'et' => [
        '=' => ' Vordsed ',
        '%' => ' Protsenti ',
        '∑' => ' summa ',
        '∆' => ' o ',
        '∞' => ' loputut ',
        '♥' => ' armastus ',
        '&' => ' Ja ',
        '+' => ' Pluss ',
    ],
    // Latvian
    'lv' => [
        '=' => ' vienads ',
        '%' => ' procents ',
        '∑' => ' summa ',
        '∆' => ' delta ',
        '∞' => ' bezgaliba ',
        '♥' => ' milestiba ',
        '&' => ' un ',
        '+' => ' pluss ',
    ],
    // Lithuanian
    'lt' => [
        '=' => ' lygus ',
        '%' => ' procentu ',
        '∑' => ' suma ',
        '∆' => ' delta ',
        '∞' => ' begalybe ',
        '♥' => ' meile ',
        '&' => ' ir ',
        '+' => ' plius ',
    ],
    // Norwegian
    'no' => [
        '=' => ' Lik ',
        '%' => ' Prosent ',
        '∑' => ' sum ',
        '∆' => ' delta ',
        '∞' => ' uendelig ',
        '♥' => ' kjaerlighet ',
        '&' => ' Og ',
        '+' => ' Pluss ',
    ],
    // Vietnamese
    'vi' => [
        '=' => ' cong bang ',
        '%' => ' phan tram ',
        '∑' => ' tong so ',
        '∆' => ' dong bang ',
        '∞' => ' vo cuc ',
        '♥' => ' Yeu ',
        '&' => ' va ',
        '+' => ' them ',
    ],
    // Arabic
    'ar' => [
        '=' => ' mtsawy ',
        '%' => ' nsbh mywyh ',
        '∑' => ' mjmw\' ',
        '∆' => ' dlta ',
        '∞' => ' ma la nhayt ',
        '♥' => ' hb ',
        '&' => ' w ',
        '+' => ' zayd ',
    ],
    // Persian (Farsi)
    'fa' => [
        '=' => ' brabr ',
        '%' => ' dr sd ',
        '∑' => ' mjmw\' ',
        '∆' => ' dlta ',
        '∞' => ' by nhayt ',
        '♥' => ' \'shq ',
        '&' => ' w ',
        '+' => ' bh \'lawh ',
    ],
    // Serbian
    'sr' => [
        '=' => ' jednak ',
        '%' => ' procenat ',
        '∑' => ' zbir ',
        '∆' => ' delta ',
        '∞' => ' beskraj ',
        '♥' => ' lubav ',
        '&' => ' i ',
        '+' => ' vise ',
    ],
    // Serbian - Cyrillic
    'sr__cyr' => [
        '=' => ' jednak ',
        '%' => ' procenat ',
        '∑' => ' zbir ',
        '∆' => ' delta ',
        '∞' => ' beskraj ',
        '♥' => ' lubav ',
        '&' => ' i ',
        '+' => ' vise ',
    ],
    // Serbian - Latin
    'sr__lat' => [
        '=' => ' jednak ',
        '%' => ' procenat ',
        '∑' => ' zbir ',
        '∆' => ' delta ',
        '∞' => ' beskraj ',
        '♥' => ' lubav ',
        '&' => ' i ',
        '+' => ' vise ',
    ],
    // Azerbaijani
    'az' => [
        '=' => ' b@rab@r ',
        '%' => ' faiz ',
        '∑' => ' m@bl@g ',
        '∆' => ' delta ',
        '∞' => ' sonsuzluq ',
        '♥' => ' sevgi ',
        '&' => ' v@ ',
        '+' => ' plus ',
    ],
    // Slovak
    'sk' => [
        '=' => ' rovny ',
        '%' => ' percento ',
        '∑' => ' sucet ',
        '∆' => ' delta ',
        '∞' => ' infinity ',
        '♥' => ' milovat ',
        '&' => ' a ',
        '+' => ' viac ',
    ],
    // French
    'fr' => [
        '=' => ' Egal ',
        '%' => ' Pourcentage ',
        '∑' => ' somme ',
        '∆' => ' delta ',
        '∞' => ' infini ',
        '♥' => ' amour ',
        '&' => ' Et ',
        '+' => ' Plus ',
    ],
    // Austrian (French)
    'fr_at' => [
        '=' => ' Egal ',
        '%' => ' Pourcentage ',
        '∑' => ' somme ',
        '∆' => ' delta ',
        '∞' => ' infini ',
        '♥' => ' amour ',
        '&' => ' Et ',
        '+' => ' Plus ',
    ],
    // Switzerland (French)
    'fr_ch' => [
        '=' => ' Egal ',
        '%' => ' Pourcentage ',
        '∑' => ' somme ',
        '∆' => ' delta ',
        '∞' => ' infini ',
        '♥' => ' amour ',
        '&' => ' Et ',
        '+' => ' Plus ',
    ],
    // German
    'de' => [
        '=' => ' gleich ',
        '%' => ' Prozent ',
        '∑' => ' gesamt ',
        '∆' => ' Unterschied ',
        '∞' => ' undendlich ',
        '♥' => ' liebe ',
        '&' => ' und ',
        '+' => ' plus ',
    ],
    // Austrian (German)
    'de_at' => [
        '=' => ' gleich ',
        '%' => ' Prozent ',
        '∑' => ' gesamt ',
        '∆' => ' Unterschied ',
        '∞' => ' undendlich ',
        '♥' => ' liebe ',
        '&' => ' und ',
        '+' => ' plus ',
    ],
    // Switzerland (German)
    'de_ch' => [
        '=' => ' gleich ',
        '%' => ' Prozent ',
        '∑' => ' gesamt ',
        '∆' => ' Unterschied ',
        '∞' => ' undendlich ',
        '♥' => ' liebe ',
        '&' => ' und ',
        '+' => ' plus ',
    ],
    // Bengali (Bangla)
    'bn' => [
        '=' => ' Saman ',
        '%' => ' Satakora ',
        '∑' => ' Samasti ',
        '∆' => ' Badhip ',
        '∞' => ' Ananta ',
        '♥' => ' Valobasa ',
        '&' => ' Abong ',
        '+' => ' Songzojon ',
    ],
    // English
    'en' => [
        '=' => ' equal ',
        '%' => ' percent ',
        '∑' => ' sum ',
        '∆' => ' delta ',
        '∞' => ' infinity ',
        '♥' => ' love ',
        '&' => ' and ',
        '+' => ' plus ',
    ],
    // Currency
    //
    // url: https://en.wikipedia.org/wiki/Currency_symbol
    'currency' => [
        '€'  => ' Euro ',
        '$'  => ' Dollar ',
        '₢'  => ' cruzeiro ',
        '₣'  => ' French franc ',
        '£'  => ' pound ',
        '₤'  => ' lira ', // Italian
        '₶'  => ' livre tournois ',
        'ℳ'  => ' mark ',
        '₥'  => ' mill ',
        '₦'  => ' naira ',
        '₧'  => ' peseta ',
        '₨'  => ' rupee ',
        'රු' => ' rupee ', // Sri Lankan
        'ரூ' => ' rupee ', // Sri Lankan
        '௹'  => ' rupee ', // Tamil
        'रू' => ' rupee ', // Nepalese
        '₹'  => ' rupee ', // Indian
        '૱'  => ' rupee ', // Gujarat
        '₩'  => ' won ',
        '₪'  => ' new shequel ',
        '₸'  => ' tenge ',
        '₫'  => ' dong ',
        '֏'  => ' dram ',
        '₭'  => ' kip ',
        '₺'  => ' lira ', // Turkish
        '₼'  => ' manat ',
        '₮'  => ' tugrik ',
        '₯'  => ' drachma ',
        '₰'  => ' pfennig ',
        '₷'  => ' spesmilo ',
        '₱'  => ' peso ', // Philippine
        '﷼‎' => ' riyal ',
        '₲'  => ' guarani ',
        '₾'  => ' lari ',
        '₳'  => ' austral ',
        '₴'  => ' hryvnia ',
        '₽'  => ' ruble ',
        '₵'  => ' cedi ',
        '₡'  => ' colon ',
        '¢'  => ' cent ',
        '¥'  => ' yen ',
        '円'  => ' yen ',
        '৳'  => ' taka ',
        '元'  => ' yuan ',
        '﷼'  => ' riyal ',
        '៛'  => ' riel ',
        '₠'  => ' European Currency ',
        '¤'  => ' currency ',
        '฿'  => ' baht ',
        '؋'  => ' afghani ',
    ],
    // Temperature
    //
    // url: https://en.wikipedia.org/wiki/Conversion_of_units_of_temperature
    'temperature' => [
        '°De' => ' Delisle ',
        '°Re' => ' Reaumur ', // Réaumur
        '°Ro' => ' Romer ', // Rømer
        '°R'  => ' Rankine ',
        '°C'  => ' Celsius ',
        '°F'  => ' Fahrenheit ',
        '°N'  => ' Newton ',
    ],
    'latin_symbols' => [
        '=' => '=',
        '%' => '%',
        '∑' => '∑',
        '∆' => '∆',
        '∞' => '∞',
        '♥' => '♥',
        '&' => '&',
        '+' => '+',
        // ---
        '©' => ' (c) ',
        '®' => ' (r) ',
        '@' => ' (at) ',
        '№' => ' No. ',
        '℞' => ' Rx ',
        '［' => '[',
        '＼' => '\\',
        '］' => ']',
        '＾' => '^',
        '＿' => '_',
        '｀' => '`',
        '‐' => '-',
        '‑' => '-',
        '‒' => '-',
        '–' => '-',
        '−' => '-',
        '—' => '-',
        '―' => '-',
        '﹘' => '-',
        '│' => '|',
        '∖' => '\\',
        '∕' => '/',
        '⁄' => '/',
        '￩' => '<-',
        '￫' => '->',
        '￪' => '|',
        '￬' => '|',
        '⁅' => '[',
        '⁆' => ']',
        '⁎' => '*',
        '、' => ',',
        '。' => '.',
        '〈' => '<',
        '〉' => '>',
        '《' => '<<',
        '》' => '>>',
        '〔' => '[',
        '〕' => ']',
        '〘' => '[',
        '〙' => ']',
        '〚' => '[',
        '〛' => ']',
        '﹝' => '[',
        '﹞' => ']',
        '︹' => '[',
        '︺' => ']',
        '﹇' => '[',
        '﹈' => ']',
        '︐' => ',',
        '︑' => ',',
        '︒' => '.',
        '︓' => ':',
        '︔' => ';',
        '︕' => '!',
        '︖' => '?',
        '︙' => '...',
        '︰' => '..',
        '︵' => '(',
        '︶' => ')',
        '﹙' => '(',
        '﹚' => ')',
        '︷' => '{',
        '︸' => '}',
        '﹛' => '{',
        '﹜' => '}',
        '︽' => '<<',
        '︾' => '>>',
        '︿' => '<',
        '﹀' => '>',
        '×' => '*',
        '÷' => '/',
        '≪' => '<<',
        '≫' => '>>',
        '⦅' => '((',
        '⦆' => '))',
        '〇' => '0',
        '′' => '\'',
        '〝' => '"',
        '〞' => '"',
        '«' => '<<',
        '»' => '>>',
        '‘' => "'",
        '’' => "'",
        '‚' => ',',
        '‛' => "'",
        '“' => '"',
        '”' => '"',
        '„' => '"',
        '‟' => '"',
        '‹' => '<',
        '›' => '>',
        '․' => '.',
        '‥' => '..',
        '…' => '...',
        '″' => '"',
        '‴' => '\'\'\'',
        '‶' => '``',
        '‷' => '```',
        '‼' => '!!',
        '⁇' => '??',
        '⁈' => '?!',
        '⁉' => '!?',
        '⁗' => '````',
        '⩴' => '::=',
        '⩵' => '==',
        '⩶' => '===',
        '﹔' => ';',
        '﹕' => ':',
        '﹖' => '?',
        '﹗' => '!',
        '﹍' => '_',
        '﹎' => '_',
        '﹏' => '_',
        '﹐' => ',',
        '﹑' => ',',
        '﹒' => '.',
        '﹟' => '#',
        '﹠' => '&',
        '﹡' => '*',
        '﹢' => '+',
        '﹣' => '-',
        '﹤' => '<',
        '﹥' => '>',
        '﹦' => '=',
        '﹨' => '\\',
        '﹩' => '$',
        '﹪' => '%',
        '﹫' => '@',
        '！' => '!',
        '＂' => '"',
        '＃' => '#',
        '＄' => '$',
        '％' => '%',
        '＆' => '&',
        '＇' => '\'',
        '（' => '(',
        '）' => ')',
        '＊' => '*',
        '＋' => '+',
        '，' => ',',
        '－' => '-',
        '．' => '.',
        '／' => '/',
        '：' => ':',
        '；' => ';',
        '＜' => '<',
        '＝' => '=',
        '＞' => '>',
        '？' => '?',
        '＠' => '@',
        '｛' => '{',
        '｜' => '|',
        '｝' => '}',
        '～' => '~',
        '｟' => '((',
        '｠' => '))',
        '￢' => '!',
        '￣' => '-',
        '￤' => '|',
        '￭' => '#',
    ],
];
<?php

return [
    'uz'                => 0,
    'tk'                => 1,
    'th'                => 0,
    'ps'                => 0,
    'or'                => 0,
    'mn'                => 0,
    'ko'                => 0,
    'ky'                => 0,
    'hy'                => 1,
    'bn'                => 5,
    'be'                => 0,
    'am'                => 0,
    'ja'                => 0,
    'zh'                => 0,
    'nl'                => 1,
    'it'                => 1,
    'mk'                => 1,
    'pt'                => 1,
    'el__greeklish'     => 2,
    'el'                => 2,
    'hi'                => 2,
    'sv'                => 1,
    'tr'                => 1,
    'bg'                => 2,
    'hu'                => 1,
    'my'                => 5,
    'hr'                => 2,
    'fi'                => 1,
    'ka'                => 1,
    'ru'                => 1,
    'ru__gost_2000_b'   => 1,
    'ru__passport_2013' => 1,
    'uk'                => 1,
    'kk'                => 1,
    'cs'                => 1,
    'da'                => 1,
    'pl'                => 1,
    'ro'                => 1,
    'eo'                => 1,
    'et'                => 1,
    'lv'                => 1,
    'lt'                => 1,
    'no'                => 1,
    'vi'                => 1,
    'ar'                => 1,
    'fa'                => 1,
    'sr'                => 1,
    'sr__cyr'           => 1,
    'sr__lat'           => 1,
    'az'                => 1,
    'sk'                => 1,
    'fr'                => 1,
    'fr_at'             => 1,
    'fr_ch'             => 1,
    'de'                => 1,
    'de_at'             => 1,
    'de_ch'             => 1,
    'en'                => 0,
    'latin'             => 3,
    ' '                 => 1,
    'msword'            => 1,
];
<?php return ['' => 0, "\x00" => 0, "\x01" => 1, "\x02" => 2, "\x03" => 3, "\x04" => 4, "\x05" => 5, "\x06" => 6, "\x07" => 7, "\x08" => 8, "\x09" => 9, "\x0A" => 10, "\x0B" => 11, "\x0C" => 12, "\x0D" => 13, "\x0E" => 14, "\x0F" => 15, "\x10" => 16, "\x11" => 17, "\x12" => 18, "\x13" => 19, "\x14" => 20, "\x15" => 21, "\x16" => 22, "\x17" => 23, "\x18" => 24, "\x19" => 25, "\x1A" => 26, "\x1B" => 27, "\x1C" => 28, "\x1D" => 29, "\x1E" => 30, "\x1F" => 31, "\x20" => 32, "\x21" => 33, "\x22" => 34, "\x23" => 35, "\x24" => 36, "\x25" => 37, "\x26" => 38, "\x27" => 39, "\x28" => 40, "\x29" => 41, "\x2A" => 42, "\x2B" => 43, "\x2C" => 44, "\x2D" => 45, "\x2E" => 46, "\x2F" => 47, "\x30" => 48, "\x31" => 49, "\x32" => 50, "\x33" => 51, "\x34" => 52, "\x35" => 53, "\x36" => 54, "\x37" => 55, "\x38" => 56, "\x39" => 57, "\x3A" => 58, "\x3B" => 59, "\x3C" => 60, "\x3D" => 61, "\x3E" => 62, "\x3F" => 63, "\x40" => 64, "\x41" => 65, "\x42" => 66, "\x43" => 67, "\x44" => 68, "\x45" => 69, "\x46" => 70, "\x47" => 71, "\x48" => 72, "\x49" => 73, "\x4A" => 74, "\x4B" => 75, "\x4C" => 76, "\x4D" => 77, "\x4E" => 78, "\x4F" => 79, "\x50" => 80, "\x51" => 81, "\x52" => 82, "\x53" => 83, "\x54" => 84, "\x55" => 85, "\x56" => 86, "\x57" => 87, "\x58" => 88, "\x59" => 89, "\x5A" => 90, "\x5B" => 91, "\x5C" => 92, "\x5D" => 93, "\x5E" => 94, "\x5F" => 95, "\x60" => 96, "\x61" => 97, "\x62" => 98, "\x63" => 99, "\x64" => 100, "\x65" => 101, "\x66" => 102, "\x67" => 103, "\x68" => 104, "\x69" => 105, "\x6A" => 106, "\x6B" => 107, "\x6C" => 108, "\x6D" => 109, "\x6E" => 110, "\x6F" => 111, "\x70" => 112, "\x71" => 113, "\x72" => 114, "\x73" => 115, "\x74" => 116, "\x75" => 117, "\x76" => 118, "\x77" => 119, "\x78" => 120, "\x79" => 121, "\x7A" => 122, "\x7B" => 123, "\x7C" => 124, "\x7D" => 125, "\x7E" => 126, "\x7F" => 127, "\x80" => 128, "\x81" => 129, "\x82" => 130, "\x83" => 131, "\x84" => 132, "\x85" => 133, "\x86" => 134, "\x87" => 135, "\x88" => 136, "\x89" => 137, "\x8A" => 138, "\x8B" => 139, "\x8C" => 140, "\x8D" => 141, "\x8E" => 142, "\x8F" => 143, "\x90" => 144, "\x91" => 145, "\x92" => 146, "\x93" => 147, "\x94" => 148, "\x95" => 149, "\x96" => 150, "\x97" => 151, "\x98" => 152, "\x99" => 153, "\x9A" => 154, "\x9B" => 155, "\x9C" => 156, "\x9D" => 157, "\x9E" => 158, "\x9F" => 159, "\xA0" => 160, "\xA1" => 161, "\xA2" => 162, "\xA3" => 163, "\xA4" => 164, "\xA5" => 165, "\xA6" => 166, "\xA7" => 167, "\xA8" => 168, "\xA9" => 169, "\xAA" => 170, "\xAB" => 171, "\xAC" => 172, "\xAD" => 173, "\xAE" => 174, "\xAF" => 175, "\xB0" => 176, "\xB1" => 177, "\xB2" => 178, "\xB3" => 179, "\xB4" => 180, "\xB5" => 181, "\xB6" => 182, "\xB7" => 183, "\xB8" => 184, "\xB9" => 185, "\xBA" => 186, "\xBB" => 187, "\xBC" => 188, "\xBD" => 189, "\xBE" => 190, "\xBF" => 191, "\xC0" => 192, "\xC1" => 193, "\xC2" => 194, "\xC3" => 195, "\xC4" => 196, "\xC5" => 197, "\xC6" => 198, "\xC7" => 199, "\xC8" => 200, "\xC9" => 201, "\xCA" => 202, "\xCB" => 203, "\xCC" => 204, "\xCD" => 205, "\xCE" => 206, "\xCF" => 207, "\xD0" => 208, "\xD1" => 209, "\xD2" => 210, "\xD3" => 211, "\xD4" => 212, "\xD5" => 213, "\xD6" => 214, "\xD7" => 215, "\xD8" => 216, "\xD9" => 217, "\xDA" => 218, "\xDB" => 219, "\xDC" => 220, "\xDD" => 221, "\xDE" => 222, "\xDF" => 223, "\xE0" => 224, "\xE1" => 225, "\xE2" => 226, "\xE3" => 227, "\xE4" => 228, "\xE5" => 229, "\xE6" => 230, "\xE7" => 231, "\xE8" => 232, "\xE9" => 233, "\xEA" => 234, "\xEB" => 235, "\xEC" => 236, "\xED" => 237, "\xEE" => 238, "\xEF" => 239, "\xF0" => 240, "\xF1" => 241, "\xF2" => 242, "\xF3" => 243, "\xF4" => 244, "\xF5" => 245, "\xF6" => 246, "\xF7" => 247, "\xF8" => 248, "\xF9" => 249, "\xFA" => 250, "\xFB" => 251, "\xFC" => 252, "\xFD" => 253, "\xFE" => 254, "\xFF" => 255];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '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', '[', '\\', ']', '^', '_', '`', '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', '{', '|', '}', '~', '', 'EUR',  // "\xc2\x80" => "\xe2\x82\xac" => EURO SIGN
    '', ',', 'f', ',,',   // "\xc2\x84" => "\xe2\x80\x9e" => DOUBLE LOW-9 QUOTATION MARK
    '...',  // "\xc2\x85" => "\xe2\x80\xa6" =>  HORIZONTAL ELLIPSIS
    '+', '++',   // "\xc2\x87" => "\xe2\x80\xa1" => DOUBLE DAGGER
    '^', '%0',   // "\xc2\x89" => "\xe2\x80\xb0" => PER MILLE SIGN
    'S', '<', 'OE',   // "\xc2\x8c" => "\xc5\x92" => LATIN CAPITAL LIGATURE OE
    '', 'Z', '', '', '\'',   // "\xc2\x91" => "\xe2\x80\x98" => LEFT SINGLE QUOTATION MARK
    '\'',   // "\xc2\x92" => "\xe2\x80\x99" => RIGHT SINGLE QUOTATION MARK
    '"', '"', '*', '-', '--',   // "\xc2\x97" => "\xe2\x80\x94" => EM DASH
    '~', 'tm', 's', '>', 'oe', '', 'z', 'Y', ' ', '!', 'C/', 'PS', '$?', 'Y=', '|', 'SS', '"', '(c)', 'a', '<<', '!', '', '(r)', '-', 'deg', '+-', '2', '3', '\'', 'u', 'P', '*', ',', '1', 'o', '>>', '1/4', '1/2', '3/4', '?', 'A', 'A', 'A', 'A', // Not "AE" - used in languages other than German
    'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', // Not "OE" - used in languages other than German
    'O', 'x', 'O', 'U', 'U', 'U', // Not "UE" - used in languages other than German
    'U', 'Y', 'Th', 'ss', 'a', 'a', 'a', 'a', // Not "ae" - used in languages other than German
    'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'd', 'n', 'o', 'o', 'o', 'o', // Not "oe" - used in languages other than German
    'o', '/', 'o', 'u', 'u', 'u', // Not "ue" - used in languages other than German
    'u', 'y', 'th', 'y', ];
<?php return ['A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'N', 'n', 'N', 'n', 'N', 'n', '\'n', 'ng', 'NG', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'b', 'B', 'B', 'b', '6', '6', 'O', 'C', 'c', 'D', 'D', 'D', 'd', 'd', '3', '@', 'E', 'F', 'f', 'G', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'l', 'W', 'N', 'n', 'O', 'O', 'o', 'OI', 'oi', 'P', 'p', 'YR', '2', '2', 'SH', 'sh', 't', 'T', 't', 'T', 'U', 'u', 'Y', 'V', 'Y', 'y', 'Z', 'z', 'ZH', 'ZH', 'zh', 'zh', '2', '5', '5', 'ts', 'w', '|', '||', '|=', '!', 'DZ', 'Dz', 'dz', 'LJ', 'Lj', 'lj', 'NJ', 'Nj', 'nj', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', '@', 'A', 'a', 'A', 'a', 'AE', 'ae', 'G', 'g', 'G', 'g', 'K', 'k', 'O', 'o', 'O', 'o', 'ZH', 'zh', 'j', 'DZ', 'Dz', 'dz', 'G', 'g', 'HV', 'W', 'N', 'n', 'A', 'a', 'AE', 'ae', 'O', 'o'];
<?php return ['A', 'a', 'A', 'a', 'E', 'e', 'E', 'e', 'I', 'i', 'I', 'i', 'O', 'o', 'O', 'o', 'R', 'r', 'R', 'r', 'U', 'u', 'U', 'u', 'S', 's', 'T', 't', 'Y', 'y', 'H', 'h', 'N', 'd', 'OU', 'ou', 'Z', 'z', 'A', 'a', 'E', 'e', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'Y', 'y', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', '[?]', '[?]', 'B', 'U', '^', 'E', 'e', 'J', 'j', 'q', 'q', 'R', 'r', 'Y', 'y', 'a', 'a', 'a', 'b', 'o', 'c', 'd', 'd', 'e', '@', '@', 'e', 'e', 'e', 'e', 'j', 'g', 'g', 'g', 'g', 'u', 'Y', 'h', 'h', 'i', 'i', 'I', 'l', 'l', 'l', 'lZ', 'W', 'W', 'm', 'n', 'n', 'n', 'o', 'OE', 'O', 'F', 'r', 'r', 'r', 'r', 'r', 'r', 'r', 'R', 'R', 's', 'S', 'j', 'S', 'S', 't', 't', 'u', 'U', 'v', '^', 'w', 'y', 'Y', 'z', 'z', 'Z', 'Z', '?', '?', '?', 'C', '@', 'B', 'E', 'G', 'H', 'j', 'k', 'L', 'q', '?', '?', 'dz', 'dZ', 'dz', 'ts', 'tS', 'tC', 'fN', 'ls', 'lz', 'WW', ']]', 'h', 'h', 'h', 'h', 'j', 'r', 'r', 'r', 'r', 'w', 'y', '\'', '"', '`', '\'', '`', '`', '\'', '?', '?', '<', '>', '^', 'V', '^', 'V', '\'', '-', '/', '\\', ',', '_', '\\', '/', ':', '.', '`', '\'', '^', 'V', '+', '-', 'V', '.', '@', ',', '~', '"', 'R', 'X', 'G', 'l', 's', 'x', '?', '', '', '', '', '', '', '', 'V', '=', '"', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', 'a', 'e', 'i', 'o', 'u', 'c', 'd', 'h', 'm', 'r', 't', 'v', 'x', '[?]', '[?]', '[?]', '[?]', '\'', ',', '[?]', '[?]', '[?]', '[?]', '', '[?]', '[?]', '[?]', '?', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', 'A', ';', 'E', 'E', 'I', '[?]', 'O', '[?]', 'U', 'O', 'I', 'A', 'B', 'G', 'D', 'E', 'Z', 'E', 'Th', 'I', 'K', 'L', 'M', 'N', 'Ks', 'O', 'P', 'R', '[?]', 'S', 'T', 'U', 'Ph', 'Kh', 'Ps', 'O', 'I', 'U', 'a', 'e', 'e', 'i', 'u', 'a', 'b', 'g', 'd', 'e', 'z', 'e', 'th', 'i', 'k', 'l', 'm', 'n', 'x', 'o', 'p', 'r', 's', 's', 't', 'u', 'ph', 'kh', 'ps', 'o', 'i', 'u', 'o', 'u', 'o', '[?]', 'b', 'th', 'U', 'U', 'U', 'ph', 'p', '&', '[?]', '[?]', 'St', 'st', 'W', 'w', 'Q', 'q', 'Sp', 'sp', 'Sh', 'sh', 'F', 'f', 'Kh', 'kh', 'H', 'h', 'G', 'g', 'CH', 'ch', 'Ti', 'ti', 'k', 'r', 'c', 'j', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['Ie', 'Io', 'Dj', 'Gj', 'Ie', 'Dz', 'I', 'Yi', 'J', 'Lj', 'Nj', 'Tsh', 'Kj', 'I', 'U', 'Dzh', 'A', 'B', 'V', 'G', 'D', 'E', 'Zh', 'Z', 'I', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'Kh', 'Ts', 'Ch', 'Sh', 'Shch', '\'', 'Y', '\'', 'E', 'Iu', 'Ia', 'a', 'b', 'v', 'g', 'd', 'e', 'zh', 'z', 'i', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'kh', 'ts', 'ch', 'sh', 'shch', '\'', 'y', '\'', 'e', 'iu', 'ia', 'ie', 'io', 'dj', 'gj', 'ie', 'dz', 'i', 'yi', 'j', 'lj', 'nj', 'tsh', 'kj', 'i', 'u', 'dzh', 'O', 'o', 'E', 'e', 'Ie', 'ie', 'E', 'e', 'Ie', 'ie', 'O', 'o', 'Io', 'io', 'Ks', 'ks', 'Ps', 'ps', 'F', 'f', 'Y', 'y', 'Y', 'y', 'u', 'u', 'O', 'o', 'O', 'o', 'Ot', 'ot', 'Q', 'q', '*1000*', '', '', '', '', '[?]', '*100.000*', '*1.000.000*', '[?]', '[?]', '"', '"', 'R\'', 'r\'', 'G\'', 'g\'', 'G\'', 'g\'', 'G\'', 'g\'', 'Zh\'', 'zh\'', 'Z\'', 'z\'', 'K\'', 'k\'', 'K\'', 'k\'', 'K\'', 'k\'', 'K\'', 'k\'', 'N\'', 'n\'', 'Ng', 'ng', 'P\'', 'p\'', 'Kh', 'kh', 'S\'', 's\'', 'T\'', 't\'', 'U', 'u', 'U\'', 'u\'', 'Kh\'', 'kh\'', 'Tts', 'tts', 'Ch\'', 'ch\'', 'Ch\'', 'ch\'', 'H', 'h', 'Ch', 'ch', 'Ch\'', 'ch\'', '`', 'Zh', 'zh', 'K\'', 'k\'', '[?]', '[?]', 'N\'', 'n\'', '[?]', '[?]', 'Ch', 'ch', '[?]', '[?]', '[?]', 'a', 'a', 'A', 'a', 'Ae', 'ae', 'Ie', 'ie', '@', '@', '@', '@', 'Zh', 'zh', 'Z', 'z', 'Dz', 'dz', 'I', 'i', 'I', 'i', 'O', 'o', 'O', 'o', 'O', 'o', 'E', 'e', 'U', 'u', 'U', 'u', 'U', 'u', 'Ch', 'ch', '[?]', '[?]', 'Y', 'y', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'A', 'B', 'G', 'D', 'E', 'Z', 'E', 'E', 'T`', 'Zh', 'I', 'L', 'Kh', 'Ts', 'K', 'H', 'Dz', 'Gh', 'Ch', 'M', 'Y', 'N', 'Sh', 'O', 'Ch`', 'P', 'J', 'Rh', 'S', 'V', 'T', 'R', 'Ts`', 'W', 'P`', 'K`', 'O', 'F', '[?]', '[?]', '<', '\'', '/', '!', ',', '?', '.', '[?]', 'a', 'b', 'g', 'd', 'e', 'z', 'e', 'e', 't`', 'zh', 'i', 'l', 'kh', 'ts', 'k', 'h', 'dz', 'gh', 'ch', 'm', 'y', 'n', 'sh', 'o', 'ch`', 'p', 'j', 'rh', 's', 'v', 't', 'r', 'ts`', 'w', 'p`', 'k`', 'o', 'f', 'ew', '[?]', ':', '-', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '@', 'e', 'a', 'o', 'i', 'e', 'e', 'a', 'a', 'o', 'o', 'u', '\'', '', '-', '-', '|', '', '', ':', '', '', 'n', 'o', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'A', 'b', 'g', 'd', 'h', 'v', 'z', 'KH', 't', 'y', 'k', 'k', 'l', 'm', 'm', 'n', 'n', 's', '`', 'p', 'p', 'TS', 'TS', 'q', 'r', 'SH', 't', '[?]', '[?]', '[?]', '[?]', '[?]', 'V', 'OY', 'i', '\'', '"', 'v', 'n', 'q', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ',', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ';', '[?]', '[?]', '[?]', '?', '[?]', '', 'a', 'a', 'w\'', '', 'y\'', '', 'b', '@', 't', 'th', 'j', 'H', 'kh', 'd', 'dh', 'r', 'z', 's', 'sh', 'S', 'D', 'T', 'Z', '`', 'G', '[?]', '[?]', '[?]', '[?]', '[?]', '', 'f', 'q', 'k', 'l', 'm', 'n', 'h', 'w', '~', 'y', 'an', 'un', 'in', 'a', 'u', 'i', 'W', '', '', '\'', '\'', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '%', '.', ',', '*', '[?]', '[?]', '', '\'', '\'', '\'', '', '\'', '\'w', '\'u', '\'y', 'tt', 'tth', 'b', 't', 'T', 'p', 'th', 'bh', '\'h', 'H', 'ny', 'dy', 'H', 'ch', 'cch', 'dd', 'D', 'D', 'Dt', 'dh', 'ddh', 'd', 'D', 'D', 'rr', 'R', 'R', 'R', 'R', 'R', 'R', 'j', 'R', 'S', 'S', 'S', 'S', 'S', 'T', 'GH', 'F', 'F', 'F', 'v', 'f', 'ph', 'Q', 'Q', 'kh', 'k', 'K', 'K', 'ng', 'K', 'g', 'G', 'N', 'G', 'G', 'G', 'L', 'L', 'L', 'L', 'N', 'N', 'N', 'N', 'N', 'h', 'Ch', 'hy', 'h', 'H', '@', 'W', 'oe', 'oe', 'u', 'yu', 'yu', 'W', 'v', 'y', 'Y', 'Y', 'W', '', '', 'y', 'y\'', '.', 'ae', '', '', '', '', '', '', '', '@', '#', '', '', '', '', '', '', '', '', '', '', '^', '', '', '', '', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'Sh', 'D', 'Gh', '&', '+m', 'h'];
<?php return ['//', '/', ',', '!', '!', '-', ',', ',', ';', '?', '~', '{', '}', '*', '[?]', '', '\'', '', 'b', 'g', 'g', 'd', 'd', 'h', 'w', 'z', 'H', 't', 't', 'y', 'yh', 'k', 'l', 'm', 'n', 's', 's', '`', 'p', 'p', 'S', 'q', 'r', 'sh', 't', '[?]', '[?]', '[?]', 'a', 'a', 'a', 'A', 'A', 'A', 'e', 'e', 'e', 'E', 'i', 'i', 'u', 'u', 'u', 'o', '', '`', '\'', '', '', 'X', 'Q', '@', '@', '|', '+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'h', 'sh', 'n', 'r', 'b', 'L', 'k', '\'', 'v', 'm', 'f', 'dh', 'th', 'l', 'g', 'ny', 's', 'd', 'z', 't', 'y', 'p', 'j', 'ch', 'tt', 'hh', 'kh', 'th', 'z', 'sh', 's', 'd', 't', 'z', '`', 'gh', 'q', 'w', 'a', 'aa', 'i', 'ee', 'u', 'oo', 'e', 'ey', 'o', 'oa', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', 'N', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'L', 'eN', 'e', 'e', 'ai', 'oN', 'o', 'o', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', 'nnn', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'rr', 'l', 'l', 'lll', 'v', 'sh', 'ss', 's', 'h', '[?]', '[?]', '\'', '\'', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', 'eN', 'e', 'e', 'ai', 'oN', 'o', 'o', 'au', '', '[?]', '[?]', 'AUM', '\'', '\'', '`', '\'', '[?]', '[?]', '[?]', 'q', 'khh', 'ghh', 'z', 'dddh', 'rh', 'f', 'yy', 'RR', 'LL', 'L', 'LL', ' / ', ' // ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'N', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', '[?]', '[?]', 'e', 'ai', '[?]', '[?]', 'o', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', '[?]', 'l', '[?]', '[?]', '[?]', 'sh', 'ss', 's', 'h', '[?]', '[?]', '\'', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', '[?]', '[?]', 'e', 'ai', '[?]', '[?]', 'o', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '[?]', '[?]', '[?]', '[?]', 'rr', 'rh', '[?]', 'yy', 'RR', 'LL', 'L', 'LL', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'r\'', 'r`', 'Rs', 'Rs', '1/', '2/', '3/', '4/', ' 1 - 1/', '/16', '', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', 'N', '[?]', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', '[?]', '[?]', '[?]', '[?]', 'ee', 'ai', '[?]', '[?]', 'oo', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bb', 'm', 'y', 'r', '[?]', 'l', 'll', '[?]', 'v', 'sh', '[?]', 's', 'h', '[?]', '[?]', '\'', '[?]', 'aa', 'i', 'ii', 'u', 'uu', '[?]', '[?]', '[?]', '[?]', 'ee', 'ai', '[?]', '[?]', 'oo', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'khh', 'ghh', 'z', 'rr', '[?]', 'f', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'N', 'H', '', '', 'G.E.O.', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'N', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', '[?]', 'eN', '[?]', 'e', 'ai', 'oN', '[?]', 'o', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'ya', 'r', '[?]', 'l', 'll', '[?]', 'v', 'sh', 'ss', 's', 'h', '[?]', '[?]', '\'', '\'', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', 'eN', '[?]', 'e', 'ai', 'oN', '[?]', 'o', 'au', '', '[?]', '[?]', 'AUM', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'RR', '[?]', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', 'N', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'L', '[?]', '[?]', 'e', 'ai', '[?]', '[?]', 'o', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', '[?]', 'l', 'll', '[?]', '', 'sh', 'ss', 's', 'h', '[?]', '[?]', '\'', '\'', 'aa', 'i', 'ii', 'u', 'uu', 'R', '[?]', '[?]', '[?]', 'e', 'ai', '[?]', '[?]', 'o', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '+', '[?]', '[?]', '[?]', '[?]', 'rr', 'rh', '[?]', 'yy', 'RR', 'LL', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', '[?]', '[?]', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', 'k', '[?]', '[?]', '[?]', 'ng', 'c', '[?]', 'j', '[?]', 'ny', 'tt', '[?]', '[?]', '[?]', 'nn', 't', '[?]', '[?]', '[?]', 'n', 'nnn', 'p', '[?]', '[?]', '[?]', 'm', 'y', 'r', 'rr', 'l', 'll', 'lll', 'v', '[?]', 'ss', 's', 'h', '[?]', '[?]', '[?]', '[?]', 'aa', 'i', 'ii', 'u', 'uu', '[?]', '[?]', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+10+', '+100+', '+1000+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', 'N', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'L', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'rr', 'l', 'll', '[?]', 'v', 'sh', 'ss', 's', 'h', '[?]', '[?]', '[?]', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'RR', 'LL', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'L', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'rr', 'l', 'll', '[?]', 'v', 'sh', 'ss', 's', 'h', '[?]', '[?]', '[?]', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'lll', '[?]', 'RR', 'LL', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', 'N', 'H', '[?]', 'a', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'L', '[?]', 'e', 'ee', 'ai', '[?]', 'o', 'oo', 'au', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', '[?]', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'rr', 'l', 'll', 'lll', 'v', 'sh', 'ss', 's', 'h', '[?]', '[?]', '[?]', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'R', '[?]', '[?]', 'e', 'ee', 'ai', '', 'o', 'oo', 'au', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'RR', 'LL', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'N', 'H', '[?]', 'a', 'aa', 'ae', 'aae', 'i', 'ii', 'u', 'uu', 'R', 'RR', 'L', 'LL', 'e', 'ee', 'ai', 'o', 'oo', 'au', '[?]', '[?]', '[?]', 'k', 'kh', 'g', 'gh', 'ng', 'nng', 'c', 'ch', 'j', 'jh', 'ny', 'jny', 'nyj', 'tt', 'tth', 'dd', 'ddh', 'nn', 'nndd', 't', 'th', 'd', 'dh', 'n', '[?]', 'nd', 'p', 'ph', 'b', 'bh', 'm', 'mb', 'y', 'r', '[?]', 'l', '[?]', '[?]', 'v', 'sh', 'ss', 's', 'h', 'll', 'f', '[?]', '[?]', '[?]', '', '[?]', '[?]', '[?]', '[?]', 'aa', 'ae', 'aae', 'i', 'ii', 'u', '[?]', 'uu', '[?]', 'R', 'e', 'ee', 'ai', 'o', 'oo', 'au', 'L', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'RR', 'LL', ' . ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', 'k', 'kh', 'kh', 'kh', 'kh', 'kh', 'ng', 'cch', 'ch', 'ch', 'ch', 'ch', 'y', 'd', 't', 'th', 'th', 'th', 'n', 'd', 't', 'th', 'th', 'th', 'n', 'b', 'p', 'ph', 'f', 'ph', 'f', 'ph', 'm', 'y', 'r', 'R', 'l', 'L', 'w', 's', 's', 's', 'h', 'l', '`', 'h', '~', 'a', 'a', 'aa', 'am', 'i', 'ii', 'ue', 'uue', 'u', 'uu', '\'', '[?]', '[?]', '[?]', '[?]', 'Bh.', 'e', 'ae', 'o', 'ai', 'ai', 'ao', '+', '', '', '', '', '', '', 'M', '', ' * ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' // ', ' /// ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'k', 'kh', '[?]', 'kh', '[?]', '[?]', 'ng', 'ch', '[?]', 's', '[?]', '[?]', 'ny', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'd', 'h', 'th', 'th', '[?]', 'n', 'b', 'p', 'ph', 'f', 'ph', 'f', '[?]', 'm', 'y', 'r', '[?]', 'l', '[?]', 'w', '[?]', '[?]', 's', 'h', '[?]', '`', '', '~', 'a', '', 'aa', 'am', 'i', 'ii', 'y', 'yy', 'u', 'uu', '[?]', 'o', 'l', 'ny', '[?]', '[?]', 'e', 'ei', 'o', 'ay', 'ai', '[?]', '+', '[?]', '', '', '', '', '', 'M', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', 'hn', 'hm', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['AUM', '', '', '', '', '', '', '', ' // ', ' * ', '', '-', ' / ', ' / ', ' // ', ' -/ ', ' +/ ', ' X/ ', ' /XX/ ', ' /X/ ', ', ', '', '', '', '', '', '', '', '', '', '', '', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.5', '1.5', '2.5', '3.5', '4.5', '5.5', '6.5', '7.5', '8.5', '-.5', '+', '*', '^', '_', '', '~', '[?]', ']', '[[', ']]', '', '', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', '[?]', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', 'p', 'ph', 'b', 'bh', 'm', 'ts', 'tsh', 'dz', 'dzh', 'w', 'zh', 'z', '\'', 'y', 'r', 'l', 'sh', 'ssh', 's', 'h', 'a', 'kss', 'r', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'R', 'RR', 'L', 'LL', 'e', 'ee', 'o', 'oo', 'M', 'H', 'i', 'ii', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', '[?]', 'ny', 'tt', 'tth', 'dd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', 'p', 'ph', 'b', 'bh', 'm', 'ts', 'tsh', 'dz', 'dzh', 'w', 'zh', 'z', '\'', 'y', 'r', 'l', 'sh', 'ss', 's', 'h', 'a', 'kss', 'w', 'y', 'r', '[?]', 'X', ' :X: ', ' /O/ ', ' /o/ ', ' \\o\\ ', ' (O) ', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 'nny', 'tt', 'tth', 'dd', 'ddh', 'nn', 'tt', 'th', 'd', 'dh', 'n', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'l', 'w', 's', 'h', 'll', 'a', '[?]', 'i', 'ii', 'u', 'uu', 'e', '[?]', 'o', 'au', '[?]', 'aa', 'i', 'ii', 'u', 'uu', 'e', 'ai', '[?]', '[?]', '[?]', 'N', '\'', ':', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' / ', ' // ', 'n*', 'r*', 'l*', 'e*', 'sh', 'ss', 'R', 'RR', 'L', 'LL', 'R', 'RR', 'L', 'LL', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'A', 'B', 'G', 'D', 'E', 'V', 'Z', 'T`', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Zh', 'R', 'S', 'T', 'U', 'P`', 'K`', 'G\'', 'Q', 'Sh', 'Ch`', 'C`', 'Z\'', 'C', 'Ch', 'X', 'J', 'H', 'E', 'Y', 'W', 'Xh', 'OE', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'a', 'b', 'g', 'd', 'e', 'v', 'z', 't`', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'zh', 'r', 's', 't', 'u', 'p`', 'k`', 'g\'', 'q', 'sh', 'ch`', 'c`', 'z\'', 'c', 'ch', 'x', 'j', 'h', 'e', 'y', 'w', 'xh', 'oe', 'f', '[?]', '[?]', '[?]', '[?]', ' // ', '[?]', '[?]', '[?]'];
<?php return ['g', 'gg', 'n', 'd', 'dd', 'r', 'm', 'b', 'bb', 's', 'ss', '', 'j', 'jj', 'c', 'k', 't', 'p', 'h', 'ng', 'nn', 'nd', 'nb', 'dg', 'rn', 'rr', 'rh', 'rN', 'mb', 'mN', 'bg', 'bn', '', 'bs', 'bsg', 'bst', 'bsb', 'bss', 'bsj', 'bj', 'bc', 'bt', 'bp', 'bN', 'bbN', 'sg', 'sn', 'sd', 'sr', 'sm', 'sb', 'sbg', 'sss', 's', 'sj', 'sc', 'sk', 'st', 'sp', 'sh', '', '', '', '', 'Z', 'g', 'd', 'm', 'b', 's', 'Z', '', 'j', 'c', 't', 'p', 'N', 'j', '', '', '', '', 'ck', 'ch', '', '', 'pb', 'pN', 'hh', 'Q', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', 'a', 'ae', 'ya', 'yae', 'eo', 'e', 'yeo', 'ye', 'o', 'wa', 'wae', 'oe', 'yo', 'u', 'weo', 'we', 'wi', 'yu', 'eu', 'yi', 'i', 'a-o', 'a-u', 'ya-o', 'ya-yo', 'eo-o', 'eo-u', 'eo-eu', 'yeo-o', 'yeo-u', 'o-eo', 'o-e', 'o-ye', 'o-o', 'o-u', 'yo-ya', 'yo-yae', 'yo-yeo', 'yo-o', 'yo-i', 'u-a', 'u-ae', 'u-eo-eu', 'u-ye', 'u-u', 'yu-a', 'yu-eo', 'yu-e', 'yu-yeo', 'yu-ye', 'yu-u', 'yu-i', 'eu-u', 'eu-eu', 'yi-u', 'i-a', 'i-ya', 'i-o', 'i-u', 'i-eu', 'i-U', 'U', 'U-eo', 'U-u', 'U-i', 'UU', '[?]', '[?]', '[?]', '[?]', '[?]', 'g', 'gg', 'gs', 'n', 'nj', 'nh', 'd', 'l', 'lg', 'lm', 'lb', 'ls', 'lt', 'lp', 'lh', 'm', 'b', 'bs', 's', 'ss', 'ng', 'j', 'c', 'k', 't', 'p', 'h', 'gl', 'gsg', 'ng', 'nd', 'ns', 'nZ', 'nt', 'dg', 'tl', 'lgs', 'ln', 'ld', 'lth', 'll', 'lmg', 'lms', 'lbs', 'lbh', 'rNp', 'lss', 'lZ', 'lk', 'lQ', 'mg', 'ml', 'mb', 'ms', 'mss', 'mZ', 'mc', 'mh', 'mN', 'bl', 'bp', 'ph', 'pN', 'sg', 'sd', 'sl', 'sb', 'Z', 'g', 'ss', '', 'kh', 'N', 'Ns', 'NZ', 'pb', 'pN', 'hn', 'hl', 'hm', 'hb', 'Q', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['ha', 'hu', 'hi', 'haa', 'hee', 'he', 'ho', '[?]', 'la', 'lu', 'li', 'laa', 'lee', 'le', 'lo', 'lwa', 'hha', 'hhu', 'hhi', 'hhaa', 'hhee', 'hhe', 'hho', 'hhwa', 'ma', 'mu', 'mi', 'maa', 'mee', 'me', 'mo', 'mwa', 'sza', 'szu', 'szi', 'szaa', 'szee', 'sze', 'szo', 'szwa', 'ra', 'ru', 'ri', 'raa', 'ree', 're', 'ro', 'rwa', 'sa', 'su', 'si', 'saa', 'see', 'se', 'so', 'swa', 'sha', 'shu', 'shi', 'shaa', 'shee', 'she', 'sho', 'shwa', 'qa', 'qu', 'qi', 'qaa', 'qee', 'qe', 'qo', '[?]', 'qwa', '[?]', 'qwi', 'qwaa', 'qwee', 'qwe', '[?]', '[?]', 'qha', 'qhu', 'qhi', 'qhaa', 'qhee', 'qhe', 'qho', '[?]', 'qhwa', '[?]', 'qhwi', 'qhwaa', 'qhwee', 'qhwe', '[?]', '[?]', 'ba', 'bu', 'bi', 'baa', 'bee', 'be', 'bo', 'bwa', 'va', 'vu', 'vi', 'vaa', 'vee', 've', 'vo', 'vwa', 'ta', 'tu', 'ti', 'taa', 'tee', 'te', 'to', 'twa', 'ca', 'cu', 'ci', 'caa', 'cee', 'ce', 'co', 'cwa', 'xa', 'xu', 'xi', 'xaa', 'xee', 'xe', 'xo', '[?]', 'xwa', '[?]', 'xwi', 'xwaa', 'xwee', 'xwe', '[?]', '[?]', 'na', 'nu', 'ni', 'naa', 'nee', 'ne', 'no', 'nwa', 'nya', 'nyu', 'nyi', 'nyaa', 'nyee', 'nye', 'nyo', 'nywa', '\'a', '\'u', '[?]', '\'aa', '\'ee', '\'e', '\'o', '\'wa', 'ka', 'ku', 'ki', 'kaa', 'kee', 'ke', 'ko', '[?]', 'kwa', '[?]', 'kwi', 'kwaa', 'kwee', 'kwe', '[?]', '[?]', 'kxa', 'kxu', 'kxi', 'kxaa', 'kxee', 'kxe', 'kxo', '[?]', 'kxwa', '[?]', 'kxwi', 'kxwaa', 'kxwee', 'kxwe', '[?]', '[?]', 'wa', 'wu', 'wi', 'waa', 'wee', 'we', 'wo', '[?]', '`a', '`u', '`i', '`aa', '`ee', '`e', '`o', '[?]', 'za', 'zu', 'zi', 'zaa', 'zee', 'ze', 'zo', 'zwa', 'zha', 'zhu', 'zhi', 'zhaa', 'zhee', 'zhe', 'zho', 'zhwa', 'ya', 'yu', 'yi', 'yaa', 'yee', 'ye', 'yo', '[?]', 'da', 'du', 'di', 'daa', 'dee', 'de', 'do', 'dwa', 'dda', 'ddu', 'ddi', 'ddaa', 'ddee', 'dde', 'ddo', 'ddwa'];
<?php return ['ja', 'ju', 'ji', 'jaa', 'jee', 'je', 'jo', 'jwa', 'ga', 'gu', 'gi', 'gaa', 'gee', 'ge', 'go', '[?]', 'gwa', '[?]', 'gwi', 'gwaa', 'gwee', 'gwe', '[?]', '[?]', 'gga', 'ggu', 'ggi', 'ggaa', 'ggee', 'gge', 'ggo', '[?]', 'tha', 'thu', 'thi', 'thaa', 'thee', 'the', 'tho', 'thwa', 'cha', 'chu', 'chi', 'chaa', 'chee', 'che', 'cho', 'chwa', 'pha', 'phu', 'phi', 'phaa', 'phee', 'phe', 'pho', 'phwa', 'tsa', 'tsu', 'tsi', 'tsaa', 'tsee', 'tse', 'tso', 'tswa', 'tza', 'tzu', 'tzi', 'tzaa', 'tzee', 'tze', 'tzo', '[?]', 'fa', 'fu', 'fi', 'faa', 'fee', 'fe', 'fo', 'fwa', 'pa', 'pu', 'pi', 'paa', 'pee', 'pe', 'po', 'pwa', 'rya', 'mya', 'fya', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ' ', '.', ',', ';', ':', ':: ', '?', '//', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10+', '20+', '30+', '40+', '50+', '60+', '70+', '80+', '90+', '100+', '10,000+', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'a', 'e', 'i', 'o', 'u', 'v', 'ga', 'ka', 'ge', 'gi', 'go', 'gu', 'gv', 'ha', 'he', 'hi', 'ho', 'hu', 'hv', 'la', 'le', 'li', 'lo', 'lu', 'lv', 'ma', 'me', 'mi', 'mo', 'mu', 'na', 'hna', 'nah', 'ne', 'ni', 'no', 'nu', 'nv', 'qua', 'que', 'qui', 'quo', 'quu', 'quv', 'sa', 's', 'se', 'si', 'so', 'su', 'sv', 'da', 'ta', 'de', 'te', 'di', 'ti', 'do', 'du', 'dv', 'dla', 'tla', 'tle', 'tli', 'tlo', 'tlu', 'tlv', 'tsa', 'tse', 'tsi', 'tso', 'tsu', 'tsv', 'wa', 'we', 'wi', 'wo', 'wu', 'wv', 'ya', 'ye', 'yi', 'yo', 'yu', 'yv', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', 'e', 'aai', 'i', 'ii', 'o', 'oo', 'oo', 'ee', 'i', 'a', 'aa', 'we', 'we', 'wi', 'wi', 'wii', 'wii', 'wo', 'wo', 'woo', 'woo', 'woo', 'wa', 'wa', 'waa', 'waa', 'waa', 'ai', 'w', '\'', 't', 'k', 'sh', 's', 'n', 'w', 'n', '[?]', 'w', 'c', '?', 'l', 'en', 'in', 'on', 'an', 'pe', 'paai', 'pi', 'pii', 'po', 'poo', 'poo', 'hee', 'hi', 'pa', 'paa', 'pwe', 'pwe', 'pwi', 'pwi', 'pwii', 'pwii', 'pwo', 'pwo', 'pwoo', 'pwoo', 'pwa', 'pwa', 'pwaa', 'pwaa', 'pwaa', 'p', 'p', 'h', 'te', 'taai', 'ti', 'tii', 'to', 'too', 'too', 'dee', 'di', 'ta', 'taa', 'twe', 'twe', 'twi', 'twi', 'twii', 'twii', 'two', 'two', 'twoo', 'twoo', 'twa', 'twa', 'twaa', 'twaa', 'twaa', 't', 'tte', 'tti', 'tto', 'tta', 'ke', 'kaai', 'ki', 'kii', 'ko', 'koo', 'koo', 'ka', 'kaa', 'kwe', 'kwe', 'kwi', 'kwi', 'kwii', 'kwii', 'kwo', 'kwo', 'kwoo', 'kwoo', 'kwa', 'kwa', 'kwaa', 'kwaa', 'kwaa', 'k', 'kw', 'keh', 'kih', 'koh', 'kah', 'ce', 'caai', 'ci', 'cii', 'co', 'coo', 'coo', 'ca', 'caa', 'cwe', 'cwe', 'cwi', 'cwi', 'cwii', 'cwii', 'cwo', 'cwo', 'cwoo', 'cwoo', 'cwa', 'cwa', 'cwaa', 'cwaa', 'cwaa', 'c', 'th', 'me', 'maai', 'mi', 'mii', 'mo', 'moo', 'moo', 'ma', 'maa', 'mwe', 'mwe', 'mwi', 'mwi', 'mwii', 'mwii', 'mwo', 'mwo', 'mwoo', 'mwoo', 'mwa', 'mwa', 'mwaa', 'mwaa', 'mwaa', 'm', 'm', 'mh', 'm', 'm', 'ne', 'naai', 'ni', 'nii', 'no', 'noo', 'noo', 'na', 'naa', 'nwe', 'nwe', 'nwa', 'nwa', 'nwaa', 'nwaa', 'nwaa', 'n', 'ng', 'nh', 'le', 'laai', 'li', 'lii', 'lo', 'loo', 'loo', 'la', 'laa', 'lwe', 'lwe', 'lwi', 'lwi', 'lwii', 'lwii', 'lwo', 'lwo', 'lwoo', 'lwoo', 'lwa', 'lwa', 'lwaa', 'lwaa', 'l', 'l', 'l', 'se', 'saai', 'si', 'sii', 'so', 'soo', 'soo', 'sa', 'saa', 'swe', 'swe', 'swi', 'swi', 'swii', 'swii', 'swo', 'swo', 'swoo', 'swoo'];
<?php return ['swa', 'swa', 'swaa', 'swaa', 'swaa', 's', 's', 'sw', 's', 'sk', 'skw', 'sW', 'spwa', 'stwa', 'skwa', 'scwa', 'she', 'shi', 'shii', 'sho', 'shoo', 'sha', 'shaa', 'shwe', 'shwe', 'shwi', 'shwi', 'shwii', 'shwii', 'shwo', 'shwo', 'shwoo', 'shwoo', 'shwa', 'shwa', 'shwaa', 'shwaa', 'sh', 'ye', 'yaai', 'yi', 'yii', 'yo', 'yoo', 'yoo', 'ya', 'yaa', 'ywe', 'ywe', 'ywi', 'ywi', 'ywii', 'ywii', 'ywo', 'ywo', 'ywoo', 'ywoo', 'ywa', 'ywa', 'ywaa', 'ywaa', 'ywaa', 'y', 'y', 'y', 'yi', 're', 're', 'le', 'raai', 'ri', 'rii', 'ro', 'roo', 'lo', 'ra', 'raa', 'la', 'rwaa', 'rwaa', 'r', 'r', 'r', 'fe', 'faai', 'fi', 'fii', 'fo', 'foo', 'fa', 'faa', 'fwaa', 'fwaa', 'f', 'the', 'the', 'thi', 'thi', 'thii', 'thii', 'tho', 'thoo', 'tha', 'thaa', 'thwaa', 'thwaa', 'th', 'tthe', 'tthi', 'ttho', 'ttha', 'tth', 'tye', 'tyi', 'tyo', 'tya', 'he', 'hi', 'hii', 'ho', 'hoo', 'ha', 'haa', 'h', 'h', 'hk', 'qaai', 'qi', 'qii', 'qo', 'qoo', 'qa', 'qaa', 'q', 'tlhe', 'tlhi', 'tlho', 'tlha', 're', 'ri', 'ro', 'ra', 'ngaai', 'ngi', 'ngii', 'ngo', 'ngoo', 'nga', 'ngaa', 'ng', 'nng', 'she', 'shi', 'sho', 'sha', 'the', 'thi', 'tho', 'tha', 'th', 'lhi', 'lhii', 'lho', 'lhoo', 'lha', 'lhaa', 'lh', 'the', 'thi', 'thii', 'tho', 'thoo', 'tha', 'thaa', 'th', 'b', 'e', 'i', 'o', 'a', 'we', 'wi', 'wo', 'wa', 'ne', 'ni', 'no', 'na', 'ke', 'ki', 'ko', 'ka', 'he', 'hi', 'ho', 'ha', 'ghu', 'gho', 'ghe', 'ghee', 'ghi', 'gha', 'ru', 'ro', 're', 'ree', 'ri', 'ra', 'wu', 'wo', 'we', 'wee', 'wi', 'wa', 'hwu', 'hwo', 'hwe', 'hwee', 'hwi', 'hwa', 'thu', 'tho', 'the', 'thee', 'thi', 'tha', 'ttu', 'tto', 'tte', 'ttee', 'tti', 'tta', 'pu', 'po', 'pe', 'pee', 'pi', 'pa', 'p', 'gu', 'go', 'ge', 'gee', 'gi', 'ga', 'khu', 'kho', 'khe', 'khee', 'khi', 'kha', 'kku', 'kko', 'kke', 'kkee', 'kki'];
<?php return ['kka', 'kk', 'nu', 'no', 'ne', 'nee', 'ni', 'na', 'mu', 'mo', 'me', 'mee', 'mi', 'ma', 'yu', 'yo', 'ye', 'yee', 'yi', 'ya', 'ju', 'ju', 'jo', 'je', 'jee', 'ji', 'ji', 'ja', 'jju', 'jjo', 'jje', 'jjee', 'jji', 'jja', 'lu', 'lo', 'le', 'lee', 'li', 'la', 'dlu', 'dlo', 'dle', 'dlee', 'dli', 'dla', 'lhu', 'lho', 'lhe', 'lhee', 'lhi', 'lha', 'tlhu', 'tlho', 'tlhe', 'tlhee', 'tlhi', 'tlha', 'tlu', 'tlo', 'tle', 'tlee', 'tli', 'tla', 'zu', 'zo', 'ze', 'zee', 'zi', 'za', 'z', 'z', 'dzu', 'dzo', 'dze', 'dzee', 'dzi', 'dza', 'su', 'so', 'se', 'see', 'si', 'sa', 'shu', 'sho', 'she', 'shee', 'shi', 'sha', 'sh', 'tsu', 'tso', 'tse', 'tsee', 'tsi', 'tsa', 'chu', 'cho', 'che', 'chee', 'chi', 'cha', 'ttsu', 'ttso', 'ttse', 'ttsee', 'ttsi', 'ttsa', 'X', '.', 'qai', 'ngai', 'nngi', 'nngii', 'nngo', 'nngoo', 'nnga', 'nngaa', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ' ', 'b', 'l', 'f', 's', 'n', 'h', 'd', 't', 'c', 'q', 'm', 'g', 'ng', 'z', 'r', 'a', 'o', 'u', 'e', 'i', 'ch', 'th', 'ph', 'p', 'x', 'p', '<', '>', '[?]', '[?]', '[?]', 'f', 'v', 'u', 'yr', 'y', 'w', 'th', 'th', 'a', 'o', 'ac', 'ae', 'o', 'o', 'o', 'oe', 'on', 'r', 'k', 'c', 'k', 'g', 'ng', 'g', 'g', 'w', 'h', 'h', 'h', 'h', 'n', 'n', 'n', 'i', 'e', 'j', 'g', 'ae', 'a', 'eo', 'p', 'z', 's', 's', 's', 'c', 'z', 't', 't', 'd', 'b', 'b', 'p', 'p', 'e', 'm', 'm', 'm', 'l', 'l', 'ng', 'ng', 'd', 'o', 'ear', 'ior', 'qu', 'qu', 'qu', 's', 'yr', 'yr', 'yr', 'q', 'x', '.', ':', '+', '17', '18', '19', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'k', 'kh', 'g', 'gh', 'ng', 'c', 'ch', 'j', 'jh', 'ny', 't', 'tth', 'd', 'ddh', 'nn', 't', 'th', 'd', 'dh', 'n', 'p', 'ph', 'b', 'bh', 'm', 'y', 'r', 'l', 'v', 'sh', 'ss', 's', 'h', 'l', 'q', 'a', 'aa', 'i', 'ii', 'u', 'uk', 'uu', 'uuv', 'ry', 'ryy', 'ly', 'lyy', 'e', 'ai', 'oo', 'oo', 'au', 'a', 'aa', 'aa', 'i', 'ii', 'y', 'yy', 'u', 'uu', 'ua', 'oe', 'ya', 'ie', 'e', 'ae', 'ai', 'oo', 'au', 'M', 'H', 'a`', '', '', '', 'r', '', '!', '', '', '', '', '', '.', ' // ', ':', '+', '++', ' * ', ' /// ', 'KR', '\'', '[?]', '[?]', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return [' @ ', ' ... ', ', ', '. ', ': ', ' // ', '', '-', ', ', '. ', '', '', '', '', '', '[?]', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'a', 'e', 'i', 'o', 'u', 'O', 'U', 'ee', 'n', 'ng', 'b', 'p', 'q', 'g', 'm', 'l', 's', 'sh', 't', 'd', 'ch', 'j', 'y', 'r', 'w', 'f', 'k', 'kha', 'ts', 'z', 'h', 'zr', 'lh', 'zh', 'ch', '-', 'e', 'i', 'o', 'u', 'O', 'U', 'ng', 'b', 'p', 'q', 'g', 'm', 't', 'd', 'ch', 'j', 'ts', 'y', 'w', 'k', 'g', 'h', 'jy', 'ny', 'dz', 'e', 'i', 'iy', 'U', 'u', 'ng', 'k', 'g', 'h', 'p', 'sh', 't', 'd', 'j', 'f', 'g', 'h', 'ts', 'z', 'r', 'ch', 'zh', 'i', 'k', 'r', 'f', 'zh', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'H', 'X', 'W', 'M', ' 3 ', ' 333 ', 'a', 'i', 'k', 'ng', 'c', 'tt', 'tth', 'dd', 'nn', 't', 'd', 'p', 'ph', 'ss', 'zh', 'z', 'a', 't', 'zh', 'gh', 'ng', 'c', 'jh', 'tta', 'ddh', 't', 'dh', 'ss', 'cy', 'zh', 'z', 'u', 'y', 'bh', '\'', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['A', 'AE', 'ae', 'B', 'C', 'D', 'D', 'E', 'e', 'i', 'J', 'K', 'L', 'M', 'N', 'O', '', 'O', '', 'O', 'Oe', 'Ou', '', '', 'P', 'R', 'R', 'T', 'U', 'u', 'u', 'm', 'V', 'W', 'Z', '', '', '', '', '', '', '', '', '', 'A', 'AE', 'B', 'B', 'D', 'E', 'E', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'N', 'O', 'Ou', 'P', 'R', 'T', 'U', 'W', 'a', 'a', 'a', 'ae', 'b', 'd', 'e', '', 'e', 'e', 'g', 'i', 'k', 'm', '', 'o', '', '', '', 'p', 't', 'u', 'u', 'm', 'v', '', 'b', 'g', 'd', 'f', '', 'i', 'r', 'u', 'v', 'b', 'g', 'r', 'f', '', '', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'g', '', '', '', '', '', 'p', '', '', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', '', 'v', 'x', 'z', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['A', 'a', 'B', 'b', 'B', 'b', 'B', 'b', 'C', 'c', 'D', 'd', 'D', 'd', 'D', 'd', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'H', 'h', 'H', 'h', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'K', 'k', 'K', 'k', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'M', 'm', 'M', 'm', 'M', 'm', 'N', 'n', 'N', 'n', 'N', 'n', 'N', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'P', 'p', 'P', 'p', 'R', 'r', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'V', 'v', 'V', 'v', 'W', 'w', 'W', 'w', 'W', 'w', 'W', 'w', 'W', 'w', 'X', 'x', 'X', 'x', 'Y', 'y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 'h', 't', 'w', 'y', 'a', 's', 's', 's', 'Ss', 'd', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'A', 'a', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'I', 'i', 'I', 'i', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'Y', 'y', 'Y', 'y', 'Y', 'y', 'Y', 'y', 'LL', 'll', 'V', 'v', 'Y', 'y'];
<?php return ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'e', 'e', 'e', 'e', 'e', 'e', '[?]', '[?]', 'E', 'E', 'E', 'E', 'E', 'E', '[?]', '[?]', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'o', 'o', 'o', 'o', 'o', 'o', '[?]', '[?]', 'O', 'O', 'O', 'O', 'O', 'O', '[?]', '[?]', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', '[?]', 'U', '[?]', 'U', '[?]', 'U', '[?]', 'U', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'a', 'a', 'e', 'e', 'e', 'e', 'i', 'i', 'o', 'o', 'u', 'u', 'o', 'o', '[?]', '[?]', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'a', 'a', 'a', 'a', 'a', '[?]', 'a', 'a', 'A', 'A', 'A', 'A', 'A', '\'', 'i', '\'', '~', '"~', 'e', 'e', 'e', '[?]', 'e', 'e', 'E', 'E', 'E', 'E', 'E', '\'`', '\'\'', '\'~', 'i', 'i', 'i', 'i', '[?]', '[?]', 'i', 'i', 'I', 'I', 'I', 'I', '[?]', '`\'', '`\'', '`~', 'u', 'u', 'u', 'u', 'R', 'R', 'u', 'u', 'U', 'U', 'U', 'U', 'R', '"`', '"\'', '`', '[?]', '[?]', 'o', 'o', 'o', '[?]', 'o', 'o', 'O', 'O', 'O', 'O', 'O', '\'', '`', '[?]'];
<?php return [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', '', '', '', '-', '-', '-', '-', '--', '--', '||', '_', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '+', '++', '*', '*>', '.', '..', '...', '.', "\n",
    "\n\n",
    '', '', '', '', '', ' ', '%0', '%00', '\'', '\'\'', '\'\'\'', '`', '``', '```', '^', '<', '>', '*', '!!', '!?', '-', '_', '-', '^', '***', '--', '/', '-[', ']-', '??', '?!', '!?', '7', 'PP', '(]', '[)', '*', '[?]', '[?]', '[?]', '%', '~', '[?]', '[?]', '[?]', "''''",    // 0x57
    '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ' ', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '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', '[?]', '[?]', '[?]', 'ECU', 'CL', 'Cr', 'Fr.', 'L.', 'mil', 'N', 'Pts', 'Rs', 'W', 'NS', 'D', 'EUR', 'K', 'T', 'Dr', 'Pf', 'P', 'G', 'A', 'UAH', 'C|', 'L', 'Sm', 'T', 'Rs', 'L', 'M', 'm', 'R', 'l', 'BTC', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ];
<?php return [' a/c ', ' a/s ', 'C', '', '', ' c/o ', ' c/u ', '', '', '', 'g', 'H', 'H', 'H', 'h', '', 'I', 'I', 'L', 'l', '', 'N', 'No. ', '', '', 'P', 'Q', 'R', 'R', 'R', '', '', '(sm)', 'TEL', '(tm)', '', 'Z', '', '', '', 'Z', '', 'K', 'A', 'B', 'C', 'e', 'e', 'E', 'F', 'F', 'M', 'o', '', '', '', '', 'i', '', 'FAX', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', 'D', 'd', 'e', 'i', 'j', '[?]', '[?]', '[?]', '[?]', 'F', '[?]', ' 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', '(D', 'D)', '((|))', ')', '[?]', '[?]', '[?]', '[?]', '[?]', ' 0/3 ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '-', '|', '-', '|', '-', '|', '\\', '/', '\\', '/', '-', '-', '~', '~', '-', '|', '-', '|', '-', '-', '-', '|', '-', '|', '|', '-', '-', '-', '-', '-', '-', '|', '|', '|', '|', '|', '|', '|', '^', 'V', '\\', '=', 'V', '^', '-', '-', '|', '|', '-', '-', '|', '|', '=', '|', '=', '=', '|', '=', '|', '=', '=', '=', '=', '=', '=', '|', '=', '|', '=', '|', '\\', '/', '\\', '/', '=', '=', '~', '~', '|', '|', '-', '|', '-', '|', '-', '-', '-', '|', '-', '|', '|', '|', '|', '|', '|', '|', '-', '\\', '\\', '|', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '-', '[?]', '[?]', '/', '\\', '*', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '|', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ':', '[?]', '[?]', '[?]', '[?]', '[?]', '~', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '<=', '>=', '<=', '>=', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '^', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '<', '> ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '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', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '0'];
<?php return ['-', '-', '|', '|', '-', '-', '|', '|', '-', '-', '|', '|', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '-', '-', '|', '|', '-', '|', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '/', '\\', 'X', '-', '|', '-', '|', '-', '|', '-', '|', '-', '|', '-', '|', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '-', '|', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '^', '^', '^', '^', '>', '>', '>', '>', '>', '>', 'V', 'V', 'V', 'V', '<', '<', '<', '<', '<', '<', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '#', '#', '#', '#', '#', '^', '^', '^', 'O', '#', '#', '#', '#', 'O', 'O', 'O', 'O', '/', '\\\\', '\\\\', '#', '#', '#', '#', '/'];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '#', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '*', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '|', '', '', '', '', '', '', '[?]', '[?]', '', '!', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[', '[?]', '<', '> ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return [' ', 'a', '1', 'b', '\'', 'k', '2', 'l', '@', 'c', 'i', 'f', '/', 'm', 's', 'p', '"', 'e', '3', 'h', '9', 'o', '6', 'r', '^', 'd', 'j', 'g', '>', 'n', 't', 'q', ',', '*', '5', '<', '-', 'u', '8', 'v', '.', '%', '[', '$', '+', 'x', '!', '&', ';', ':', '4', '\\', '0', 'z', '7', '(', '_', '?', 'w', ']', '#', 'y', ')', '=', '[d7]', '[d17]', '[d27]', '[d127]', '[d37]', '[d137]', '[d237]', '[d1237]', '[d47]', '[d147]', '[d247]', '[d1247]', '[d347]', '[d1347]', '[d2347]', '[d12347]', '[d57]', '[d157]', '[d257]', '[d1257]', '[d357]', '[d1357]', '[d2357]', '[d12357]', '[d457]', '[d1457]', '[d2457]', '[d12457]', '[d3457]', '[d13457]', '[d23457]', '[d123457]', '[d67]', '[d167]', '[d267]', '[d1267]', '[d367]', '[d1367]', '[d2367]', '[d12367]', '[d467]', '[d1467]', '[d2467]', '[d12467]', '[d3467]', '[d13467]', '[d23467]', '[d123467]', '[d567]', '[d1567]', '[d2567]', '[d12567]', '[d3567]', '[d13567]', '[d23567]', '[d123567]', '[d4567]', '[d14567]', '[d24567]', '[d124567]', '[d34567]', '[d134567]', '[d234567]', '[d1234567]', '[d8]', '[d18]', '[d28]', '[d128]', '[d38]', '[d138]', '[d238]', '[d1238]', '[d48]', '[d148]', '[d248]', '[d1248]', '[d348]', '[d1348]', '[d2348]', '[d12348]', '[d58]', '[d158]', '[d258]', '[d1258]', '[d358]', '[d1358]', '[d2358]', '[d12358]', '[d458]', '[d1458]', '[d2458]', '[d12458]', '[d3458]', '[d13458]', '[d23458]', '[d123458]', '[d68]', '[d168]', '[d268]', '[d1268]', '[d368]', '[d1368]', '[d2368]', '[d12368]', '[d468]', '[d1468]', '[d2468]', '[d12468]', '[d3468]', '[d13468]', '[d23468]', '[d123468]', '[d568]', '[d1568]', '[d2568]', '[d12568]', '[d3568]', '[d13568]', '[d23568]', '[d123568]', '[d4568]', '[d14568]', '[d24568]', '[d124568]', '[d34568]', '[d134568]', '[d234568]', '[d1234568]', '[d78]', '[d178]', '[d278]', '[d1278]', '[d378]', '[d1378]', '[d2378]', '[d12378]', '[d478]', '[d1478]', '[d2478]', '[d12478]', '[d3478]', '[d13478]', '[d23478]', '[d123478]', '[d578]', '[d1578]', '[d2578]', '[d12578]', '[d3578]', '[d13578]', '[d23578]', '[d123578]', '[d4578]', '[d14578]', '[d24578]', '[d124578]', '[d34578]', '[d134578]', '[d234578]', '[d1234578]', '[d678]', '[d1678]', '[d2678]', '[d12678]', '[d3678]', '[d13678]', '[d23678]', '[d123678]', '[d4678]', '[d14678]', '[d24678]', '[d124678]', '[d34678]', '[d134678]', '[d234678]', '[d1234678]', '[d5678]', '[d15678]', '[d25678]', '[d125678]', '[d35678]', '[d135678]', '[d235678]', '[d1235678]', '[d45678]', '[d145678]', '[d245678]', '[d1245678]', '[d345678]', '[d1345678]', '[d2345678]', '[d12345678]'];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '{', '} ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '::=', '==', '===', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'L', 'l', 'L', 'P', 'R', 'a', 't', 'H', 'h', 'K', 'k', 'Z', 'z', '', 'M', 'A', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['r', 'r.', '[?]', '[?]', '[?]', '[?]', 'T', 'T.', '[?]', 's', '[?]', '[]', '\\', '/', '[?]', '__', '[?]', '[?]', '>', '%', '[?]', '[?]', '>', '=', '[?]', '/', '-', '~', '\\', '/', '~', '~', '|-', '-|', '[?]', '[?]', '[?]', '[?]', '<=', '=>', '((', '))', '[?]', '[?]', '::', '[?]', '?', '\'', 'o', '.', ',', '.', ',', ';', '[?]', '[?]', '[?]', '[?]', '----', '------', 'x', '|', '[?]', '[?]', '=', ',', '"', '`--', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?]', '[?]'];
<?php return [' ', ', ', '. ', '"', '[JIS]', '"', '/', '0', '<', '> ', '<<', '>> ', '[', '] ', '{', '} ', '[(', ')] ', '@', 'X ', '[', '] ', '[[', ']] ', '((', ')) ', '[[', ']] ', '~ ', '``', '\'\'', ',,', '@', '1', '2', '3', '4', '5', '6', '7', '8', '9', '', '', '', '', '', '', '~', '+', '+', '+', '+', '', '@', ' // ', '+10+', '+20+', '+30+', '[?]', '[?]', '[?]', '', '', '[?]', 'a', 'a', 'i', 'i', 'u', 'u', 'e', 'e', 'o', 'o', 'ka', 'ga', 'ki', 'gi', 'ku', 'gu', 'ke', 'ge', 'ko', 'go', 'sa', 'za', 'shi',   // 0x57
    'zi', 'su', 'zu', 'se', 'ze', 'so', 'zo', 'ta', 'da', 'chi',   // 0x61
    'di', 'tsu',   // 0x63
    'tsu',   // 0x64
    'du', 'te', 'de', 'to', 'do', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'ba', 'pa', 'hi', 'bi', 'pi', 'hu', 'bu', 'pu', 'he', 'be', 'pe', 'ho', 'bo', 'po', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'ya', 'yu', 'yu', 'yo', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wa', 'wi', 'we', 'wo', 'n', 'vu', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '"', '"', '[?]', '[?]', 'a', 'a', 'i', 'i', 'u', 'u', 'e', 'e', 'o', 'o', 'ka', 'ga', 'ki', 'gi', 'ku', 'gu', 'ke', 'ge', 'ko', 'go', 'sa', 'za', 'shi',   // 0xb7
    'zi', 'su', 'zu', 'se', 'ze', 'so', 'zo', 'ta', 'da', 'chi',   // 0xc1
    'di', 'tsu',   // 0xc3
    'tsu',   // 0xc4
    'du', 'te', 'de', 'to', 'do', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'ba', 'pa', 'hi', 'bi', 'pi', 'hu', 'bu', 'pu', 'he', 'be', 'pe', 'ho', 'bo', 'po', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'ya', 'yu', 'yu', 'yo', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wa', 'wi', 'we', 'wo', 'n', 'vu', 'ka', 'ke', 'va', 'vi', 've', 'vo', '', '', '"', '"', ];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', 'B', 'P', 'M', 'F', 'D', 'T', 'N', 'L', 'G', 'K', 'H', 'J', 'Q', 'X', 'ZH', 'CH', 'SH', 'R', 'Z', 'C', 'S', 'A', 'O', 'E', 'EH', 'AI', 'EI', 'AU', 'OU', 'AN', 'EN', 'ANG', 'ENG', 'ER', 'I', 'U', 'IU', 'V', 'NG', 'GN', '[?]', '[?]', '[?]', '[?]', 'g', 'gg', 'gs', 'n', 'nj', 'nh', 'd', 'dd', 'r', 'lg', 'lm', 'lb', 'ls', 'lt', 'lp', 'rh', 'm', 'b', 'bb', 'bs', 's', 'ss', '', 'j', 'jj', 'c', 'k', 't', 'p', 'h', 'a', 'ae', 'ya', 'yae', 'eo', 'e', 'yeo', 'ye', 'o', 'wa', 'wae', 'oe', 'yo', 'u', 'weo', 'we', 'wi', 'yu', 'eu', 'yi', 'i', '', 'nn', 'nd', 'ns', 'nZ', 'lgs', 'ld', 'lbs', 'lZ', 'lQ', 'mb', 'ms', 'mZ', 'mN', 'bg', '', 'bsg', 'bst', 'bj', 'bt', 'bN', 'bbN', 'sg', 'sn', 'sd', 'sb', 'sj', 'Z', '', 'N', 'Ns', 'NZ', 'pN', 'hh', 'Q', 'yo-ya', 'yo-yae', 'yo-i', 'yu-yeo', 'yu-ye', 'yu-i', 'U', 'U-i', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'BU', 'ZI', 'JI', 'GU', 'EE', 'ENN', 'OO', 'ONN', 'IR', 'ANN', 'INN', 'UNN', 'IM', 'NGG', 'AINN', 'AUNN', 'AM', 'OM', 'ONG', 'INNN', 'P', 'T', 'K', 'H', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['(g)', '(n)', '(d)', '(r)', '(m)', '(b)', '(s)', '()', '(j)', '(c)', '(k)', '(t)', '(p)', '(h)', '(ga)', '(na)', '(da)', '(ra)', '(ma)', '(ba)', '(sa)', '(a)', '(ja)', '(ca)', '(ka)', '(ta)', '(pa)', '(ha)', '(ju)', '[?]', '[?]', '[?]', '(1) ', '(2) ', '(3) ', '(4) ', '(5) ', '(6) ', '(7) ', '(8) ', '(9) ', '(10) ', '(Yue) ', '(Huo) ', '(Shui) ', '(Mu) ', '(Jin) ', '(Tu) ', '(Ri) ', '(Zhu) ', '(You) ', '(She) ', '(Ming) ', '(Te) ', '(Cai) ', '(Zhu) ', '(Lao) ', '(Dai) ', '(Hu) ', '(Xue) ', '(Jian) ', '(Qi) ', '(Zi) ', '(Xie) ', '(Ji) ', '(Xiu) ', '<<', '>>', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '(g)', '(n)', '(d)', '(r)', '(m)', '(b)', '(s)', '()', '(j)', '(c)', '(k)', '(t)', '(p)', '(h)', '(ga)', '(na)', '(da)', '(ra)', '(ma)', '(ba)', '(sa)', '(a)', '(ja)', '(ca)', '(ka)', '(ta)', '(pa)', '(ha)', '[?]', '[?]', '[?]', 'KIS ', '(1) ', '(2) ', '(3) ', '(4) ', '(5) ', '(6) ', '(7) ', '(8) ', '(9) ', '(10) ', '(Yue) ', '(Huo) ', '(Shui) ', '(Mu) ', '(Jin) ', '(Tu) ', '(Ri) ', '(Zhu) ', '(You) ', '(She) ', '(Ming) ', '(Te) ', '(Cai) ', '(Zhu) ', '(Lao) ', '(Mi) ', '(Nan) ', '(Nu) ', '(Shi) ', '(You) ', '(Yin) ', '(Zhu) ', '(Xiang) ', '(Xiu) ', '(Xie) ', '(Zheng) ', '(Shang) ', '(Zhong) ', '(Xia) ', '(Zuo) ', '(You) ', '(Yi) ', '(Zong) ', '(Xue) ', '(Jian) ', '(Qi) ', '(Zi) ', '(Xie) ', '(Ye) ', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '1M', '2M', '3M', '4M', '5M', '6M', '7M', '8M', '9M', '10M', '11M', '12M', 'Hg', 'erg', 'eV', 'LTD', 'a', 'i', 'u', 'u', 'o', 'ka', 'ki', 'ku', 'ke', 'ko', 'sa', 'si', 'su', 'se', 'so', 'ta', 'ti', 'tu', 'te', 'to', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'hi', 'hu', 'he', 'ho', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'yu', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wi', 'we', 'wo'];
<?php return ['apartment', 'alpha', 'ampere', 'are', 'inning', 'inch', 'won', 'escudo', 'acre', 'ounce', 'ohm', 'kai-ri', 'carat', 'calorie', 'gallon', 'gamma', 'giga', 'guinea', 'curie', 'guilder', 'kilo', 'kilogram', 'kilometer', 'kilowatt', 'gram', 'gram ton', 'cruzeiro', 'krone', 'case', 'koruna', 'co-op', 'cycle', 'centime', 'shilling', 'centi', 'cent', 'dozen', 'desi', 'dollar', 'ton', 'nano', 'knot', 'heights', 'percent', 'parts', 'barrel', 'piaster', 'picul', 'pico', 'building', 'farad', 'feet', 'bushel', 'franc', 'hectare', 'peso', 'pfennig', 'hertz', 'pence', 'page', 'beta', 'point', 'volt', 'hon', 'pound', 'hall', 'horn', 'micro', 'mile', 'mach', 'mark', 'mansion', 'micron', 'milli', 'millibar', 'mega', 'megaton', 'meter', 'yard', 'yard', 'yuan', 'liter', 'lira', 'rupee', 'ruble', 'rem', 'roentgen', 'watt', '0h', '1h', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', '10h', '11h', '12h', '13h', '14h', '15h', '16h', '17h', '18h', '19h', '20h', '21h', '22h', '23h', '24h', 'hPa', 'da', 'AU', 'bar', 'oV', 'pc', 'dm', 'dm^2', 'dm^3', 'IU', 'Heisei', 'Syouwa', 'Taisyou', 'Meiji', 'Inc.', 'pA', 'nA', 'microamp', 'mA', 'kA', 'kB', 'MB', 'GB', 'cal', 'kcal', 'pF', 'nF', 'microFarad', 'microgram', 'mg', 'kg', 'Hz', 'kHz', 'MHz', 'GHz', 'THz', 'microliter', 'ml', 'dl', 'kl', 'fm', 'nm', 'micrometer', 'mm', 'cm', 'km', 'mm^2', 'cm^2', 'm^2', 'km^2', 'mm^3', 'cm^3', 'm^3', 'km^3', 'm/s', 'm/s^2', 'Pa', 'kPa', 'MPa', 'GPa', 'rad', 'rad/s', 'rad/s^2', 'ps', 'ns', 'microsecond', 'ms', 'pV', 'nV', 'microvolt', 'mV', 'kV', 'MV', 'pW', 'nW', 'microwatt', 'mW', 'kW', 'MW', 'kOhm', 'MOhm', 'a.m.', 'Bq', 'cc', 'cd', 'C/kg', 'Co.', 'dB', 'Gy', 'ha', 'HP', 'in', 'K.K.', 'KM', 'kt', 'lm', 'ln', 'log', 'lx', 'mb', 'mil', 'mol', 'pH', 'p.m.', 'PPM', 'PR', 'sr', 'Sv', 'Wb', '[?]', '[?]', '1d', '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', '10d', '11d', '12d', '13d', '14d', '15d', '16d', '17d', '18d', '19d', '20d', '21d', '22d', '23d', '24d', '25d', '26d', '27d', '28d', '29d', '30d', '31d', 'gal'];
<?php return ['[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['Yi ', 'Ding ', 'Kao ', 'Qi ', 'Shang ', 'Xia ', '[?] ', 'Mo ', 'Zhang ', 'San ', 'Shang ', 'Xia ', 'Ji ', 'Bu ', 'Yu ', 'Mian ', 'Gai ', 'Chou ', 'Chou ', 'Zhuan ', 'Qie ', 'Pi ', 'Shi ', 'Shi ', 'Qiu ', 'Bing ', 'Ye ', 'Cong ', 'Dong ', 'Si ', 'Cheng ', 'Diu ', 'Qiu ', 'Liang ', 'Diu ', 'You ', 'Liang ', 'Yan ', 'Bing ', 'Sang ', 'Gun ', 'Jiu ', 'Ge ', 'Ya ', 'Qiang ', 'Zhong ', 'Ji ', 'Jie ', 'Feng ', 'Guan ', 'Chuan ', 'Chan ', 'Lin ', 'Zhuo ', 'Zhu ', 'Ha ', 'Wan ', 'Dan ', 'Wei ', 'Zhu ', 'Jing ', 'Li ', 'Ju ', 'Pie ', 'Fu ', 'Yi ', 'Yi ', 'Nai ', 'Shime ', 'Jiu ', 'Jiu ', 'Zhe ', 'Yao ', 'Yi ', '[?] ', 'Zhi ', 'Wu ', 'Zha ', 'Hu ', 'Fa ', 'Le ', 'Zhong ', 'Ping ', 'Pang ', 'Qiao ', 'Hu ', 'Guai ', 'Cheng ', 'Cheng ', 'Yi ', 'Yin ', '[?] ', 'Mie ', 'Jiu ', 'Qi ', 'Ye ', 'Xi ', 'Xiang ', 'Gai ', 'Diu ', 'Hal ', '[?] ', 'Shu ', 'Twul ', 'Shi ', 'Ji ', 'Nang ', 'Jia ', 'Kel ', 'Shi ', '[?] ', 'Ol ', 'Mai ', 'Luan ', 'Cal ', 'Ru ', 'Xue ', 'Yan ', 'Fu ', 'Sha ', 'Na ', 'Gan ', 'Sol ', 'El ', 'Cwul ', '[?] ', 'Gan ', 'Chi ', 'Gui ', 'Gan ', 'Luan ', 'Lin ', 'Yi ', 'Jue ', 'Liao ', 'Ma ', 'Yu ', 'Zheng ', 'Shi ', 'Shi ', 'Er ', 'Chu ', 'Yu ', 'Yu ', 'Yu ', 'Yun ', 'Hu ', 'Qi ', 'Wu ', 'Jing ', 'Si ', 'Sui ', 'Gen ', 'Gen ', 'Ya ', 'Xie ', 'Ya ', 'Qi ', 'Ya ', 'Ji ', 'Tou ', 'Wang ', 'Kang ', 'Ta ', 'Jiao ', 'Hai ', 'Yi ', 'Chan ', 'Heng ', 'Mu ', '[?] ', 'Xiang ', 'Jing ', 'Ting ', 'Liang ', 'Xiang ', 'Jing ', 'Ye ', 'Qin ', 'Bo ', 'You ', 'Xie ', 'Dan ', 'Lian ', 'Duo ', 'Wei ', 'Ren ', 'Ren ', 'Ji ', 'La ', 'Wang ', 'Yi ', 'Shi ', 'Ren ', 'Le ', 'Ding ', 'Ze ', 'Jin ', 'Pu ', 'Chou ', 'Ba ', 'Zhang ', 'Jin ', 'Jie ', 'Bing ', 'Reng ', 'Cong ', 'Fo ', 'San ', 'Lun ', 'Sya ', 'Cang ', 'Zi ', 'Shi ', 'Ta ', 'Zhang ', 'Fu ', 'Xian ', 'Xian ', 'Tuo ', 'Hong ', 'Tong ', 'Ren ', 'Qian ', 'Gan ', 'Yi ', 'Di ', 'Dai ', 'Ling ', 'Yi ', 'Chao ', 'Chang ', 'Sa ', '[?] ', 'Yi ', 'Mu ', 'Men ', 'Ren ', 'Jia ', 'Chao ', 'Yang ', 'Qian ', 'Zhong ', 'Pi ', 'Wan ', 'Wu ', 'Jian ', 'Jie ', 'Yao ', 'Feng ', 'Cang ', 'Ren ', 'Wang ', 'Fen ', 'Di ', 'Fang '];
<?php return ['Zhong ', 'Qi ', 'Pei ', 'Yu ', 'Diao ', 'Dun ', 'Wen ', 'Yi ', 'Xin ', 'Kang ', 'Yi ', 'Ji ', 'Ai ', 'Wu ', 'Ji ', 'Fu ', 'Fa ', 'Xiu ', 'Jin ', 'Bei ', 'Dan ', 'Fu ', 'Tang ', 'Zhong ', 'You ', 'Huo ', 'Hui ', 'Yu ', 'Cui ', 'Chuan ', 'San ', 'Wei ', 'Chuan ', 'Che ', 'Ya ', 'Xian ', 'Shang ', 'Chang ', 'Lun ', 'Cang ', 'Xun ', 'Xin ', 'Wei ', 'Zhu ', '[?] ', 'Xuan ', 'Nu ', 'Bo ', 'Gu ', 'Ni ', 'Ni ', 'Xie ', 'Ban ', 'Xu ', 'Ling ', 'Zhou ', 'Shen ', 'Qu ', 'Si ', 'Beng ', 'Si ', 'Jia ', 'Pi ', 'Yi ', 'Si ', 'Ai ', 'Zheng ', 'Dian ', 'Han ', 'Mai ', 'Dan ', 'Zhu ', 'Bu ', 'Qu ', 'Bi ', 'Shao ', 'Ci ', 'Wei ', 'Di ', 'Zhu ', 'Zuo ', 'You ', 'Yang ', 'Ti ', 'Zhan ', 'He ', 'Bi ', 'Tuo ', 'She ', 'Yu ', 'Yi ', 'Fo ', 'Zuo ', 'Kou ', 'Ning ', 'Tong ', 'Ni ', 'Xuan ', 'Qu ', 'Yong ', 'Wa ', 'Qian ', '[?] ', 'Ka ', '[?] ', 'Pei ', 'Huai ', 'He ', 'Lao ', 'Xiang ', 'Ge ', 'Yang ', 'Bai ', 'Fa ', 'Ming ', 'Jia ', 'Er ', 'Bing ', 'Ji ', 'Hen ', 'Huo ', 'Gui ', 'Quan ', 'Tiao ', 'Jiao ', 'Ci ', 'Yi ', 'Shi ', 'Xing ', 'Shen ', 'Tuo ', 'Kan ', 'Zhi ', 'Gai ', 'Lai ', 'Yi ', 'Chi ', 'Kua ', 'Guang ', 'Li ', 'Yin ', 'Shi ', 'Mi ', 'Zhu ', 'Xu ', 'You ', 'An ', 'Lu ', 'Mou ', 'Er ', 'Lun ', 'Tong ', 'Cha ', 'Chi ', 'Xun ', 'Gong ', 'Zhou ', 'Yi ', 'Ru ', 'Jian ', 'Xia ', 'Jia ', 'Zai ', 'Lu ', 'Ko ', 'Jiao ', 'Zhen ', 'Ce ', 'Qiao ', 'Kuai ', 'Chai ', 'Ning ', 'Nong ', 'Jin ', 'Wu ', 'Hou ', 'Jiong ', 'Cheng ', 'Zhen ', 'Zuo ', 'Chou ', 'Qin ', 'Lu ', 'Ju ', 'Shu ', 'Ting ', 'Shen ', 'Tuo ', 'Bo ', 'Nan ', 'Hao ', 'Bian ', 'Tui ', 'Yu ', 'Xi ', 'Cu ', 'E ', 'Qiu ', 'Xu ', 'Kuang ', 'Ku ', 'Wu ', 'Jun ', 'Yi ', 'Fu ', 'Lang ', 'Zu ', 'Qiao ', 'Li ', 'Yong ', 'Hun ', 'Jing ', 'Xian ', 'San ', 'Pai ', 'Su ', 'Fu ', 'Xi ', 'Li ', 'Fu ', 'Ping ', 'Bao ', 'Yu ', 'Si ', 'Xia ', 'Xin ', 'Xiu ', 'Yu ', 'Ti ', 'Che ', 'Chou ', '[?] ', 'Yan ', 'Lia ', 'Li ', 'Lai ', '[?] ', 'Jian ', 'Xiu ', 'Fu ', 'He ', 'Ju ', 'Xiao ', 'Pai ', 'Jian ', 'Biao ', 'Chu ', 'Fei ', 'Feng ', 'Ya ', 'An ', 'Bei ', 'Yu ', 'Xin ', 'Bi ', 'Jian '];
<?php return ['Chang ', 'Chi ', 'Bing ', 'Zan ', 'Yao ', 'Cui ', 'Lia ', 'Wan ', 'Lai ', 'Cang ', 'Zong ', 'Ge ', 'Guan ', 'Bei ', 'Tian ', 'Shu ', 'Shu ', 'Men ', 'Dao ', 'Tan ', 'Jue ', 'Chui ', 'Xing ', 'Peng ', 'Tang ', 'Hou ', 'Yi ', 'Qi ', 'Ti ', 'Gan ', 'Jing ', 'Jie ', 'Sui ', 'Chang ', 'Jie ', 'Fang ', 'Zhi ', 'Kong ', 'Juan ', 'Zong ', 'Ju ', 'Qian ', 'Ni ', 'Lun ', 'Zhuo ', 'Wei ', 'Luo ', 'Song ', 'Leng ', 'Hun ', 'Dong ', 'Zi ', 'Ben ', 'Wu ', 'Ju ', 'Nai ', 'Cai ', 'Jian ', 'Zhai ', 'Ye ', 'Zhi ', 'Sha ', 'Qing ', '[?] ', 'Ying ', 'Cheng ', 'Jian ', 'Yan ', 'Nuan ', 'Zhong ', 'Chun ', 'Jia ', 'Jie ', 'Wei ', 'Yu ', 'Bing ', 'Ruo ', 'Ti ', 'Wei ', 'Pian ', 'Yan ', 'Feng ', 'Tang ', 'Wo ', 'E ', 'Xie ', 'Che ', 'Sheng ', 'Kan ', 'Di ', 'Zuo ', 'Cha ', 'Ting ', 'Bei ', 'Ye ', 'Huang ', 'Yao ', 'Zhan ', 'Chou ', 'Yan ', 'You ', 'Jian ', 'Xu ', 'Zha ', 'Ci ', 'Fu ', 'Bi ', 'Zhi ', 'Zong ', 'Mian ', 'Ji ', 'Yi ', 'Xie ', 'Xun ', 'Si ', 'Duan ', 'Ce ', 'Zhen ', 'Ou ', 'Tou ', 'Tou ', 'Bei ', 'Za ', 'Lu ', 'Jie ', 'Wei ', 'Fen ', 'Chang ', 'Gui ', 'Sou ', 'Zhi ', 'Su ', 'Xia ', 'Fu ', 'Yuan ', 'Rong ', 'Li ', 'Ru ', 'Yun ', 'Gou ', 'Ma ', 'Bang ', 'Dian ', 'Tang ', 'Hao ', 'Jie ', 'Xi ', 'Shan ', 'Qian ', 'Jue ', 'Cang ', 'Chu ', 'San ', 'Bei ', 'Xiao ', 'Yong ', 'Yao ', 'Tan ', 'Suo ', 'Yang ', 'Fa ', 'Bing ', 'Jia ', 'Dai ', 'Zai ', 'Tang ', '[?] ', 'Bin ', 'Chu ', 'Nuo ', 'Can ', 'Lei ', 'Cui ', 'Yong ', 'Zao ', 'Zong ', 'Peng ', 'Song ', 'Ao ', 'Chuan ', 'Yu ', 'Zhai ', 'Cou ', 'Shang ', 'Qiang ', 'Jing ', 'Chi ', 'Sha ', 'Han ', 'Zhang ', 'Qing ', 'Yan ', 'Di ', 'Xi ', 'Lu ', 'Bei ', 'Piao ', 'Jin ', 'Lian ', 'Lu ', 'Man ', 'Qian ', 'Xian ', 'Tan ', 'Ying ', 'Dong ', 'Zhuan ', 'Xiang ', 'Shan ', 'Qiao ', 'Jiong ', 'Tui ', 'Zun ', 'Pu ', 'Xi ', 'Lao ', 'Chang ', 'Guang ', 'Liao ', 'Qi ', 'Deng ', 'Chan ', 'Wei ', 'Ji ', 'Fan ', 'Hui ', 'Chuan ', 'Jian ', 'Dan ', 'Jiao ', 'Jiu ', 'Seng ', 'Fen ', 'Xian ', 'Jue ', 'E ', 'Jiao ', 'Jian ', 'Tong ', 'Lin ', 'Bo ', 'Gu ', '[?] ', 'Su ', 'Xian ', 'Jiang ', 'Min ', 'Ye ', 'Jin ', 'Jia ', 'Qiao ', 'Pi ', 'Feng ', 'Zhou ', 'Ai ', 'Sai '];
<?php return ['Yi ', 'Jun ', 'Nong ', 'Chan ', 'Yi ', 'Dang ', 'Jing ', 'Xuan ', 'Kuai ', 'Jian ', 'Chu ', 'Dan ', 'Jiao ', 'Sha ', 'Zai ', '[?] ', 'Bin ', 'An ', 'Ru ', 'Tai ', 'Chou ', 'Chai ', 'Lan ', 'Ni ', 'Jin ', 'Qian ', 'Meng ', 'Wu ', 'Ning ', 'Qiong ', 'Ni ', 'Chang ', 'Lie ', 'Lei ', 'Lu ', 'Kuang ', 'Bao ', 'Du ', 'Biao ', 'Zan ', 'Zhi ', 'Si ', 'You ', 'Hao ', 'Chen ', 'Chen ', 'Li ', 'Teng ', 'Wei ', 'Long ', 'Chu ', 'Chan ', 'Rang ', 'Shu ', 'Hui ', 'Li ', 'Luo ', 'Zan ', 'Nuo ', 'Tang ', 'Yan ', 'Lei ', 'Nang ', 'Er ', 'Wu ', 'Yun ', 'Zan ', 'Yuan ', 'Xiong ', 'Chong ', 'Zhao ', 'Xiong ', 'Xian ', 'Guang ', 'Dui ', 'Ke ', 'Dui ', 'Mian ', 'Tu ', 'Chang ', 'Er ', 'Dui ', 'Er ', 'Xin ', 'Tu ', 'Si ', 'Yan ', 'Yan ', 'Shi ', 'Shi ', 'Dang ', 'Qian ', 'Dou ', 'Fen ', 'Mao ', 'Shen ', 'Dou ', 'Bai ', 'Jing ', 'Li ', 'Huang ', 'Ru ', 'Wang ', 'Nei ', 'Quan ', 'Liang ', 'Yu ', 'Ba ', 'Gong ', 'Liu ', 'Xi ', '[?] ', 'Lan ', 'Gong ', 'Tian ', 'Guan ', 'Xing ', 'Bing ', 'Qi ', 'Ju ', 'Dian ', 'Zi ', 'Ppwun ', 'Yang ', 'Jian ', 'Shou ', 'Ji ', 'Yi ', 'Ji ', 'Chan ', 'Jiong ', 'Mao ', 'Ran ', 'Nei ', 'Yuan ', 'Mao ', 'Gang ', 'Ran ', 'Ce ', 'Jiong ', 'Ce ', 'Zai ', 'Gua ', 'Jiong ', 'Mao ', 'Zhou ', 'Mou ', 'Gou ', 'Xu ', 'Mian ', 'Mi ', 'Rong ', 'Yin ', 'Xie ', 'Kan ', 'Jun ', 'Nong ', 'Yi ', 'Mi ', 'Shi ', 'Guan ', 'Meng ', 'Zhong ', 'Ju ', 'Yuan ', 'Ming ', 'Kou ', 'Lam ', 'Fu ', 'Xie ', 'Mi ', 'Bing ', 'Dong ', 'Tai ', 'Gang ', 'Feng ', 'Bing ', 'Hu ', 'Chong ', 'Jue ', 'Hu ', 'Kuang ', 'Ye ', 'Leng ', 'Pan ', 'Fu ', 'Min ', 'Dong ', 'Xian ', 'Lie ', 'Xia ', 'Jian ', 'Jing ', 'Shu ', 'Mei ', 'Tu ', 'Qi ', 'Gu ', 'Zhun ', 'Song ', 'Jing ', 'Liang ', 'Qing ', 'Diao ', 'Ling ', 'Dong ', 'Gan ', 'Jian ', 'Yin ', 'Cou ', 'Yi ', 'Li ', 'Cang ', 'Ming ', 'Zhuen ', 'Cui ', 'Si ', 'Duo ', 'Jin ', 'Lin ', 'Lin ', 'Ning ', 'Xi ', 'Du ', 'Ji ', 'Fan ', 'Fan ', 'Fan ', 'Feng ', 'Ju ', 'Chu ', 'Tako ', 'Feng ', 'Mok ', 'Ci ', 'Fu ', 'Feng ', 'Ping ', 'Feng ', 'Kai ', 'Huang ', 'Kai ', 'Gan ', 'Deng ', 'Ping ', 'Qu ', 'Xiong ', 'Kuai ', 'Tu ', 'Ao ', 'Chu ', 'Ji ', 'Dang ', 'Han ', 'Han ', 'Zao '];
<?php return ['Dao ', 'Diao ', 'Dao ', 'Ren ', 'Ren ', 'Chuang ', 'Fen ', 'Qie ', 'Yi ', 'Ji ', 'Kan ', 'Qian ', 'Cun ', 'Chu ', 'Wen ', 'Ji ', 'Dan ', 'Xing ', 'Hua ', 'Wan ', 'Jue ', 'Li ', 'Yue ', 'Lie ', 'Liu ', 'Ze ', 'Gang ', 'Chuang ', 'Fu ', 'Chu ', 'Qu ', 'Ju ', 'Shan ', 'Min ', 'Ling ', 'Zhong ', 'Pan ', 'Bie ', 'Jie ', 'Jie ', 'Bao ', 'Li ', 'Shan ', 'Bie ', 'Chan ', 'Jing ', 'Gua ', 'Gen ', 'Dao ', 'Chuang ', 'Kui ', 'Ku ', 'Duo ', 'Er ', 'Zhi ', 'Shua ', 'Quan ', 'Cha ', 'Ci ', 'Ke ', 'Jie ', 'Gui ', 'Ci ', 'Gui ', 'Kai ', 'Duo ', 'Ji ', 'Ti ', 'Jing ', 'Lou ', 'Gen ', 'Ze ', 'Yuan ', 'Cuo ', 'Xue ', 'Ke ', 'La ', 'Qian ', 'Cha ', 'Chuang ', 'Gua ', 'Jian ', 'Cuo ', 'Li ', 'Ti ', 'Fei ', 'Pou ', 'Chan ', 'Qi ', 'Chuang ', 'Zi ', 'Gang ', 'Wan ', 'Bo ', 'Ji ', 'Duo ', 'Qing ', 'Yan ', 'Zhuo ', 'Jian ', 'Ji ', 'Bo ', 'Yan ', 'Ju ', 'Huo ', 'Sheng ', 'Jian ', 'Duo ', 'Duan ', 'Wu ', 'Gua ', 'Fu ', 'Sheng ', 'Jian ', 'Ge ', 'Zha ', 'Kai ', 'Chuang ', 'Juan ', 'Chan ', 'Tuan ', 'Lu ', 'Li ', 'Fou ', 'Shan ', 'Piao ', 'Kou ', 'Jiao ', 'Gua ', 'Qiao ', 'Jue ', 'Hua ', 'Zha ', 'Zhuo ', 'Lian ', 'Ju ', 'Pi ', 'Liu ', 'Gui ', 'Jiao ', 'Gui ', 'Jian ', 'Jian ', 'Tang ', 'Huo ', 'Ji ', 'Jian ', 'Yi ', 'Jian ', 'Zhi ', 'Chan ', 'Cuan ', 'Mo ', 'Li ', 'Zhu ', 'Li ', 'Ya ', 'Quan ', 'Ban ', 'Gong ', 'Jia ', 'Wu ', 'Mai ', 'Lie ', 'Jin ', 'Keng ', 'Xie ', 'Zhi ', 'Dong ', 'Zhu ', 'Nu ', 'Jie ', 'Qu ', 'Shao ', 'Yi ', 'Zhu ', 'Miao ', 'Li ', 'Jing ', 'Lao ', 'Lao ', 'Juan ', 'Kou ', 'Yang ', 'Wa ', 'Xiao ', 'Mou ', 'Kuang ', 'Jie ', 'Lie ', 'He ', 'Shi ', 'Ke ', 'Jing ', 'Hao ', 'Bo ', 'Min ', 'Chi ', 'Lang ', 'Yong ', 'Yong ', 'Mian ', 'Ke ', 'Xun ', 'Juan ', 'Qing ', 'Lu ', 'Pou ', 'Meng ', 'Lai ', 'Le ', 'Kai ', 'Mian ', 'Dong ', 'Xu ', 'Xu ', 'Kan ', 'Wu ', 'Yi ', 'Xun ', 'Weng ', 'Sheng ', 'Lao ', 'Mu ', 'Lu ', 'Piao ', 'Shi ', 'Ji ', 'Qin ', 'Qiang ', 'Jiao ', 'Quan ', 'Yang ', 'Yi ', 'Jue ', 'Fan ', 'Juan ', 'Tong ', 'Ju ', 'Dan ', 'Xie ', 'Mai ', 'Xun ', 'Xun ', 'Lu ', 'Li ', 'Che ', 'Rang ', 'Quan ', 'Bao ', 'Shao ', 'Yun ', 'Jiu ', 'Bao ', 'Gou ', 'Wu '];
<?php return ['Yun ', 'Mwun ', 'Nay ', 'Gai ', 'Gai ', 'Bao ', 'Cong ', '[?] ', 'Xiong ', 'Peng ', 'Ju ', 'Tao ', 'Ge ', 'Pu ', 'An ', 'Pao ', 'Fu ', 'Gong ', 'Da ', 'Jiu ', 'Qiong ', 'Bi ', 'Hua ', 'Bei ', 'Nao ', 'Chi ', 'Fang ', 'Jiu ', 'Yi ', 'Za ', 'Jiang ', 'Kang ', 'Jiang ', 'Kuang ', 'Hu ', 'Xia ', 'Qu ', 'Bian ', 'Gui ', 'Qie ', 'Zang ', 'Kuang ', 'Fei ', 'Hu ', 'Tou ', 'Gui ', 'Gui ', 'Hui ', 'Dan ', 'Gui ', 'Lian ', 'Lian ', 'Suan ', 'Du ', 'Jiu ', 'Qu ', 'Xi ', 'Pi ', 'Qu ', 'Yi ', 'Qia ', 'Yan ', 'Bian ', 'Ni ', 'Qu ', 'Shi ', 'Xin ', 'Qian ', 'Nian ', 'Sa ', 'Zu ', 'Sheng ', 'Wu ', 'Hui ', 'Ban ', 'Shi ', 'Xi ', 'Wan ', 'Hua ', 'Xie ', 'Wan ', 'Bei ', 'Zu ', 'Zhuo ', 'Xie ', 'Dan ', 'Mai ', 'Nan ', 'Dan ', 'Ji ', 'Bo ', 'Shuai ', 'Bu ', 'Kuang ', 'Bian ', 'Bu ', 'Zhan ', 'Qia ', 'Lu ', 'You ', 'Lu ', 'Xi ', 'Gua ', 'Wo ', 'Xie ', 'Jie ', 'Jie ', 'Wei ', 'Ang ', 'Qiong ', 'Zhi ', 'Mao ', 'Yin ', 'Wei ', 'Shao ', 'Ji ', 'Que ', 'Luan ', 'Shi ', 'Juan ', 'Xie ', 'Xu ', 'Jin ', 'Que ', 'Wu ', 'Ji ', 'E ', 'Qing ', 'Xi ', '[?] ', 'Han ', 'Zhan ', 'E ', 'Ting ', 'Li ', 'Zhe ', 'Han ', 'Li ', 'Ya ', 'Ya ', 'Yan ', 'She ', 'Zhi ', 'Zha ', 'Pang ', '[?] ', 'He ', 'Ya ', 'Zhi ', 'Ce ', 'Pang ', 'Ti ', 'Li ', 'She ', 'Hou ', 'Ting ', 'Zui ', 'Cuo ', 'Fei ', 'Yuan ', 'Ce ', 'Yuan ', 'Xiang ', 'Yan ', 'Li ', 'Jue ', 'Sha ', 'Dian ', 'Chu ', 'Jiu ', 'Qin ', 'Ao ', 'Gui ', 'Yan ', 'Si ', 'Li ', 'Chang ', 'Lan ', 'Li ', 'Yan ', 'Yan ', 'Yuan ', 'Si ', 'Gong ', 'Lin ', 'Qiu ', 'Qu ', 'Qu ', 'Uk ', 'Lei ', 'Du ', 'Xian ', 'Zhuan ', 'San ', 'Can ', 'Can ', 'Can ', 'Can ', 'Ai ', 'Dai ', 'You ', 'Cha ', 'Ji ', 'You ', 'Shuang ', 'Fan ', 'Shou ', 'Guai ', 'Ba ', 'Fa ', 'Ruo ', 'Shi ', 'Shu ', 'Zhuo ', 'Qu ', 'Shou ', 'Bian ', 'Xu ', 'Jia ', 'Pan ', 'Sou ', 'Gao ', 'Wei ', 'Sou ', 'Die ', 'Rui ', 'Cong ', 'Kou ', 'Gu ', 'Ju ', 'Ling ', 'Gua ', 'Tao ', 'Kou ', 'Zhi ', 'Jiao ', 'Zhao ', 'Ba ', 'Ding ', 'Ke ', 'Tai ', 'Chi ', 'Shi ', 'You ', 'Qiu ', 'Po ', 'Xie ', 'Hao ', 'Si ', 'Tan ', 'Chi ', 'Le ', 'Diao ', 'Ji ', '[?] ', 'Hong '];
<?php return ['Mie ', 'Xu ', 'Mang ', 'Chi ', 'Ge ', 'Xuan ', 'Yao ', 'Zi ', 'He ', 'Ji ', 'Diao ', 'Cun ', 'Tong ', 'Ming ', 'Hou ', 'Li ', 'Tu ', 'Xiang ', 'Zha ', 'Xia ', 'Ye ', 'Lu ', 'A ', 'Ma ', 'Ou ', 'Xue ', 'Yi ', 'Jun ', 'Chou ', 'Lin ', 'Tun ', 'Yin ', 'Fei ', 'Bi ', 'Qin ', 'Qin ', 'Jie ', 'Bu ', 'Fou ', 'Ba ', 'Dun ', 'Fen ', 'E ', 'Han ', 'Ting ', 'Hang ', 'Shun ', 'Qi ', 'Hong ', 'Zhi ', 'Shen ', 'Wu ', 'Wu ', 'Chao ', 'Ne ', 'Xue ', 'Xi ', 'Chui ', 'Dou ', 'Wen ', 'Hou ', 'Ou ', 'Wu ', 'Gao ', 'Ya ', 'Jun ', 'Lu ', 'E ', 'Ge ', 'Mei ', 'Ai ', 'Qi ', 'Cheng ', 'Wu ', 'Gao ', 'Fu ', 'Jiao ', 'Hong ', 'Chi ', 'Sheng ', 'Ne ', 'Tun ', 'Fu ', 'Yi ', 'Dai ', 'Ou ', 'Li ', 'Bai ', 'Yuan ', 'Kuai ', '[?] ', 'Qiang ', 'Wu ', 'E ', 'Shi ', 'Quan ', 'Pen ', 'Wen ', 'Ni ', 'M ', 'Ling ', 'Ran ', 'You ', 'Di ', 'Zhou ', 'Shi ', 'Zhou ', 'Tie ', 'Xi ', 'Yi ', 'Qi ', 'Ping ', 'Zi ', 'Gu ', 'Zi ', 'Wei ', 'Xu ', 'He ', 'Nao ', 'Xia ', 'Pei ', 'Yi ', 'Xiao ', 'Shen ', 'Hu ', 'Ming ', 'Da ', 'Qu ', 'Ju ', 'Gem ', 'Za ', 'Tuo ', 'Duo ', 'Pou ', 'Pao ', 'Bi ', 'Fu ', 'Yang ', 'He ', 'Zha ', 'He ', 'Hai ', 'Jiu ', 'Yong ', 'Fu ', 'Que ', 'Zhou ', 'Wa ', 'Ka ', 'Gu ', 'Ka ', 'Zuo ', 'Bu ', 'Long ', 'Dong ', 'Ning ', 'Tha ', 'Si ', 'Xian ', 'Huo ', 'Qi ', 'Er ', 'E ', 'Guang ', 'Zha ', 'Xi ', 'Yi ', 'Lie ', 'Zi ', 'Mie ', 'Mi ', 'Zhi ', 'Yao ', 'Ji ', 'Zhou ', 'Ge ', 'Shuai ', 'Zan ', 'Xiao ', 'Ke ', 'Hui ', 'Kua ', 'Huai ', 'Tao ', 'Xian ', 'E ', 'Xuan ', 'Xiu ', 'Wai ', 'Yan ', 'Lao ', 'Yi ', 'Ai ', 'Pin ', 'Shen ', 'Tong ', 'Hong ', 'Xiong ', 'Chi ', 'Wa ', 'Ha ', 'Zai ', 'Yu ', 'Di ', 'Pai ', 'Xiang ', 'Ai ', 'Hen ', 'Kuang ', 'Ya ', 'Da ', 'Xiao ', 'Bi ', 'Yue ', '[?] ', 'Hua ', 'Sasou ', 'Kuai ', 'Duo ', '[?] ', 'Ji ', 'Nong ', 'Mou ', 'Yo ', 'Hao ', 'Yuan ', 'Long ', 'Pou ', 'Mang ', 'Ge ', 'E ', 'Chi ', 'Shao ', 'Li ', 'Na ', 'Zu ', 'He ', 'Ku ', 'Xiao ', 'Xian ', 'Lao ', 'Bo ', 'Zhe ', 'Zha ', 'Liang ', 'Ba ', 'Mie ', 'Le ', 'Sui ', 'Fou ', 'Bu ', 'Han ', 'Heng ', 'Geng ', 'Shuo ', 'Ge '];
<?php return ['You ', 'Yan ', 'Gu ', 'Gu ', 'Bai ', 'Han ', 'Suo ', 'Chun ', 'Yi ', 'Ai ', 'Jia ', 'Tu ', 'Xian ', 'Huan ', 'Li ', 'Xi ', 'Tang ', 'Zuo ', 'Qiu ', 'Che ', 'Wu ', 'Zao ', 'Ya ', 'Dou ', 'Qi ', 'Di ', 'Qin ', 'Ma ', 'Mal ', 'Hong ', 'Dou ', 'Kes ', 'Lao ', 'Liang ', 'Suo ', 'Zao ', 'Huan ', 'Lang ', 'Sha ', 'Ji ', 'Zuo ', 'Wo ', 'Feng ', 'Yin ', 'Hu ', 'Qi ', 'Shou ', 'Wei ', 'Shua ', 'Chang ', 'Er ', 'Li ', 'Qiang ', 'An ', 'Jie ', 'Yo ', 'Nian ', 'Yu ', 'Tian ', 'Lai ', 'Sha ', 'Xi ', 'Tuo ', 'Hu ', 'Ai ', 'Zhou ', 'Nou ', 'Ken ', 'Zhuo ', 'Zhuo ', 'Shang ', 'Di ', 'Heng ', 'Lan ', 'A ', 'Xiao ', 'Xiang ', 'Tun ', 'Wu ', 'Wen ', 'Cui ', 'Sha ', 'Hu ', 'Qi ', 'Qi ', 'Tao ', 'Dan ', 'Dan ', 'Ye ', 'Zi ', 'Bi ', 'Cui ', 'Chuo ', 'He ', 'Ya ', 'Qi ', 'Zhe ', 'Pei ', 'Liang ', 'Xian ', 'Pi ', 'Sha ', 'La ', 'Ze ', 'Qing ', 'Gua ', 'Pa ', 'Zhe ', 'Se ', 'Zhuan ', 'Nie ', 'Guo ', 'Luo ', 'Yan ', 'Di ', 'Quan ', 'Tan ', 'Bo ', 'Ding ', 'Lang ', 'Xiao ', '[?] ', 'Tang ', 'Chi ', 'Ti ', 'An ', 'Jiu ', 'Dan ', 'Ke ', 'Yong ', 'Wei ', 'Nan ', 'Shan ', 'Yu ', 'Zhe ', 'La ', 'Jie ', 'Hou ', 'Han ', 'Die ', 'Zhou ', 'Chai ', 'Wai ', 'Re ', 'Yu ', 'Yin ', 'Zan ', 'Yao ', 'Wo ', 'Mian ', 'Hu ', 'Yun ', 'Chuan ', 'Hui ', 'Huan ', 'Huan ', 'Xi ', 'He ', 'Ji ', 'Kui ', 'Zhong ', 'Wei ', 'Sha ', 'Xu ', 'Huang ', 'Du ', 'Nie ', 'Xuan ', 'Liang ', 'Yu ', 'Sang ', 'Chi ', 'Qiao ', 'Yan ', 'Dan ', 'Pen ', 'Can ', 'Li ', 'Yo ', 'Zha ', 'Wei ', 'Miao ', 'Ying ', 'Pen ', 'Phos ', 'Kui ', 'Xi ', 'Yu ', 'Jie ', 'Lou ', 'Ku ', 'Sao ', 'Huo ', 'Ti ', 'Yao ', 'He ', 'A ', 'Xiu ', 'Qiang ', 'Se ', 'Yong ', 'Su ', 'Hong ', 'Xie ', 'Yi ', 'Suo ', 'Ma ', 'Cha ', 'Hai ', 'Ke ', 'Ta ', 'Sang ', 'Tian ', 'Ru ', 'Sou ', 'Wa ', 'Ji ', 'Pang ', 'Wu ', 'Xian ', 'Shi ', 'Ge ', 'Zi ', 'Jie ', 'Luo ', 'Weng ', 'Wa ', 'Si ', 'Chi ', 'Hao ', 'Suo ', 'Jia ', 'Hai ', 'Suo ', 'Qin ', 'Nie ', 'He ', 'Cis ', 'Sai ', 'Ng ', 'Ge ', 'Na ', 'Dia ', 'Ai ', '[?] ', 'Tong ', 'Bi ', 'Ao ', 'Ao ', 'Lian ', 'Cui ', 'Zhe ', 'Mo ', 'Sou ', 'Sou ', 'Tan '];
<?php return ['Di ', 'Qi ', 'Jiao ', 'Chong ', 'Jiao ', 'Kai ', 'Tan ', 'San ', 'Cao ', 'Jia ', 'Ai ', 'Xiao ', 'Piao ', 'Lou ', 'Ga ', 'Gu ', 'Xiao ', 'Hu ', 'Hui ', 'Guo ', 'Ou ', 'Xian ', 'Ze ', 'Chang ', 'Xu ', 'Po ', 'De ', 'Ma ', 'Ma ', 'Hu ', 'Lei ', 'Du ', 'Ga ', 'Tang ', 'Ye ', 'Beng ', 'Ying ', 'Saai ', 'Jiao ', 'Mi ', 'Xiao ', 'Hua ', 'Mai ', 'Ran ', 'Zuo ', 'Peng ', 'Lao ', 'Xiao ', 'Ji ', 'Zhu ', 'Chao ', 'Kui ', 'Zui ', 'Xiao ', 'Si ', 'Hao ', 'Fu ', 'Liao ', 'Qiao ', 'Xi ', 'Xiu ', 'Tan ', 'Tan ', 'Mo ', 'Xun ', 'E ', 'Zun ', 'Fan ', 'Chi ', 'Hui ', 'Zan ', 'Chuang ', 'Cu ', 'Dan ', 'Yu ', 'Tun ', 'Cheng ', 'Jiao ', 'Ye ', 'Xi ', 'Qi ', 'Hao ', 'Lian ', 'Xu ', 'Deng ', 'Hui ', 'Yin ', 'Pu ', 'Jue ', 'Qin ', 'Xun ', 'Nie ', 'Lu ', 'Si ', 'Yan ', 'Ying ', 'Da ', 'Dan ', 'Yu ', 'Zhou ', 'Jin ', 'Nong ', 'Yue ', 'Hui ', 'Qi ', 'E ', 'Zao ', 'Yi ', 'Shi ', 'Jiao ', 'Yuan ', 'Ai ', 'Yong ', 'Jue ', 'Kuai ', 'Yu ', 'Pen ', 'Dao ', 'Ge ', 'Xin ', 'Dun ', 'Dang ', 'Sin ', 'Sai ', 'Pi ', 'Pi ', 'Yin ', 'Zui ', 'Ning ', 'Di ', 'Lan ', 'Ta ', 'Huo ', 'Ru ', 'Hao ', 'Xia ', 'Ya ', 'Duo ', 'Xi ', 'Chou ', 'Ji ', 'Jin ', 'Hao ', 'Ti ', 'Chang ', '[?] ', '[?] ', 'Ca ', 'Ti ', 'Lu ', 'Hui ', 'Bo ', 'You ', 'Nie ', 'Yin ', 'Hu ', 'Mo ', 'Huang ', 'Zhe ', 'Li ', 'Liu ', 'Haai ', 'Nang ', 'Xiao ', 'Mo ', 'Yan ', 'Li ', 'Lu ', 'Long ', 'Fu ', 'Dan ', 'Chen ', 'Pin ', 'Pi ', 'Xiang ', 'Huo ', 'Mo ', 'Xi ', 'Duo ', 'Ku ', 'Yan ', 'Chan ', 'Ying ', 'Rang ', 'Dian ', 'La ', 'Ta ', 'Xiao ', 'Jiao ', 'Chuo ', 'Huan ', 'Huo ', 'Zhuan ', 'Nie ', 'Xiao ', 'Ca ', 'Li ', 'Chan ', 'Chai ', 'Li ', 'Yi ', 'Luo ', 'Nang ', 'Zan ', 'Su ', 'Xi ', 'So ', 'Jian ', 'Za ', 'Zhu ', 'Lan ', 'Nie ', 'Nang ', '[?] ', '[?] ', 'Wei ', 'Hui ', 'Yin ', 'Qiu ', 'Si ', 'Nin ', 'Jian ', 'Hui ', 'Xin ', 'Yin ', 'Nan ', 'Tuan ', 'Tuan ', 'Dun ', 'Kang ', 'Yuan ', 'Jiong ', 'Pian ', 'Yun ', 'Cong ', 'Hu ', 'Hui ', 'Yuan ', 'You ', 'Guo ', 'Kun ', 'Cong ', 'Wei ', 'Tu ', 'Wei ', 'Lun ', 'Guo ', 'Qun ', 'Ri ', 'Ling ', 'Gu ', 'Guo ', 'Tai ', 'Guo ', 'Tu ', 'You '];
<?php return ['Guo ', 'Yin ', 'Hun ', 'Pu ', 'Yu ', 'Han ', 'Yuan ', 'Lun ', 'Quan ', 'Yu ', 'Qing ', 'Guo ', 'Chuan ', 'Wei ', 'Yuan ', 'Quan ', 'Ku ', 'Fu ', 'Yuan ', 'Yuan ', 'E ', 'Tu ', 'Tu ', 'Tu ', 'Tuan ', 'Lue ', 'Hui ', 'Yi ', 'Yuan ', 'Luan ', 'Luan ', 'Tu ', 'Ya ', 'Tu ', 'Ting ', 'Sheng ', 'Pu ', 'Lu ', 'Iri ', 'Ya ', 'Zai ', 'Wei ', 'Ge ', 'Yu ', 'Wu ', 'Gui ', 'Pi ', 'Yi ', 'Di ', 'Qian ', 'Qian ', 'Zhen ', 'Zhuo ', 'Dang ', 'Qia ', 'Akutsu ', 'Yama ', 'Kuang ', 'Chang ', 'Qi ', 'Nie ', 'Mo ', 'Ji ', 'Jia ', 'Zhi ', 'Zhi ', 'Ban ', 'Xun ', 'Tou ', 'Qin ', 'Fen ', 'Jun ', 'Keng ', 'Tun ', 'Fang ', 'Fen ', 'Ben ', 'Tan ', 'Kan ', 'Pi ', 'Zuo ', 'Keng ', 'Bi ', 'Xing ', 'Di ', 'Jing ', 'Ji ', 'Kuai ', 'Di ', 'Jing ', 'Jian ', 'Tan ', 'Li ', 'Ba ', 'Wu ', 'Fen ', 'Zhui ', 'Po ', 'Pan ', 'Tang ', 'Kun ', 'Qu ', 'Tan ', 'Zhi ', 'Tuo ', 'Gan ', 'Ping ', 'Dian ', 'Gua ', 'Ni ', 'Tai ', 'Pi ', 'Jiong ', 'Yang ', 'Fo ', 'Ao ', 'Liu ', 'Qiu ', 'Mu ', 'Ke ', 'Gou ', 'Xue ', 'Ba ', 'Chi ', 'Che ', 'Ling ', 'Zhu ', 'Fu ', 'Hu ', 'Zhi ', 'Chui ', 'La ', 'Long ', 'Long ', 'Lu ', 'Ao ', 'Tay ', 'Pao ', '[?] ', 'Xing ', 'Dong ', 'Ji ', 'Ke ', 'Lu ', 'Ci ', 'Chi ', 'Lei ', 'Gai ', 'Yin ', 'Hou ', 'Dui ', 'Zhao ', 'Fu ', 'Guang ', 'Yao ', 'Duo ', 'Duo ', 'Gui ', 'Cha ', 'Yang ', 'Yin ', 'Fa ', 'Gou ', 'Yuan ', 'Die ', 'Xie ', 'Ken ', 'Jiong ', 'Shou ', 'E ', 'Ha ', 'Dian ', 'Hong ', 'Wu ', 'Kua ', '[?] ', 'Tao ', 'Dang ', 'Kai ', 'Gake ', 'Nao ', 'An ', 'Xing ', 'Xian ', 'Huan ', 'Bang ', 'Pei ', 'Ba ', 'Yi ', 'Yin ', 'Han ', 'Xu ', 'Chui ', 'Cen ', 'Geng ', 'Ai ', 'Peng ', 'Fang ', 'Que ', 'Yong ', 'Xun ', 'Jia ', 'Di ', 'Mai ', 'Lang ', 'Xuan ', 'Cheng ', 'Yan ', 'Jin ', 'Zhe ', 'Lei ', 'Lie ', 'Bu ', 'Cheng ', 'Gomi ', 'Bu ', 'Shi ', 'Xun ', 'Guo ', 'Jiong ', 'Ye ', 'Nian ', 'Di ', 'Yu ', 'Bu ', 'Ya ', 'Juan ', 'Sui ', 'Pi ', 'Cheng ', 'Wan ', 'Ju ', 'Lun ', 'Zheng ', 'Kong ', 'Chong ', 'Dong ', 'Dai ', 'Tan ', 'An ', 'Cai ', 'Shu ', 'Beng ', 'Kan ', 'Zhi ', 'Duo ', 'Yi ', 'Zhi ', 'Yi ', 'Pei ', 'Ji ', 'Zhun ', 'Qi ', 'Sao ', 'Ju ', 'Ni '];
<?php return ['Ku ', 'Ke ', 'Tang ', 'Kun ', 'Ni ', 'Jian ', 'Dui ', 'Jin ', 'Gang ', 'Yu ', 'E ', 'Peng ', 'Gu ', 'Tu ', 'Leng ', '[?] ', 'Ya ', 'Qian ', '[?] ', 'An ', '[?] ', 'Duo ', 'Nao ', 'Tu ', 'Cheng ', 'Yin ', 'Hun ', 'Bi ', 'Lian ', 'Guo ', 'Die ', 'Zhuan ', 'Hou ', 'Bao ', 'Bao ', 'Yu ', 'Di ', 'Mao ', 'Jie ', 'Ruan ', 'E ', 'Geng ', 'Kan ', 'Zong ', 'Yu ', 'Huang ', 'E ', 'Yao ', 'Yan ', 'Bao ', 'Ji ', 'Mei ', 'Chang ', 'Du ', 'Tuo ', 'Yin ', 'Feng ', 'Zhong ', 'Jie ', 'Zhen ', 'Feng ', 'Gang ', 'Chuan ', 'Jian ', 'Pyeng ', 'Toride ', 'Xiang ', 'Huang ', 'Leng ', 'Duan ', '[?] ', 'Xuan ', 'Ji ', 'Ji ', 'Kuai ', 'Ying ', 'Ta ', 'Cheng ', 'Yong ', 'Kai ', 'Su ', 'Su ', 'Shi ', 'Mi ', 'Ta ', 'Weng ', 'Cheng ', 'Tu ', 'Tang ', 'Que ', 'Zhong ', 'Li ', 'Peng ', 'Bang ', 'Sai ', 'Zang ', 'Dui ', 'Tian ', 'Wu ', 'Cheng ', 'Xun ', 'Ge ', 'Zhen ', 'Ai ', 'Gong ', 'Yan ', 'Kan ', 'Tian ', 'Yuan ', 'Wen ', 'Xie ', 'Liu ', 'Ama ', 'Lang ', 'Chang ', 'Peng ', 'Beng ', 'Chen ', 'Cu ', 'Lu ', 'Ou ', 'Qian ', 'Mei ', 'Mo ', 'Zhuan ', 'Shuang ', 'Shu ', 'Lou ', 'Chi ', 'Man ', 'Biao ', 'Jing ', 'Qi ', 'Shu ', 'Di ', 'Zhang ', 'Kan ', 'Yong ', 'Dian ', 'Chen ', 'Zhi ', 'Xi ', 'Guo ', 'Qiang ', 'Jin ', 'Di ', 'Shang ', 'Mu ', 'Cui ', 'Yan ', 'Ta ', 'Zeng ', 'Qi ', 'Qiang ', 'Liang ', '[?] ', 'Zhui ', 'Qiao ', 'Zeng ', 'Xu ', 'Shan ', 'Shan ', 'Ba ', 'Pu ', 'Kuai ', 'Dong ', 'Fan ', 'Que ', 'Mo ', 'Dun ', 'Dun ', 'Dun ', 'Di ', 'Sheng ', 'Duo ', 'Duo ', 'Tan ', 'Deng ', 'Wu ', 'Fen ', 'Huang ', 'Tan ', 'Da ', 'Ye ', 'Sho ', 'Mama ', 'Yu ', 'Qiang ', 'Ji ', 'Qiao ', 'Ken ', 'Yi ', 'Pi ', 'Bi ', 'Dian ', 'Jiang ', 'Ye ', 'Yong ', 'Bo ', 'Tan ', 'Lan ', 'Ju ', 'Huai ', 'Dang ', 'Rang ', 'Qian ', 'Xun ', 'Lan ', 'Xi ', 'He ', 'Ai ', 'Ya ', 'Dao ', 'Hao ', 'Ruan ', 'Mama ', 'Lei ', 'Kuang ', 'Lu ', 'Yan ', 'Tan ', 'Wei ', 'Huai ', 'Long ', 'Long ', 'Rui ', 'Li ', 'Lin ', 'Rang ', 'Ten ', 'Xun ', 'Yan ', 'Lei ', 'Ba ', '[?] ', 'Shi ', 'Ren ', '[?] ', 'Zhuang ', 'Zhuang ', 'Sheng ', 'Yi ', 'Mai ', 'Ke ', 'Zhu ', 'Zhuang ', 'Hu ', 'Hu ', 'Kun ', 'Yi ', 'Hu ', 'Xu ', 'Kun ', 'Shou ', 'Mang ', 'Zun '];
<?php return ['Shou ', 'Yi ', 'Zhi ', 'Gu ', 'Chu ', 'Jiang ', 'Feng ', 'Bei ', 'Cay ', 'Bian ', 'Sui ', 'Qun ', 'Ling ', 'Fu ', 'Zuo ', 'Xia ', 'Xiong ', '[?] ', 'Nao ', 'Xia ', 'Kui ', 'Xi ', 'Wai ', 'Yuan ', 'Mao ', 'Su ', 'Duo ', 'Duo ', 'Ye ', 'Qing ', 'Uys ', 'Gou ', 'Gou ', 'Qi ', 'Meng ', 'Meng ', 'Yin ', 'Huo ', 'Chen ', 'Da ', 'Ze ', 'Tian ', 'Tai ', 'Fu ', 'Guai ', 'Yao ', 'Yang ', 'Hang ', 'Gao ', 'Shi ', 'Ben ', 'Tai ', 'Tou ', 'Yan ', 'Bi ', 'Yi ', 'Kua ', 'Jia ', 'Duo ', 'Kwu ', 'Kuang ', 'Yun ', 'Jia ', 'Pa ', 'En ', 'Lian ', 'Huan ', 'Di ', 'Yan ', 'Pao ', 'Quan ', 'Qi ', 'Nai ', 'Feng ', 'Xie ', 'Fen ', 'Dian ', '[?] ', 'Kui ', 'Zou ', 'Huan ', 'Qi ', 'Kai ', 'Zha ', 'Ben ', 'Yi ', 'Jiang ', 'Tao ', 'Zang ', 'Ben ', 'Xi ', 'Xiang ', 'Fei ', 'Diao ', 'Xun ', 'Keng ', 'Dian ', 'Ao ', 'She ', 'Weng ', 'Pan ', 'Ao ', 'Wu ', 'Ao ', 'Jiang ', 'Lian ', 'Duo ', 'Yun ', 'Jiang ', 'Shi ', 'Fen ', 'Huo ', 'Bi ', 'Lian ', 'Duo ', 'Nu ', 'Nu ', 'Ding ', 'Nai ', 'Qian ', 'Jian ', 'Ta ', 'Jiu ', 'Nan ', 'Cha ', 'Hao ', 'Xian ', 'Fan ', 'Ji ', 'Shuo ', 'Ru ', 'Fei ', 'Wang ', 'Hong ', 'Zhuang ', 'Fu ', 'Ma ', 'Dan ', 'Ren ', 'Fu ', 'Jing ', 'Yan ', 'Xie ', 'Wen ', 'Zhong ', 'Pa ', 'Du ', 'Ji ', 'Keng ', 'Zhong ', 'Yao ', 'Jin ', 'Yun ', 'Miao ', 'Pei ', 'Shi ', 'Yue ', 'Zhuang ', 'Niu ', 'Yan ', 'Na ', 'Xin ', 'Fen ', 'Bi ', 'Yu ', 'Tuo ', 'Feng ', 'Yuan ', 'Fang ', 'Wu ', 'Yu ', 'Gui ', 'Du ', 'Ba ', 'Ni ', 'Zhou ', 'Zhuo ', 'Zhao ', 'Da ', 'Nai ', 'Yuan ', 'Tou ', 'Xuan ', 'Zhi ', 'E ', 'Mei ', 'Mo ', 'Qi ', 'Bi ', 'Shen ', 'Qie ', 'E ', 'He ', 'Xu ', 'Fa ', 'Zheng ', 'Min ', 'Ban ', 'Mu ', 'Fu ', 'Ling ', 'Zi ', 'Zi ', 'Shi ', 'Ran ', 'Shan ', 'Yang ', 'Man ', 'Jie ', 'Gu ', 'Si ', 'Xing ', 'Wei ', 'Zi ', 'Ju ', 'Shan ', 'Pin ', 'Ren ', 'Yao ', 'Tong ', 'Jiang ', 'Shu ', 'Ji ', 'Gai ', 'Shang ', 'Kuo ', 'Juan ', 'Jiao ', 'Gou ', 'Mu ', 'Jian ', 'Jian ', 'Yi ', 'Nian ', 'Zhi ', 'Ji ', 'Ji ', 'Xian ', 'Heng ', 'Guang ', 'Jun ', 'Kua ', 'Yan ', 'Ming ', 'Lie ', 'Pei ', 'Yan ', 'You ', 'Yan ', 'Cha ', 'Shen ', 'Yin ', 'Chi ', 'Gui ', 'Quan ', 'Zi '];
<?php return ['Song ', 'Wei ', 'Hong ', 'Wa ', 'Lou ', 'Ya ', 'Rao ', 'Jiao ', 'Luan ', 'Ping ', 'Xian ', 'Shao ', 'Li ', 'Cheng ', 'Xiao ', 'Mang ', 'Fu ', 'Suo ', 'Wu ', 'Wei ', 'Ke ', 'Lai ', 'Chuo ', 'Ding ', 'Niang ', 'Xing ', 'Nan ', 'Yu ', 'Nuo ', 'Pei ', 'Nei ', 'Juan ', 'Shen ', 'Zhi ', 'Han ', 'Di ', 'Zhuang ', 'E ', 'Pin ', 'Tui ', 'Han ', 'Mian ', 'Wu ', 'Yan ', 'Wu ', 'Xi ', 'Yan ', 'Yu ', 'Si ', 'Yu ', 'Wa ', '[?] ', 'Xian ', 'Ju ', 'Qu ', 'Shui ', 'Qi ', 'Xian ', 'Zhui ', 'Dong ', 'Chang ', 'Lu ', 'Ai ', 'E ', 'E ', 'Lou ', 'Mian ', 'Cong ', 'Pou ', 'Ju ', 'Po ', 'Cai ', 'Ding ', 'Wan ', 'Biao ', 'Xiao ', 'Shu ', 'Qi ', 'Hui ', 'Fu ', 'E ', 'Wo ', 'Tan ', 'Fei ', 'Wei ', 'Jie ', 'Tian ', 'Ni ', 'Quan ', 'Jing ', 'Hun ', 'Jing ', 'Qian ', 'Dian ', 'Xing ', 'Hu ', 'Wa ', 'Lai ', 'Bi ', 'Yin ', 'Chou ', 'Chuo ', 'Fu ', 'Jing ', 'Lun ', 'Yan ', 'Lan ', 'Kun ', 'Yin ', 'Ya ', 'Ju ', 'Li ', 'Dian ', 'Xian ', 'Hwa ', 'Hua ', 'Ying ', 'Chan ', 'Shen ', 'Ting ', 'Dang ', 'Yao ', 'Wu ', 'Nan ', 'Ruo ', 'Jia ', 'Tou ', 'Xu ', 'Yu ', 'Wei ', 'Ti ', 'Rou ', 'Mei ', 'Dan ', 'Ruan ', 'Qin ', 'Hui ', 'Wu ', 'Qian ', 'Chun ', 'Mao ', 'Fu ', 'Jie ', 'Duan ', 'Xi ', 'Zhong ', 'Mei ', 'Huang ', 'Mian ', 'An ', 'Ying ', 'Xuan ', 'Jie ', 'Wei ', 'Mei ', 'Yuan ', 'Zhen ', 'Qiu ', 'Ti ', 'Xie ', 'Tuo ', 'Lian ', 'Mao ', 'Ran ', 'Si ', 'Pian ', 'Wei ', 'Wa ', 'Jiu ', 'Hu ', 'Ao ', '[?] ', 'Bou ', 'Xu ', 'Tou ', 'Gui ', 'Zou ', 'Yao ', 'Pi ', 'Xi ', 'Yuan ', 'Ying ', 'Rong ', 'Ru ', 'Chi ', 'Liu ', 'Mei ', 'Pan ', 'Ao ', 'Ma ', 'Gou ', 'Kui ', 'Qin ', 'Jia ', 'Sao ', 'Zhen ', 'Yuan ', 'Cha ', 'Yong ', 'Ming ', 'Ying ', 'Ji ', 'Su ', 'Niao ', 'Xian ', 'Tao ', 'Pang ', 'Lang ', 'Nao ', 'Bao ', 'Ai ', 'Pi ', 'Pin ', 'Yi ', 'Piao ', 'Yu ', 'Lei ', 'Xuan ', 'Man ', 'Yi ', 'Zhang ', 'Kang ', 'Yong ', 'Ni ', 'Li ', 'Di ', 'Gui ', 'Yan ', 'Jin ', 'Zhuan ', 'Chang ', 'Ce ', 'Han ', 'Nen ', 'Lao ', 'Mo ', 'Zhe ', 'Hu ', 'Hu ', 'Ao ', 'Nen ', 'Qiang ', 'Ma ', 'Pie ', 'Gu ', 'Wu ', 'Jiao ', 'Tuo ', 'Zhan ', 'Mao ', 'Xian ', 'Xian ', 'Mo ', 'Liao ', 'Lian ', 'Hua '];
<?php return ['Gui ', 'Deng ', 'Zhi ', 'Xu ', 'Yi ', 'Hua ', 'Xi ', 'Hui ', 'Rao ', 'Xi ', 'Yan ', 'Chan ', 'Jiao ', 'Mei ', 'Fan ', 'Fan ', 'Xian ', 'Yi ', 'Wei ', 'Jiao ', 'Fu ', 'Shi ', 'Bi ', 'Shan ', 'Sui ', 'Qiang ', 'Lian ', 'Huan ', 'Xin ', 'Niao ', 'Dong ', 'Yi ', 'Can ', 'Ai ', 'Niang ', 'Neng ', 'Ma ', 'Tiao ', 'Chou ', 'Jin ', 'Ci ', 'Yu ', 'Pin ', 'Yong ', 'Xu ', 'Nai ', 'Yan ', 'Tai ', 'Ying ', 'Can ', 'Niao ', 'Wo ', 'Ying ', 'Mian ', 'Kaka ', 'Ma ', 'Shen ', 'Xing ', 'Ni ', 'Du ', 'Liu ', 'Yuan ', 'Lan ', 'Yan ', 'Shuang ', 'Ling ', 'Jiao ', 'Niang ', 'Lan ', 'Xian ', 'Ying ', 'Shuang ', 'Shuai ', 'Quan ', 'Mi ', 'Li ', 'Luan ', 'Yan ', 'Zhu ', 'Lan ', 'Zi ', 'Jie ', 'Jue ', 'Jue ', 'Kong ', 'Yun ', 'Zi ', 'Zi ', 'Cun ', 'Sun ', 'Fu ', 'Bei ', 'Zi ', 'Xiao ', 'Xin ', 'Meng ', 'Si ', 'Tai ', 'Bao ', 'Ji ', 'Gu ', 'Nu ', 'Xue ', '[?] ', 'Zhuan ', 'Hai ', 'Luan ', 'Sun ', 'Huai ', 'Mie ', 'Cong ', 'Qian ', 'Shu ', 'Chan ', 'Ya ', 'Zi ', 'Ni ', 'Fu ', 'Zi ', 'Li ', 'Xue ', 'Bo ', 'Ru ', 'Lai ', 'Nie ', 'Nie ', 'Ying ', 'Luan ', 'Mian ', 'Zhu ', 'Rong ', 'Ta ', 'Gui ', 'Zhai ', 'Qiong ', 'Yu ', 'Shou ', 'An ', 'Tu ', 'Song ', 'Wan ', 'Rou ', 'Yao ', 'Hong ', 'Yi ', 'Jing ', 'Zhun ', 'Mi ', 'Zhu ', 'Dang ', 'Hong ', 'Zong ', 'Guan ', 'Zhou ', 'Ding ', 'Wan ', 'Yi ', 'Bao ', 'Shi ', 'Shi ', 'Chong ', 'Shen ', 'Ke ', 'Xuan ', 'Shi ', 'You ', 'Huan ', 'Yi ', 'Tiao ', 'Shi ', 'Xian ', 'Gong ', 'Cheng ', 'Qun ', 'Gong ', 'Xiao ', 'Zai ', 'Zha ', 'Bao ', 'Hai ', 'Yan ', 'Xiao ', 'Jia ', 'Shen ', 'Chen ', 'Rong ', 'Huang ', 'Mi ', 'Kou ', 'Kuan ', 'Bin ', 'Su ', 'Cai ', 'Zan ', 'Ji ', 'Yuan ', 'Ji ', 'Yin ', 'Mi ', 'Kou ', 'Qing ', 'Que ', 'Zhen ', 'Jian ', 'Fu ', 'Ning ', 'Bing ', 'Huan ', 'Mei ', 'Qin ', 'Han ', 'Yu ', 'Shi ', 'Ning ', 'Qin ', 'Ning ', 'Zhi ', 'Yu ', 'Bao ', 'Kuan ', 'Ning ', 'Qin ', 'Mo ', 'Cha ', 'Ju ', 'Gua ', 'Qin ', 'Hu ', 'Wu ', 'Liao ', 'Shi ', 'Zhu ', 'Zhai ', 'Shen ', 'Wei ', 'Xie ', 'Kuan ', 'Hui ', 'Liao ', 'Jun ', 'Huan ', 'Yi ', 'Yi ', 'Bao ', 'Qin ', 'Chong ', 'Bao ', 'Feng ', 'Cun ', 'Dui ', 'Si ', 'Xun ', 'Dao ', 'Lu ', 'Dui ', 'Shou '];
<?php return ['Po ', 'Feng ', 'Zhuan ', 'Fu ', 'She ', 'Ke ', 'Jiang ', 'Jiang ', 'Zhuan ', 'Wei ', 'Zun ', 'Xun ', 'Shu ', 'Dui ', 'Dao ', 'Xiao ', 'Ji ', 'Shao ', 'Er ', 'Er ', 'Er ', 'Ga ', 'Jian ', 'Shu ', 'Chen ', 'Shang ', 'Shang ', 'Mo ', 'Ga ', 'Chang ', 'Liao ', 'Xian ', 'Xian ', '[?] ', 'Wang ', 'Wang ', 'You ', 'Liao ', 'Liao ', 'Yao ', 'Mang ', 'Wang ', 'Wang ', 'Wang ', 'Ga ', 'Yao ', 'Duo ', 'Kui ', 'Zhong ', 'Jiu ', 'Gan ', 'Gu ', 'Gan ', 'Tui ', 'Gan ', 'Gan ', 'Shi ', 'Yin ', 'Chi ', 'Kao ', 'Ni ', 'Jin ', 'Wei ', 'Niao ', 'Ju ', 'Pi ', 'Ceng ', 'Xi ', 'Bi ', 'Ju ', 'Jie ', 'Tian ', 'Qu ', 'Ti ', 'Jie ', 'Wu ', 'Diao ', 'Shi ', 'Shi ', 'Ping ', 'Ji ', 'Xie ', 'Chen ', 'Xi ', 'Ni ', 'Zhan ', 'Xi ', '[?] ', 'Man ', 'E ', 'Lou ', 'Ping ', 'Ti ', 'Fei ', 'Shu ', 'Xie ', 'Tu ', 'Lu ', 'Lu ', 'Xi ', 'Ceng ', 'Lu ', 'Ju ', 'Xie ', 'Ju ', 'Jue ', 'Liao ', 'Jue ', 'Shu ', 'Xi ', 'Che ', 'Tun ', 'Ni ', 'Shan ', '[?] ', 'Xian ', 'Li ', 'Xue ', 'Nata ', '[?] ', 'Long ', 'Yi ', 'Qi ', 'Ren ', 'Wu ', 'Han ', 'Shen ', 'Yu ', 'Chu ', 'Sui ', 'Qi ', '[?] ', 'Yue ', 'Ban ', 'Yao ', 'Ang ', 'Ya ', 'Wu ', 'Jie ', 'E ', 'Ji ', 'Qian ', 'Fen ', 'Yuan ', 'Qi ', 'Cen ', 'Qian ', 'Qi ', 'Cha ', 'Jie ', 'Qu ', 'Gang ', 'Xian ', 'Ao ', 'Lan ', 'Dao ', 'Ba ', 'Zuo ', 'Zuo ', 'Yang ', 'Ju ', 'Gang ', 'Ke ', 'Gou ', 'Xue ', 'Bei ', 'Li ', 'Tiao ', 'Ju ', 'Yan ', 'Fu ', 'Xiu ', 'Jia ', 'Ling ', 'Tuo ', 'Pei ', 'You ', 'Dai ', 'Kuang ', 'Yue ', 'Qu ', 'Hu ', 'Po ', 'Min ', 'An ', 'Tiao ', 'Ling ', 'Chi ', 'Yuri ', 'Dong ', 'Cem ', 'Kui ', 'Xiu ', 'Mao ', 'Tong ', 'Xue ', 'Yi ', 'Kura ', 'He ', 'Ke ', 'Luo ', 'E ', 'Fu ', 'Xun ', 'Die ', 'Lu ', 'An ', 'Er ', 'Gai ', 'Quan ', 'Tong ', 'Yi ', 'Mu ', 'Shi ', 'An ', 'Wei ', 'Hu ', 'Zhi ', 'Mi ', 'Li ', 'Ji ', 'Tong ', 'Wei ', 'You ', 'Sang ', 'Xia ', 'Li ', 'Yao ', 'Jiao ', 'Zheng ', 'Luan ', 'Jiao ', 'E ', 'E ', 'Yu ', 'Ye ', 'Bu ', 'Qiao ', 'Qun ', 'Feng ', 'Feng ', 'Nao ', 'Li ', 'You ', 'Xian ', 'Hong ', 'Dao ', 'Shen ', 'Cheng ', 'Tu ', 'Geng ', 'Jun ', 'Hao ', 'Xia ', 'Yin ', 'Yu '];
<?php return ['Lang ', 'Kan ', 'Lao ', 'Lai ', 'Xian ', 'Que ', 'Kong ', 'Chong ', 'Chong ', 'Ta ', 'Lin ', 'Hua ', 'Ju ', 'Lai ', 'Qi ', 'Min ', 'Kun ', 'Kun ', 'Zu ', 'Gu ', 'Cui ', 'Ya ', 'Ya ', 'Gang ', 'Lun ', 'Lun ', 'Leng ', 'Jue ', 'Duo ', 'Zheng ', 'Guo ', 'Yin ', 'Dong ', 'Han ', 'Zheng ', 'Wei ', 'Yao ', 'Pi ', 'Yan ', 'Song ', 'Jie ', 'Beng ', 'Zu ', 'Jue ', 'Dong ', 'Zhan ', 'Gu ', 'Yin ', '[?] ', 'Ze ', 'Huang ', 'Yu ', 'Wei ', 'Yang ', 'Feng ', 'Qiu ', 'Dun ', 'Ti ', 'Yi ', 'Zhi ', 'Shi ', 'Zai ', 'Yao ', 'E ', 'Zhu ', 'Kan ', 'Lu ', 'Yan ', 'Mei ', 'Gan ', 'Ji ', 'Ji ', 'Huan ', 'Ting ', 'Sheng ', 'Mei ', 'Qian ', 'Wu ', 'Yu ', 'Zong ', 'Lan ', 'Jue ', 'Yan ', 'Yan ', 'Wei ', 'Zong ', 'Cha ', 'Sui ', 'Rong ', 'Yamashina ', 'Qin ', 'Yu ', 'Kewashii ', 'Lou ', 'Tu ', 'Dui ', 'Xi ', 'Weng ', 'Cang ', 'Dang ', 'Hong ', 'Jie ', 'Ai ', 'Liu ', 'Wu ', 'Song ', 'Qiao ', 'Zi ', 'Wei ', 'Beng ', 'Dian ', 'Cuo ', 'Qian ', 'Yong ', 'Nie ', 'Cuo ', 'Ji ', '[?] ', 'Tao ', 'Song ', 'Zong ', 'Jiang ', 'Liao ', 'Kang ', 'Chan ', 'Die ', 'Cen ', 'Ding ', 'Tu ', 'Lou ', 'Zhang ', 'Zhan ', 'Zhan ', 'Ao ', 'Cao ', 'Qu ', 'Qiang ', 'Zui ', 'Zui ', 'Dao ', 'Dao ', 'Xi ', 'Yu ', 'Bo ', 'Long ', 'Xiang ', 'Ceng ', 'Bo ', 'Qin ', 'Jiao ', 'Yan ', 'Lao ', 'Zhan ', 'Lin ', 'Liao ', 'Liao ', 'Jin ', 'Deng ', 'Duo ', 'Zun ', 'Jiao ', 'Gui ', 'Yao ', 'Qiao ', 'Yao ', 'Jue ', 'Zhan ', 'Yi ', 'Xue ', 'Nao ', 'Ye ', 'Ye ', 'Yi ', 'E ', 'Xian ', 'Ji ', 'Xie ', 'Ke ', 'Xi ', 'Di ', 'Ao ', 'Zui ', '[?] ', 'Ni ', 'Rong ', 'Dao ', 'Ling ', 'Za ', 'Yu ', 'Yue ', 'Yin ', '[?] ', 'Jie ', 'Li ', 'Sui ', 'Long ', 'Long ', 'Dian ', 'Ying ', 'Xi ', 'Ju ', 'Chan ', 'Ying ', 'Kui ', 'Yan ', 'Wei ', 'Nao ', 'Quan ', 'Chao ', 'Cuan ', 'Luan ', 'Dian ', 'Dian ', '[?] ', 'Yan ', 'Yan ', 'Yan ', 'Nao ', 'Yan ', 'Chuan ', 'Gui ', 'Chuan ', 'Zhou ', 'Huang ', 'Jing ', 'Xun ', 'Chao ', 'Chao ', 'Lie ', 'Gong ', 'Zuo ', 'Qiao ', 'Ju ', 'Gong ', 'Kek ', 'Wu ', 'Pwu ', 'Pwu ', 'Chai ', 'Qiu ', 'Qiu ', 'Ji ', 'Yi ', 'Si ', 'Ba ', 'Zhi ', 'Zhao ', 'Xiang ', 'Yi ', 'Jin ', 'Xun ', 'Juan ', 'Phas ', 'Xun ', 'Jin ', 'Fu '];
<?php return ['Za ', 'Bi ', 'Shi ', 'Bu ', 'Ding ', 'Shuai ', 'Fan ', 'Nie ', 'Shi ', 'Fen ', 'Pa ', 'Zhi ', 'Xi ', 'Hu ', 'Dan ', 'Wei ', 'Zhang ', 'Tang ', 'Dai ', 'Ma ', 'Pei ', 'Pa ', 'Tie ', 'Fu ', 'Lian ', 'Zhi ', 'Zhou ', 'Bo ', 'Zhi ', 'Di ', 'Mo ', 'Yi ', 'Yi ', 'Ping ', 'Qia ', 'Juan ', 'Ru ', 'Shuai ', 'Dai ', 'Zheng ', 'Shui ', 'Qiao ', 'Zhen ', 'Shi ', 'Qun ', 'Xi ', 'Bang ', 'Dai ', 'Gui ', 'Chou ', 'Ping ', 'Zhang ', 'Sha ', 'Wan ', 'Dai ', 'Wei ', 'Chang ', 'Sha ', 'Qi ', 'Ze ', 'Guo ', 'Mao ', 'Du ', 'Hou ', 'Zheng ', 'Xu ', 'Mi ', 'Wei ', 'Wo ', 'Fu ', 'Yi ', 'Bang ', 'Ping ', 'Tazuna ', 'Gong ', 'Pan ', 'Huang ', 'Dao ', 'Mi ', 'Jia ', 'Teng ', 'Hui ', 'Zhong ', 'Shan ', 'Man ', 'Mu ', 'Biao ', 'Guo ', 'Ze ', 'Mu ', 'Bang ', 'Zhang ', 'Jiong ', 'Chan ', 'Fu ', 'Zhi ', 'Hu ', 'Fan ', 'Chuang ', 'Bi ', 'Hei ', '[?] ', 'Mi ', 'Qiao ', 'Chan ', 'Fen ', 'Meng ', 'Bang ', 'Chou ', 'Mie ', 'Chu ', 'Jie ', 'Xian ', 'Lan ', 'Gan ', 'Ping ', 'Nian ', 'Qian ', 'Bing ', 'Bing ', 'Xing ', 'Gan ', 'Yao ', 'Huan ', 'You ', 'You ', 'Ji ', 'Yan ', 'Pi ', 'Ting ', 'Ze ', 'Guang ', 'Zhuang ', 'Mo ', 'Qing ', 'Bi ', 'Qin ', 'Dun ', 'Chuang ', 'Gui ', 'Ya ', 'Bai ', 'Jie ', 'Xu ', 'Lu ', 'Wu ', '[?] ', 'Ku ', 'Ying ', 'Di ', 'Pao ', 'Dian ', 'Ya ', 'Miao ', 'Geng ', 'Ci ', 'Fu ', 'Tong ', 'Pang ', 'Fei ', 'Xiang ', 'Yi ', 'Zhi ', 'Tiao ', 'Zhi ', 'Xiu ', 'Du ', 'Zuo ', 'Xiao ', 'Tu ', 'Gui ', 'Ku ', 'Pang ', 'Ting ', 'You ', 'Bu ', 'Ding ', 'Cheng ', 'Lai ', 'Bei ', 'Ji ', 'An ', 'Shu ', 'Kang ', 'Yong ', 'Tuo ', 'Song ', 'Shu ', 'Qing ', 'Yu ', 'Yu ', 'Miao ', 'Sou ', 'Ce ', 'Xiang ', 'Fei ', 'Jiu ', 'He ', 'Hui ', 'Liu ', 'Sha ', 'Lian ', 'Lang ', 'Sou ', 'Jian ', 'Pou ', 'Qing ', 'Jiu ', 'Jiu ', 'Qin ', 'Ao ', 'Kuo ', 'Lou ', 'Yin ', 'Liao ', 'Dai ', 'Lu ', 'Yi ', 'Chu ', 'Chan ', 'Tu ', 'Si ', 'Xin ', 'Miao ', 'Chang ', 'Wu ', 'Fei ', 'Guang ', 'Koc ', 'Kuai ', 'Bi ', 'Qiang ', 'Xie ', 'Lin ', 'Lin ', 'Liao ', 'Lu ', '[?] ', 'Ying ', 'Xian ', 'Ting ', 'Yong ', 'Li ', 'Ting ', 'Yin ', 'Xun ', 'Yan ', 'Ting ', 'Di ', 'Po ', 'Jian ', 'Hui ', 'Nai ', 'Hui ', 'Gong ', 'Nian '];
<?php return ['Kai ', 'Bian ', 'Yi ', 'Qi ', 'Nong ', 'Fen ', 'Ju ', 'Yan ', 'Yi ', 'Zang ', 'Bi ', 'Yi ', 'Yi ', 'Er ', 'San ', 'Shi ', 'Er ', 'Shi ', 'Shi ', 'Gong ', 'Diao ', 'Yin ', 'Hu ', 'Fu ', 'Hong ', 'Wu ', 'Tui ', 'Chi ', 'Jiang ', 'Ba ', 'Shen ', 'Di ', 'Zhang ', 'Jue ', 'Tao ', 'Fu ', 'Di ', 'Mi ', 'Xian ', 'Hu ', 'Chao ', 'Nu ', 'Jing ', 'Zhen ', 'Yi ', 'Mi ', 'Quan ', 'Wan ', 'Shao ', 'Ruo ', 'Xuan ', 'Jing ', 'Dun ', 'Zhang ', 'Jiang ', 'Qiang ', 'Peng ', 'Dan ', 'Qiang ', 'Bi ', 'Bi ', 'She ', 'Dan ', 'Jian ', 'Gou ', 'Sei ', 'Fa ', 'Bi ', 'Kou ', 'Nagi ', 'Bie ', 'Xiao ', 'Dan ', 'Kuo ', 'Qiang ', 'Hong ', 'Mi ', 'Kuo ', 'Wan ', 'Jue ', 'Ji ', 'Ji ', 'Gui ', 'Dang ', 'Lu ', 'Lu ', 'Tuan ', 'Hui ', 'Zhi ', 'Hui ', 'Hui ', 'Yi ', 'Yi ', 'Yi ', 'Yi ', 'Huo ', 'Huo ', 'Shan ', 'Xing ', 'Wen ', 'Tong ', 'Yan ', 'Yan ', 'Yu ', 'Chi ', 'Cai ', 'Biao ', 'Diao ', 'Bin ', 'Peng ', 'Yong ', 'Piao ', 'Zhang ', 'Ying ', 'Chi ', 'Chi ', 'Zhuo ', 'Tuo ', 'Ji ', 'Pang ', 'Zhong ', 'Yi ', 'Wang ', 'Che ', 'Bi ', 'Chi ', 'Ling ', 'Fu ', 'Wang ', 'Zheng ', 'Cu ', 'Wang ', 'Jing ', 'Dai ', 'Xi ', 'Xun ', 'Hen ', 'Yang ', 'Huai ', 'Lu ', 'Hou ', 'Wa ', 'Cheng ', 'Zhi ', 'Xu ', 'Jing ', 'Tu ', 'Cong ', '[?] ', 'Lai ', 'Cong ', 'De ', 'Pai ', 'Xi ', '[?] ', 'Qi ', 'Chang ', 'Zhi ', 'Cong ', 'Zhou ', 'Lai ', 'Yu ', 'Xie ', 'Jie ', 'Jian ', 'Chi ', 'Jia ', 'Bian ', 'Huang ', 'Fu ', 'Xun ', 'Wei ', 'Pang ', 'Yao ', 'Wei ', 'Xi ', 'Zheng ', 'Piao ', 'Chi ', 'De ', 'Zheng ', 'Zheng ', 'Bie ', 'De ', 'Chong ', 'Che ', 'Jiao ', 'Wei ', 'Jiao ', 'Hui ', 'Mei ', 'Long ', 'Xiang ', 'Bao ', 'Qu ', 'Xin ', 'Shu ', 'Bi ', 'Yi ', 'Le ', 'Ren ', 'Dao ', 'Ding ', 'Gai ', 'Ji ', 'Ren ', 'Ren ', 'Chan ', 'Tan ', 'Te ', 'Te ', 'Gan ', 'Qi ', 'Shi ', 'Cun ', 'Zhi ', 'Wang ', 'Mang ', 'Xi ', 'Fan ', 'Ying ', 'Tian ', 'Min ', 'Min ', 'Zhong ', 'Chong ', 'Wu ', 'Ji ', 'Wu ', 'Xi ', 'Ye ', 'You ', 'Wan ', 'Cong ', 'Zhong ', 'Kuai ', 'Yu ', 'Bian ', 'Zhi ', 'Qi ', 'Cui ', 'Chen ', 'Tai ', 'Tun ', 'Qian ', 'Nian ', 'Hun ', 'Xiong ', 'Niu ', 'Wang ', 'Xian ', 'Xin ', 'Kang ', 'Hu ', 'Kai ', 'Fen '];
<?php return ['Huai ', 'Tai ', 'Song ', 'Wu ', 'Ou ', 'Chang ', 'Chuang ', 'Ju ', 'Yi ', 'Bao ', 'Chao ', 'Min ', 'Pei ', 'Zuo ', 'Zen ', 'Yang ', 'Kou ', 'Ban ', 'Nu ', 'Nao ', 'Zheng ', 'Pa ', 'Bu ', 'Tie ', 'Gu ', 'Hu ', 'Ju ', 'Da ', 'Lian ', 'Si ', 'Chou ', 'Di ', 'Dai ', 'Yi ', 'Tu ', 'You ', 'Fu ', 'Ji ', 'Peng ', 'Xing ', 'Yuan ', 'Ni ', 'Guai ', 'Fu ', 'Xi ', 'Bi ', 'You ', 'Qie ', 'Xuan ', 'Cong ', 'Bing ', 'Huang ', 'Xu ', 'Chu ', 'Pi ', 'Xi ', 'Xi ', 'Tan ', 'Koraeru ', 'Zong ', 'Dui ', '[?] ', 'Ki ', 'Yi ', 'Chi ', 'Ren ', 'Xun ', 'Shi ', 'Xi ', 'Lao ', 'Heng ', 'Kuang ', 'Mu ', 'Zhi ', 'Xie ', 'Lian ', 'Tiao ', 'Huang ', 'Die ', 'Hao ', 'Kong ', 'Gui ', 'Heng ', 'Xi ', 'Xiao ', 'Shu ', 'S ', 'Kua ', 'Qiu ', 'Yang ', 'Hui ', 'Hui ', 'Chi ', 'Jia ', 'Yi ', 'Xiong ', 'Guai ', 'Lin ', 'Hui ', 'Zi ', 'Xu ', 'Chi ', 'Xiang ', 'Nu ', 'Hen ', 'En ', 'Ke ', 'Tong ', 'Tian ', 'Gong ', 'Quan ', 'Xi ', 'Qia ', 'Yue ', 'Peng ', 'Ken ', 'De ', 'Hui ', 'E ', 'Kyuu ', 'Tong ', 'Yan ', 'Kai ', 'Ce ', 'Nao ', 'Yun ', 'Mang ', 'Yong ', 'Yong ', 'Yuan ', 'Pi ', 'Kun ', 'Qiao ', 'Yue ', 'Yu ', 'Yu ', 'Jie ', 'Xi ', 'Zhe ', 'Lin ', 'Ti ', 'Han ', 'Hao ', 'Qie ', 'Ti ', 'Bu ', 'Yi ', 'Qian ', 'Hui ', 'Xi ', 'Bei ', 'Man ', 'Yi ', 'Heng ', 'Song ', 'Quan ', 'Cheng ', 'Hui ', 'Wu ', 'Wu ', 'You ', 'Li ', 'Liang ', 'Huan ', 'Cong ', 'Yi ', 'Yue ', 'Li ', 'Nin ', 'Nao ', 'E ', 'Que ', 'Xuan ', 'Qian ', 'Wu ', 'Min ', 'Cong ', 'Fei ', 'Bei ', 'Duo ', 'Cui ', 'Chang ', 'Men ', 'Li ', 'Ji ', 'Guan ', 'Guan ', 'Xing ', 'Dao ', 'Qi ', 'Kong ', 'Tian ', 'Lun ', 'Xi ', 'Kan ', 'Kun ', 'Ni ', 'Qing ', 'Chou ', 'Dun ', 'Guo ', 'Chan ', 'Liang ', 'Wan ', 'Yuan ', 'Jin ', 'Ji ', 'Lin ', 'Yu ', 'Huo ', 'He ', 'Quan ', 'Tan ', 'Ti ', 'Ti ', 'Nie ', 'Wang ', 'Chuo ', 'Bu ', 'Hun ', 'Xi ', 'Tang ', 'Xin ', 'Wei ', 'Hui ', 'E ', 'Rui ', 'Zong ', 'Jian ', 'Yong ', 'Dian ', 'Ju ', 'Can ', 'Cheng ', 'De ', 'Bei ', 'Qie ', 'Can ', 'Dan ', 'Guan ', 'Duo ', 'Nao ', 'Yun ', 'Xiang ', 'Zhui ', 'Die ', 'Huang ', 'Chun ', 'Qiong ', 'Re ', 'Xing ', 'Ce ', 'Bian ', 'Hun ', 'Zong ', 'Ti '];
<?php return ['Qiao ', 'Chou ', 'Bei ', 'Xuan ', 'Wei ', 'Ge ', 'Qian ', 'Wei ', 'Yu ', 'Yu ', 'Bi ', 'Xuan ', 'Huan ', 'Min ', 'Bi ', 'Yi ', 'Mian ', 'Yong ', 'Kai ', 'Dang ', 'Yin ', 'E ', 'Chen ', 'Mou ', 'Ke ', 'Ke ', 'Yu ', 'Ai ', 'Qie ', 'Yan ', 'Nuo ', 'Gan ', 'Yun ', 'Zong ', 'Sai ', 'Leng ', 'Fen ', '[?] ', 'Kui ', 'Kui ', 'Que ', 'Gong ', 'Yun ', 'Su ', 'Su ', 'Qi ', 'Yao ', 'Song ', 'Huang ', 'Ji ', 'Gu ', 'Ju ', 'Chuang ', 'Ni ', 'Xie ', 'Kai ', 'Zheng ', 'Yong ', 'Cao ', 'Sun ', 'Shen ', 'Bo ', 'Kai ', 'Yuan ', 'Xie ', 'Hun ', 'Yong ', 'Yang ', 'Li ', 'Sao ', 'Tao ', 'Yin ', 'Ci ', 'Xu ', 'Qian ', 'Tai ', 'Huang ', 'Yun ', 'Shen ', 'Ming ', '[?] ', 'She ', 'Cong ', 'Piao ', 'Mo ', 'Mu ', 'Guo ', 'Chi ', 'Can ', 'Can ', 'Can ', 'Cui ', 'Min ', 'Te ', 'Zhang ', 'Tong ', 'Ao ', 'Shuang ', 'Man ', 'Guan ', 'Que ', 'Zao ', 'Jiu ', 'Hui ', 'Kai ', 'Lian ', 'Ou ', 'Song ', 'Jin ', 'Yin ', 'Lu ', 'Shang ', 'Wei ', 'Tuan ', 'Man ', 'Qian ', 'She ', 'Yong ', 'Qing ', 'Kang ', 'Di ', 'Zhi ', 'Lou ', 'Juan ', 'Qi ', 'Qi ', 'Yu ', 'Ping ', 'Liao ', 'Cong ', 'You ', 'Chong ', 'Zhi ', 'Tong ', 'Cheng ', 'Qi ', 'Qu ', 'Peng ', 'Bei ', 'Bie ', 'Chun ', 'Jiao ', 'Zeng ', 'Chi ', 'Lian ', 'Ping ', 'Kui ', 'Hui ', 'Qiao ', 'Cheng ', 'Yin ', 'Yin ', 'Xi ', 'Xi ', 'Dan ', 'Tan ', 'Duo ', 'Dui ', 'Dui ', 'Su ', 'Jue ', 'Ce ', 'Xiao ', 'Fan ', 'Fen ', 'Lao ', 'Lao ', 'Chong ', 'Han ', 'Qi ', 'Xian ', 'Min ', 'Jing ', 'Liao ', 'Wu ', 'Can ', 'Jue ', 'Cu ', 'Xian ', 'Tan ', 'Sheng ', 'Pi ', 'Yi ', 'Chu ', 'Xian ', 'Nao ', 'Dan ', 'Tan ', 'Jing ', 'Song ', 'Han ', 'Jiao ', 'Wai ', 'Huan ', 'Dong ', 'Qin ', 'Qin ', 'Qu ', 'Cao ', 'Ken ', 'Xie ', 'Ying ', 'Ao ', 'Mao ', 'Yi ', 'Lin ', 'Se ', 'Jun ', 'Huai ', 'Men ', 'Lan ', 'Ai ', 'Lin ', 'Yan ', 'Gua ', 'Xia ', 'Chi ', 'Yu ', 'Yin ', 'Dai ', 'Meng ', 'Ai ', 'Meng ', 'Dui ', 'Qi ', 'Mo ', 'Lan ', 'Men ', 'Chou ', 'Zhi ', 'Nuo ', 'Nuo ', 'Yan ', 'Yang ', 'Bo ', 'Zhi ', 'Kuang ', 'Kuang ', 'You ', 'Fu ', 'Liu ', 'Mie ', 'Cheng ', '[?] ', 'Chan ', 'Meng ', 'Lan ', 'Huai ', 'Xuan ', 'Rang ', 'Chan ', 'Ji ', 'Ju ', 'Huan ', 'She ', 'Yi '];
<?php return ['Lian ', 'Nan ', 'Mi ', 'Tang ', 'Jue ', 'Gang ', 'Gang ', 'Gang ', 'Ge ', 'Yue ', 'Wu ', 'Jian ', 'Xu ', 'Shu ', 'Rong ', 'Xi ', 'Cheng ', 'Wo ', 'Jie ', 'Ge ', 'Jian ', 'Qiang ', 'Huo ', 'Qiang ', 'Zhan ', 'Dong ', 'Qi ', 'Jia ', 'Die ', 'Zei ', 'Jia ', 'Ji ', 'Shi ', 'Kan ', 'Ji ', 'Kui ', 'Gai ', 'Deng ', 'Zhan ', 'Chuang ', 'Ge ', 'Jian ', 'Jie ', 'Yu ', 'Jian ', 'Yan ', 'Lu ', 'Xi ', 'Zhan ', 'Xi ', 'Xi ', 'Chuo ', 'Dai ', 'Qu ', 'Hu ', 'Hu ', 'Hu ', 'E ', 'Shi ', 'Li ', 'Mao ', 'Hu ', 'Li ', 'Fang ', 'Suo ', 'Bian ', 'Dian ', 'Jiong ', 'Shang ', 'Yi ', 'Yi ', 'Shan ', 'Hu ', 'Fei ', 'Yan ', 'Shou ', 'T ', 'Cai ', 'Zha ', 'Qiu ', 'Le ', 'Bu ', 'Ba ', 'Da ', 'Reng ', 'Fu ', 'Hameru ', 'Zai ', 'Tuo ', 'Zhang ', 'Diao ', 'Kang ', 'Yu ', 'Ku ', 'Han ', 'Shen ', 'Cha ', 'Yi ', 'Gu ', 'Kou ', 'Wu ', 'Tuo ', 'Qian ', 'Zhi ', 'Ren ', 'Kuo ', 'Men ', 'Sao ', 'Yang ', 'Niu ', 'Ban ', 'Che ', 'Rao ', 'Xi ', 'Qian ', 'Ban ', 'Jia ', 'Yu ', 'Fu ', 'Ao ', 'Xi ', 'Pi ', 'Zhi ', 'Zi ', 'E ', 'Dun ', 'Zhao ', 'Cheng ', 'Ji ', 'Yan ', 'Kuang ', 'Bian ', 'Chao ', 'Ju ', 'Wen ', 'Hu ', 'Yue ', 'Jue ', 'Ba ', 'Qin ', 'Zhen ', 'Zheng ', 'Yun ', 'Wan ', 'Nu ', 'Yi ', 'Shu ', 'Zhua ', 'Pou ', 'Tou ', 'Dou ', 'Kang ', 'Zhe ', 'Pou ', 'Fu ', 'Pao ', 'Ba ', 'Ao ', 'Ze ', 'Tuan ', 'Kou ', 'Lun ', 'Qiang ', '[?] ', 'Hu ', 'Bao ', 'Bing ', 'Zhi ', 'Peng ', 'Tan ', 'Pu ', 'Pi ', 'Tai ', 'Yao ', 'Zhen ', 'Zha ', 'Yang ', 'Bao ', 'He ', 'Ni ', 'Yi ', 'Di ', 'Chi ', 'Pi ', 'Za ', 'Mo ', 'Mo ', 'Shen ', 'Ya ', 'Chou ', 'Qu ', 'Min ', 'Chu ', 'Jia ', 'Fu ', 'Zhan ', 'Zhu ', 'Dan ', 'Chai ', 'Mu ', 'Nian ', 'La ', 'Fu ', 'Pao ', 'Ban ', 'Pai ', 'Ling ', 'Na ', 'Guai ', 'Qian ', 'Ju ', 'Tuo ', 'Ba ', 'Tuo ', 'Tuo ', 'Ao ', 'Ju ', 'Zhuo ', 'Pan ', 'Zhao ', 'Bai ', 'Bai ', 'Di ', 'Ni ', 'Ju ', 'Kuo ', 'Long ', 'Jian ', '[?] ', 'Yong ', 'Lan ', 'Ning ', 'Bo ', 'Ze ', 'Qian ', 'Hen ', 'Gua ', 'Shi ', 'Jie ', 'Zheng ', 'Nin ', 'Gong ', 'Gong ', 'Quan ', 'Shuan ', 'Cun ', 'Zan ', 'Kao ', 'Chi ', 'Xie ', 'Ce ', 'Hui ', 'Pin ', 'Zhuai ', 'Shi ', 'Na '];
<?php return ['Bo ', 'Chi ', 'Gua ', 'Zhi ', 'Kuo ', 'Duo ', 'Duo ', 'Zhi ', 'Qie ', 'An ', 'Nong ', 'Zhen ', 'Ge ', 'Jiao ', 'Ku ', 'Dong ', 'Ru ', 'Tiao ', 'Lie ', 'Zha ', 'Lu ', 'Die ', 'Wa ', 'Jue ', 'Mushiru ', 'Ju ', 'Zhi ', 'Luan ', 'Ya ', 'Zhua ', 'Ta ', 'Xie ', 'Nao ', 'Dang ', 'Jiao ', 'Zheng ', 'Ji ', 'Hui ', 'Xun ', 'Ku ', 'Ai ', 'Tuo ', 'Nuo ', 'Cuo ', 'Bo ', 'Geng ', 'Ti ', 'Zhen ', 'Cheng ', 'Suo ', 'Suo ', 'Keng ', 'Mei ', 'Long ', 'Ju ', 'Peng ', 'Jian ', 'Yi ', 'Ting ', 'Shan ', 'Nuo ', 'Wan ', 'Xie ', 'Cha ', 'Feng ', 'Jiao ', 'Wu ', 'Jun ', 'Jiu ', 'Tong ', 'Kun ', 'Huo ', 'Tu ', 'Zhuo ', 'Pou ', 'Le ', 'Ba ', 'Han ', 'Shao ', 'Nie ', 'Juan ', 'Ze ', 'Song ', 'Ye ', 'Jue ', 'Bu ', 'Huan ', 'Bu ', 'Zun ', 'Yi ', 'Zhai ', 'Lu ', 'Sou ', 'Tuo ', 'Lao ', 'Sun ', 'Bang ', 'Jian ', 'Huan ', 'Dao ', '[?] ', 'Wan ', 'Qin ', 'Peng ', 'She ', 'Lie ', 'Min ', 'Men ', 'Fu ', 'Bai ', 'Ju ', 'Dao ', 'Wo ', 'Ai ', 'Juan ', 'Yue ', 'Zong ', 'Chen ', 'Chui ', 'Jie ', 'Tu ', 'Ben ', 'Na ', 'Nian ', 'Nuo ', 'Zu ', 'Wo ', 'Xi ', 'Xian ', 'Cheng ', 'Dian ', 'Sao ', 'Lun ', 'Qing ', 'Gang ', 'Duo ', 'Shou ', 'Diao ', 'Pou ', 'Di ', 'Zhang ', 'Gun ', 'Ji ', 'Tao ', 'Qia ', 'Qi ', 'Pai ', 'Shu ', 'Qian ', 'Ling ', 'Yi ', 'Ya ', 'Jue ', 'Zheng ', 'Liang ', 'Gua ', 'Yi ', 'Huo ', 'Shan ', 'Zheng ', 'Lue ', 'Cai ', 'Tan ', 'Che ', 'Bing ', 'Jie ', 'Ti ', 'Kong ', 'Tui ', 'Yan ', 'Cuo ', 'Zou ', 'Ju ', 'Tian ', 'Qian ', 'Ken ', 'Bai ', 'Shou ', 'Jie ', 'Lu ', 'Guo ', 'Haba ', '[?] ', 'Zhi ', 'Dan ', 'Mang ', 'Xian ', 'Sao ', 'Guan ', 'Peng ', 'Yuan ', 'Nuo ', 'Jian ', 'Zhen ', 'Jiu ', 'Jian ', 'Yu ', 'Yan ', 'Kui ', 'Nan ', 'Hong ', 'Rou ', 'Pi ', 'Wei ', 'Sai ', 'Zou ', 'Xuan ', 'Miao ', 'Ti ', 'Nie ', 'Cha ', 'Shi ', 'Zong ', 'Zhen ', 'Yi ', 'Shun ', 'Heng ', 'Bian ', 'Yang ', 'Huan ', 'Yan ', 'Zuan ', 'An ', 'Xu ', 'Ya ', 'Wo ', 'Ke ', 'Chuai ', 'Ji ', 'Ti ', 'La ', 'La ', 'Cheng ', 'Kai ', 'Jiu ', 'Jiu ', 'Tu ', 'Jie ', 'Hui ', 'Geng ', 'Chong ', 'Shuo ', 'She ', 'Xie ', 'Yuan ', 'Qian ', 'Ye ', 'Cha ', 'Zha ', 'Bei ', 'Yao ', '[?] ', '[?] ', 'Lan ', 'Wen ', 'Qin '];
<?php return ['Chan ', 'Ge ', 'Lou ', 'Zong ', 'Geng ', 'Jiao ', 'Gou ', 'Qin ', 'Yong ', 'Que ', 'Chou ', 'Chi ', 'Zhan ', 'Sun ', 'Sun ', 'Bo ', 'Chu ', 'Rong ', 'Beng ', 'Cuo ', 'Sao ', 'Ke ', 'Yao ', 'Dao ', 'Zhi ', 'Nu ', 'Xie ', 'Jian ', 'Sou ', 'Qiu ', 'Gao ', 'Xian ', 'Shuo ', 'Sang ', 'Jin ', 'Mie ', 'E ', 'Chui ', 'Nuo ', 'Shan ', 'Ta ', 'Jie ', 'Tang ', 'Pan ', 'Ban ', 'Da ', 'Li ', 'Tao ', 'Hu ', 'Zhi ', 'Wa ', 'Xia ', 'Qian ', 'Wen ', 'Qiang ', 'Tian ', 'Zhen ', 'E ', 'Xi ', 'Nuo ', 'Quan ', 'Cha ', 'Zha ', 'Ge ', 'Wu ', 'En ', 'She ', 'Kang ', 'She ', 'Shu ', 'Bai ', 'Yao ', 'Bin ', 'Sou ', 'Tan ', 'Sa ', 'Chan ', 'Suo ', 'Liao ', 'Chong ', 'Chuang ', 'Guo ', 'Bing ', 'Feng ', 'Shuai ', 'Di ', 'Qi ', 'Sou ', 'Zhai ', 'Lian ', 'Tang ', 'Chi ', 'Guan ', 'Lu ', 'Luo ', 'Lou ', 'Zong ', 'Gai ', 'Hu ', 'Zha ', 'Chuang ', 'Tang ', 'Hua ', 'Cui ', 'Nai ', 'Mo ', 'Jiang ', 'Gui ', 'Ying ', 'Zhi ', 'Ao ', 'Zhi ', 'Nie ', 'Man ', 'Shan ', 'Kou ', 'Shu ', 'Suo ', 'Tuan ', 'Jiao ', 'Mo ', 'Mo ', 'Zhe ', 'Xian ', 'Keng ', 'Piao ', 'Jiang ', 'Yin ', 'Gou ', 'Qian ', 'Lue ', 'Ji ', 'Ying ', 'Jue ', 'Pie ', 'Pie ', 'Lao ', 'Dun ', 'Xian ', 'Ruan ', 'Kui ', 'Zan ', 'Yi ', 'Xun ', 'Cheng ', 'Cheng ', 'Sa ', 'Nao ', 'Heng ', 'Si ', 'Qian ', 'Huang ', 'Da ', 'Zun ', 'Nian ', 'Lin ', 'Zheng ', 'Hui ', 'Zhuang ', 'Jiao ', 'Ji ', 'Cao ', 'Dan ', 'Dan ', 'Che ', 'Bo ', 'Che ', 'Jue ', 'Xiao ', 'Liao ', 'Ben ', 'Fu ', 'Qiao ', 'Bo ', 'Cuo ', 'Zhuo ', 'Zhuan ', 'Tuo ', 'Pu ', 'Qin ', 'Dun ', 'Nian ', '[?] ', 'Xie ', 'Lu ', 'Jiao ', 'Cuan ', 'Ta ', 'Han ', 'Qiao ', 'Zhua ', 'Jian ', 'Gan ', 'Yong ', 'Lei ', 'Kuo ', 'Lu ', 'Shan ', 'Zhuo ', 'Ze ', 'Pu ', 'Chuo ', 'Ji ', 'Dang ', 'Suo ', 'Cao ', 'Qing ', 'Jing ', 'Huan ', 'Jie ', 'Qin ', 'Kuai ', 'Dan ', 'Xi ', 'Ge ', 'Pi ', 'Bo ', 'Ao ', 'Ju ', 'Ye ', '[?] ', 'Mang ', 'Sou ', 'Mi ', 'Ji ', 'Tai ', 'Zhuo ', 'Dao ', 'Xing ', 'Lan ', 'Ca ', 'Ju ', 'Ye ', 'Ru ', 'Ye ', 'Ye ', 'Ni ', 'Hu ', 'Ji ', 'Bin ', 'Ning ', 'Ge ', 'Zhi ', 'Jie ', 'Kuo ', 'Mo ', 'Jian ', 'Xie ', 'Lie ', 'Tan ', 'Bai ', 'Sou ', 'Lu ', 'Lue ', 'Rao ', 'Zhi '];
<?php return ['Pan ', 'Yang ', 'Lei ', 'Sa ', 'Shu ', 'Zan ', 'Nian ', 'Xian ', 'Jun ', 'Huo ', 'Li ', 'La ', 'Han ', 'Ying ', 'Lu ', 'Long ', 'Qian ', 'Qian ', 'Zan ', 'Qian ', 'Lan ', 'San ', 'Ying ', 'Mei ', 'Rang ', 'Chan ', '[?] ', 'Cuan ', 'Xi ', 'She ', 'Luo ', 'Jun ', 'Mi ', 'Li ', 'Zan ', 'Luan ', 'Tan ', 'Zuan ', 'Li ', 'Dian ', 'Wa ', 'Dang ', 'Jiao ', 'Jue ', 'Lan ', 'Li ', 'Nang ', 'Zhi ', 'Gui ', 'Gui ', 'Qi ', 'Xin ', 'Pu ', 'Sui ', 'Shou ', 'Kao ', 'You ', 'Gai ', 'Yi ', 'Gong ', 'Gan ', 'Ban ', 'Fang ', 'Zheng ', 'Bo ', 'Dian ', 'Kou ', 'Min ', 'Wu ', 'Gu ', 'He ', 'Ce ', 'Xiao ', 'Mi ', 'Chu ', 'Ge ', 'Di ', 'Xu ', 'Jiao ', 'Min ', 'Chen ', 'Jiu ', 'Zhen ', 'Duo ', 'Yu ', 'Chi ', 'Ao ', 'Bai ', 'Xu ', 'Jiao ', 'Duo ', 'Lian ', 'Nie ', 'Bi ', 'Chang ', 'Dian ', 'Duo ', 'Yi ', 'Gan ', 'San ', 'Ke ', 'Yan ', 'Dun ', 'Qi ', 'Dou ', 'Xiao ', 'Duo ', 'Jiao ', 'Jing ', 'Yang ', 'Xia ', 'Min ', 'Shu ', 'Ai ', 'Qiao ', 'Ai ', 'Zheng ', 'Di ', 'Zhen ', 'Fu ', 'Shu ', 'Liao ', 'Qu ', 'Xiong ', 'Xi ', 'Jiao ', 'Sen ', 'Jiao ', 'Zhuo ', 'Yi ', 'Lian ', 'Bi ', 'Li ', 'Xiao ', 'Xiao ', 'Wen ', 'Xue ', 'Qi ', 'Qi ', 'Zhai ', 'Bin ', 'Jue ', 'Zhai ', '[?] ', 'Fei ', 'Ban ', 'Ban ', 'Lan ', 'Yu ', 'Lan ', 'Wei ', 'Dou ', 'Sheng ', 'Liao ', 'Jia ', 'Hu ', 'Xie ', 'Jia ', 'Yu ', 'Zhen ', 'Jiao ', 'Wo ', 'Tou ', 'Chu ', 'Jin ', 'Chi ', 'Yin ', 'Fu ', 'Qiang ', 'Zhan ', 'Qu ', 'Zhuo ', 'Zhan ', 'Duan ', 'Zhuo ', 'Si ', 'Xin ', 'Zhuo ', 'Zhuo ', 'Qin ', 'Lin ', 'Zhuo ', 'Chu ', 'Duan ', 'Zhu ', 'Fang ', 'Xie ', 'Hang ', 'Yu ', 'Shi ', 'Pei ', 'You ', 'Mye ', 'Pang ', 'Qi ', 'Zhan ', 'Mao ', 'Lu ', 'Pei ', 'Pi ', 'Liu ', 'Fu ', 'Fang ', 'Xuan ', 'Jing ', 'Jing ', 'Ni ', 'Zu ', 'Zhao ', 'Yi ', 'Liu ', 'Shao ', 'Jian ', 'Es ', 'Yi ', 'Qi ', 'Zhi ', 'Fan ', 'Piao ', 'Fan ', 'Zhan ', 'Guai ', 'Sui ', 'Yu ', 'Wu ', 'Ji ', 'Ji ', 'Ji ', 'Huo ', 'Ri ', 'Dan ', 'Jiu ', 'Zhi ', 'Zao ', 'Xie ', 'Tiao ', 'Xun ', 'Xu ', 'Xu ', 'Xu ', 'Gan ', 'Han ', 'Tai ', 'Di ', 'Xu ', 'Chan ', 'Shi ', 'Kuang ', 'Yang ', 'Shi ', 'Wang ', 'Min ', 'Min ', 'Tun ', 'Chun ', 'Wu '];
<?php return ['Yun ', 'Bei ', 'Ang ', 'Ze ', 'Ban ', 'Jie ', 'Kun ', 'Sheng ', 'Hu ', 'Fang ', 'Hao ', 'Gui ', 'Chang ', 'Xuan ', 'Ming ', 'Hun ', 'Fen ', 'Qin ', 'Hu ', 'Yi ', 'Xi ', 'Xin ', 'Yan ', 'Ze ', 'Fang ', 'Tan ', 'Shen ', 'Ju ', 'Yang ', 'Zan ', 'Bing ', 'Xing ', 'Ying ', 'Xuan ', 'Pei ', 'Zhen ', 'Ling ', 'Chun ', 'Hao ', 'Mei ', 'Zuo ', 'Mo ', 'Bian ', 'Xu ', 'Hun ', 'Zhao ', 'Zong ', 'Shi ', 'Shi ', 'Yu ', 'Fei ', 'Die ', 'Mao ', 'Ni ', 'Chang ', 'Wen ', 'Dong ', 'Ai ', 'Bing ', 'Ang ', 'Zhou ', 'Long ', 'Xian ', 'Kuang ', 'Tiao ', 'Chao ', 'Shi ', 'Huang ', 'Huang ', 'Xuan ', 'Kui ', 'Xu ', 'Jiao ', 'Jin ', 'Zhi ', 'Jin ', 'Shang ', 'Tong ', 'Hong ', 'Yan ', 'Gai ', 'Xiang ', 'Shai ', 'Xiao ', 'Ye ', 'Yun ', 'Hui ', 'Han ', 'Han ', 'Jun ', 'Wan ', 'Xian ', 'Kun ', 'Zhou ', 'Xi ', 'Cheng ', 'Sheng ', 'Bu ', 'Zhe ', 'Zhe ', 'Wu ', 'Han ', 'Hui ', 'Hao ', 'Chen ', 'Wan ', 'Tian ', 'Zhuo ', 'Zui ', 'Zhou ', 'Pu ', 'Jing ', 'Xi ', 'Shan ', 'Yi ', 'Xi ', 'Qing ', 'Qi ', 'Jing ', 'Gui ', 'Zhen ', 'Yi ', 'Zhi ', 'An ', 'Wan ', 'Lin ', 'Liang ', 'Chang ', 'Wang ', 'Xiao ', 'Zan ', 'Hi ', 'Xuan ', 'Xuan ', 'Yi ', 'Xia ', 'Yun ', 'Hui ', 'Fu ', 'Min ', 'Kui ', 'He ', 'Ying ', 'Du ', 'Wei ', 'Shu ', 'Qing ', 'Mao ', 'Nan ', 'Jian ', 'Nuan ', 'An ', 'Yang ', 'Chun ', 'Yao ', 'Suo ', 'Jin ', 'Ming ', 'Jiao ', 'Kai ', 'Gao ', 'Weng ', 'Chang ', 'Qi ', 'Hao ', 'Yan ', 'Li ', 'Ai ', 'Ji ', 'Gui ', 'Men ', 'Zan ', 'Xie ', 'Hao ', 'Mu ', 'Mo ', 'Cong ', 'Ni ', 'Zhang ', 'Hui ', 'Bao ', 'Han ', 'Xuan ', 'Chuan ', 'Liao ', 'Xian ', 'Dan ', 'Jing ', 'Pie ', 'Lin ', 'Tun ', 'Xi ', 'Yi ', 'Ji ', 'Huang ', 'Tai ', 'Ye ', 'Ye ', 'Li ', 'Tan ', 'Tong ', 'Xiao ', 'Fei ', 'Qin ', 'Zhao ', 'Hao ', 'Yi ', 'Xiang ', 'Xing ', 'Sen ', 'Jiao ', 'Bao ', 'Jing ', 'Yian ', 'Ai ', 'Ye ', 'Ru ', 'Shu ', 'Meng ', 'Xun ', 'Yao ', 'Pu ', 'Li ', 'Chen ', 'Kuang ', 'Die ', '[?] ', 'Yan ', 'Huo ', 'Lu ', 'Xi ', 'Rong ', 'Long ', 'Nang ', 'Luo ', 'Luan ', 'Shai ', 'Tang ', 'Yan ', 'Chu ', 'Yue ', 'Yue ', 'Qu ', 'Yi ', 'Geng ', 'Ye ', 'Hu ', 'He ', 'Shu ', 'Cao ', 'Cao ', 'Noboru ', 'Man ', 'Ceng ', 'Ceng ', 'Ti '];
<?php return ['Zui ', 'Can ', 'Xu ', 'Hui ', 'Yin ', 'Qie ', 'Fen ', 'Pi ', 'Yue ', 'You ', 'Ruan ', 'Peng ', 'Ban ', 'Fu ', 'Ling ', 'Fei ', 'Qu ', '[?] ', 'Nu ', 'Tiao ', 'Shuo ', 'Zhen ', 'Lang ', 'Lang ', 'Juan ', 'Ming ', 'Huang ', 'Wang ', 'Tun ', 'Zhao ', 'Ji ', 'Qi ', 'Ying ', 'Zong ', 'Wang ', 'Tong ', 'Lang ', '[?] ', 'Meng ', 'Long ', 'Mu ', 'Deng ', 'Wei ', 'Mo ', 'Ben ', 'Zha ', 'Zhu ', 'Zhu ', '[?] ', 'Zhu ', 'Ren ', 'Ba ', 'Po ', 'Duo ', 'Duo ', 'Dao ', 'Li ', 'Qiu ', 'Ji ', 'Jiu ', 'Bi ', 'Xiu ', 'Ting ', 'Ci ', 'Sha ', 'Eburi ', 'Za ', 'Quan ', 'Qian ', 'Yu ', 'Gan ', 'Wu ', 'Cha ', 'Shan ', 'Xun ', 'Fan ', 'Wu ', 'Zi ', 'Li ', 'Xing ', 'Cai ', 'Cun ', 'Ren ', 'Shao ', 'Tuo ', 'Di ', 'Zhang ', 'Mang ', 'Chi ', 'Yi ', 'Gu ', 'Gong ', 'Du ', 'Yi ', 'Qi ', 'Shu ', 'Gang ', 'Tiao ', 'Moku ', 'Soma ', 'Tochi ', 'Lai ', 'Sugi ', 'Mang ', 'Yang ', 'Ma ', 'Miao ', 'Si ', 'Yuan ', 'Hang ', 'Fei ', 'Bei ', 'Jie ', 'Dong ', 'Gao ', 'Yao ', 'Xian ', 'Chu ', 'Qun ', 'Pa ', 'Shu ', 'Hua ', 'Xin ', 'Chou ', 'Zhu ', 'Chou ', 'Song ', 'Ban ', 'Song ', 'Ji ', 'Yue ', 'Jin ', 'Gou ', 'Ji ', 'Mao ', 'Pi ', 'Bi ', 'Wang ', 'Ang ', 'Fang ', 'Fen ', 'Yi ', 'Fu ', 'Nan ', 'Xi ', 'Hu ', 'Ya ', 'Dou ', 'Xun ', 'Zhen ', 'Yao ', 'Lin ', 'Rui ', 'E ', 'Mei ', 'Zhao ', 'Guo ', 'Zhi ', 'Cong ', 'Yun ', 'Waku ', 'Dou ', 'Shu ', 'Zao ', '[?] ', 'Li ', 'Haze ', 'Jian ', 'Cheng ', 'Matsu ', 'Qiang ', 'Feng ', 'Nan ', 'Xiao ', 'Xian ', 'Ku ', 'Ping ', 'Yi ', 'Xi ', 'Zhi ', 'Guai ', 'Xiao ', 'Jia ', 'Jia ', 'Gou ', 'Fu ', 'Mo ', 'Yi ', 'Ye ', 'Ye ', 'Shi ', 'Nie ', 'Bi ', 'Duo ', 'Yi ', 'Ling ', 'Bing ', 'Ni ', 'La ', 'He ', 'Pan ', 'Fan ', 'Zhong ', 'Dai ', 'Ci ', 'Yang ', 'Fu ', 'Bo ', 'Mou ', 'Gan ', 'Qi ', 'Ran ', 'Rou ', 'Mao ', 'Zhao ', 'Song ', 'Zhe ', 'Xia ', 'You ', 'Shen ', 'Ju ', 'Tuo ', 'Zuo ', 'Nan ', 'Ning ', 'Yong ', 'Di ', 'Zhi ', 'Zha ', 'Cha ', 'Dan ', 'Gu ', 'Pu ', 'Jiu ', 'Ao ', 'Fu ', 'Jian ', 'Bo ', 'Duo ', 'Ke ', 'Nai ', 'Zhu ', 'Bi ', 'Liu ', 'Chai ', 'Zha ', 'Si ', 'Zhu ', 'Pei ', 'Shi ', 'Guai ', 'Cha ', 'Yao ', 'Jue ', 'Jiu ', 'Shi '];
<?php return ['Zhi ', 'Liu ', 'Mei ', 'Hoy ', 'Rong ', 'Zha ', '[?] ', 'Biao ', 'Zhan ', 'Jie ', 'Long ', 'Dong ', 'Lu ', 'Sayng ', 'Li ', 'Lan ', 'Yong ', 'Shu ', 'Xun ', 'Shuan ', 'Qi ', 'Zhen ', 'Qi ', 'Li ', 'Yi ', 'Xiang ', 'Zhen ', 'Li ', 'Su ', 'Gua ', 'Kan ', 'Bing ', 'Ren ', 'Xiao ', 'Bo ', 'Ren ', 'Bing ', 'Zi ', 'Chou ', 'Yi ', 'Jie ', 'Xu ', 'Zhu ', 'Jian ', 'Zui ', 'Er ', 'Er ', 'You ', 'Fa ', 'Gong ', 'Kao ', 'Lao ', 'Zhan ', 'Li ', 'Yin ', 'Yang ', 'He ', 'Gen ', 'Zhi ', 'Chi ', 'Ge ', 'Zai ', 'Luan ', 'Fu ', 'Jie ', 'Hang ', 'Gui ', 'Tao ', 'Guang ', 'Wei ', 'Kuang ', 'Ru ', 'An ', 'An ', 'Juan ', 'Yi ', 'Zhuo ', 'Ku ', 'Zhi ', 'Qiong ', 'Tong ', 'Sang ', 'Sang ', 'Huan ', 'Jie ', 'Jiu ', 'Xue ', 'Duo ', 'Zhui ', 'Yu ', 'Zan ', 'Kasei ', 'Ying ', 'Masu ', '[?] ', 'Zhan ', 'Ya ', 'Nao ', 'Zhen ', 'Dang ', 'Qi ', 'Qiao ', 'Hua ', 'Kuai ', 'Jiang ', 'Zhuang ', 'Xun ', 'Suo ', 'Sha ', 'Zhen ', 'Bei ', 'Ting ', 'Gua ', 'Jing ', 'Bo ', 'Ben ', 'Fu ', 'Rui ', 'Tong ', 'Jue ', 'Xi ', 'Lang ', 'Liu ', 'Feng ', 'Qi ', 'Wen ', 'Jun ', 'Gan ', 'Cu ', 'Liang ', 'Qiu ', 'Ting ', 'You ', 'Mei ', 'Bang ', 'Long ', 'Peng ', 'Zhuang ', 'Di ', 'Xuan ', 'Tu ', 'Zao ', 'Ao ', 'Gu ', 'Bi ', 'Di ', 'Han ', 'Zi ', 'Zhi ', 'Ren ', 'Bei ', 'Geng ', 'Jian ', 'Huan ', 'Wan ', 'Nuo ', 'Jia ', 'Tiao ', 'Ji ', 'Xiao ', 'Lu ', 'Huan ', 'Shao ', 'Cen ', 'Fen ', 'Song ', 'Meng ', 'Wu ', 'Li ', 'Li ', 'Dou ', 'Cen ', 'Ying ', 'Suo ', 'Ju ', 'Ti ', 'Jie ', 'Kun ', 'Zhuo ', 'Shu ', 'Chan ', 'Fan ', 'Wei ', 'Jing ', 'Li ', 'Bing ', 'Fumoto ', 'Shikimi ', 'Tao ', 'Zhi ', 'Lai ', 'Lian ', 'Jian ', 'Zhuo ', 'Ling ', 'Li ', 'Qi ', 'Bing ', 'Zhun ', 'Cong ', 'Qian ', 'Mian ', 'Qi ', 'Qi ', 'Cai ', 'Gun ', 'Chan ', 'Te ', 'Fei ', 'Pai ', 'Bang ', 'Pou ', 'Hun ', 'Zong ', 'Cheng ', 'Zao ', 'Ji ', 'Li ', 'Peng ', 'Yu ', 'Yu ', 'Gu ', 'Hun ', 'Dong ', 'Tang ', 'Gang ', 'Wang ', 'Di ', 'Xi ', 'Fan ', 'Cheng ', 'Zhan ', 'Qi ', 'Yuan ', 'Yan ', 'Yu ', 'Quan ', 'Yi ', 'Sen ', 'Ren ', 'Chui ', 'Leng ', 'Qi ', 'Zhuo ', 'Fu ', 'Ke ', 'Lai ', 'Zou ', 'Zou ', 'Zhuo ', 'Guan ', 'Fen ', 'Fen ', 'Chen ', 'Qiong ', 'Nie '];
<?php return ['Wan ', 'Guo ', 'Lu ', 'Hao ', 'Jie ', 'Yi ', 'Chou ', 'Ju ', 'Ju ', 'Cheng ', 'Zuo ', 'Liang ', 'Qiang ', 'Zhi ', 'Zhui ', 'Ya ', 'Ju ', 'Bei ', 'Jiao ', 'Zhuo ', 'Zi ', 'Bin ', 'Peng ', 'Ding ', 'Chu ', 'Chang ', 'Kunugi ', 'Momiji ', 'Jian ', 'Gui ', 'Xi ', 'Du ', 'Qian ', 'Kunugi ', 'Soko ', 'Shide ', 'Luo ', 'Zhi ', 'Ken ', 'Myeng ', 'Tafu ', '[?] ', 'Peng ', 'Zhan ', '[?] ', 'Tuo ', 'Sen ', 'Duo ', 'Ye ', 'Fou ', 'Wei ', 'Wei ', 'Duan ', 'Jia ', 'Zong ', 'Jian ', 'Yi ', 'Shen ', 'Xi ', 'Yan ', 'Yan ', 'Chuan ', 'Zhan ', 'Chun ', 'Yu ', 'He ', 'Zha ', 'Wo ', 'Pian ', 'Bi ', 'Yao ', 'Huo ', 'Xu ', 'Ruo ', 'Yang ', 'La ', 'Yan ', 'Ben ', 'Hun ', 'Kui ', 'Jie ', 'Kui ', 'Si ', 'Feng ', 'Xie ', 'Tuo ', 'Zhi ', 'Jian ', 'Mu ', 'Mao ', 'Chu ', 'Hu ', 'Hu ', 'Lian ', 'Leng ', 'Ting ', 'Nan ', 'Yu ', 'You ', 'Mei ', 'Song ', 'Xuan ', 'Xuan ', 'Ying ', 'Zhen ', 'Pian ', 'Ye ', 'Ji ', 'Jie ', 'Ye ', 'Chu ', 'Shun ', 'Yu ', 'Cou ', 'Wei ', 'Mei ', 'Di ', 'Ji ', 'Jie ', 'Kai ', 'Qiu ', 'Ying ', 'Rou ', 'Heng ', 'Lou ', 'Le ', 'Hazou ', 'Katsura ', 'Pin ', 'Muro ', 'Gai ', 'Tan ', 'Lan ', 'Yun ', 'Yu ', 'Chen ', 'Lu ', 'Ju ', 'Sakaki ', '[?] ', 'Pi ', 'Xie ', 'Jia ', 'Yi ', 'Zhan ', 'Fu ', 'Nai ', 'Mi ', 'Lang ', 'Rong ', 'Gu ', 'Jian ', 'Ju ', 'Ta ', 'Yao ', 'Zhen ', 'Bang ', 'Sha ', 'Yuan ', 'Zi ', 'Ming ', 'Su ', 'Jia ', 'Yao ', 'Jie ', 'Huang ', 'Gan ', 'Fei ', 'Zha ', 'Qian ', 'Ma ', 'Sun ', 'Yuan ', 'Xie ', 'Rong ', 'Shi ', 'Zhi ', 'Cui ', 'Yun ', 'Ting ', 'Liu ', 'Rong ', 'Tang ', 'Que ', 'Zhai ', 'Si ', 'Sheng ', 'Ta ', 'Ke ', 'Xi ', 'Gu ', 'Qi ', 'Kao ', 'Gao ', 'Sun ', 'Pan ', 'Tao ', 'Ge ', 'Xun ', 'Dian ', 'Nou ', 'Ji ', 'Shuo ', 'Gou ', 'Chui ', 'Qiang ', 'Cha ', 'Qian ', 'Huai ', 'Mei ', 'Xu ', 'Gang ', 'Gao ', 'Zhuo ', 'Tuo ', 'Hashi ', 'Yang ', 'Dian ', 'Jia ', 'Jian ', 'Zui ', 'Kashi ', 'Ori ', 'Bin ', 'Zhu ', '[?] ', 'Xi ', 'Qi ', 'Lian ', 'Hui ', 'Yong ', 'Qian ', 'Guo ', 'Gai ', 'Gai ', 'Tuan ', 'Hua ', 'Cu ', 'Sen ', 'Cui ', 'Beng ', 'You ', 'Hu ', 'Jiang ', 'Hu ', 'Huan ', 'Kui ', 'Yi ', 'Nie ', 'Gao ', 'Kang ', 'Gui ', 'Gui ', 'Cao ', 'Man ', 'Jin '];
<?php return ['Di ', 'Zhuang ', 'Le ', 'Lang ', 'Chen ', 'Cong ', 'Li ', 'Xiu ', 'Qing ', 'Shuang ', 'Fan ', 'Tong ', 'Guan ', 'Ji ', 'Suo ', 'Lei ', 'Lu ', 'Liang ', 'Mi ', 'Lou ', 'Chao ', 'Su ', 'Ke ', 'Shu ', 'Tang ', 'Biao ', 'Lu ', 'Jiu ', 'Shu ', 'Zha ', 'Shu ', 'Zhang ', 'Men ', 'Mo ', 'Niao ', 'Yang ', 'Tiao ', 'Peng ', 'Zhu ', 'Sha ', 'Xi ', 'Quan ', 'Heng ', 'Jian ', 'Cong ', '[?] ', 'Hokuso ', 'Qiang ', 'Tara ', 'Ying ', 'Er ', 'Xin ', 'Zhi ', 'Qiao ', 'Zui ', 'Cong ', 'Pu ', 'Shu ', 'Hua ', 'Kui ', 'Zhen ', 'Zun ', 'Yue ', 'Zhan ', 'Xi ', 'Xun ', 'Dian ', 'Fa ', 'Gan ', 'Mo ', 'Wu ', 'Qiao ', 'Nao ', 'Lin ', 'Liu ', 'Qiao ', 'Xian ', 'Run ', 'Fan ', 'Zhan ', 'Tuo ', 'Lao ', 'Yun ', 'Shun ', 'Tui ', 'Cheng ', 'Tang ', 'Meng ', 'Ju ', 'Cheng ', 'Su ', 'Jue ', 'Jue ', 'Tan ', 'Hui ', 'Ji ', 'Nuo ', 'Xiang ', 'Tuo ', 'Ning ', 'Rui ', 'Zhu ', 'Chuang ', 'Zeng ', 'Fen ', 'Qiong ', 'Ran ', 'Heng ', 'Cen ', 'Gu ', 'Liu ', 'Lao ', 'Gao ', 'Chu ', 'Zusa ', 'Nude ', 'Ca ', 'San ', 'Ji ', 'Dou ', 'Shou ', 'Lu ', '[?] ', '[?] ', 'Yuan ', 'Ta ', 'Shu ', 'Jiang ', 'Tan ', 'Lin ', 'Nong ', 'Yin ', 'Xi ', 'Sui ', 'Shan ', 'Zui ', 'Xuan ', 'Cheng ', 'Gan ', 'Ju ', 'Zui ', 'Yi ', 'Qin ', 'Pu ', 'Yan ', 'Lei ', 'Feng ', 'Hui ', 'Dang ', 'Ji ', 'Sui ', 'Bo ', 'Bi ', 'Ding ', 'Chu ', 'Zhua ', 'Kuai ', 'Ji ', 'Jie ', 'Jia ', 'Qing ', 'Zhe ', 'Jian ', 'Qiang ', 'Dao ', 'Yi ', 'Biao ', 'Song ', 'She ', 'Lin ', 'Kunugi ', 'Cha ', 'Meng ', 'Yin ', 'Tao ', 'Tai ', 'Mian ', 'Qi ', 'Toan ', 'Bin ', 'Huo ', 'Ji ', 'Qian ', 'Mi ', 'Ning ', 'Yi ', 'Gao ', 'Jian ', 'Yin ', 'Er ', 'Qing ', 'Yan ', 'Qi ', 'Mi ', 'Zhao ', 'Gui ', 'Chun ', 'Ji ', 'Kui ', 'Po ', 'Deng ', 'Chu ', '[?] ', 'Mian ', 'You ', 'Zhi ', 'Guang ', 'Qian ', 'Lei ', 'Lei ', 'Sa ', 'Lu ', 'Li ', 'Cuan ', 'Lu ', 'Mie ', 'Hui ', 'Ou ', 'Lu ', 'Jie ', 'Gao ', 'Du ', 'Yuan ', 'Li ', 'Fei ', 'Zhuo ', 'Sou ', 'Lian ', 'Tamo ', 'Chu ', '[?] ', 'Zhu ', 'Lu ', 'Yan ', 'Li ', 'Zhu ', 'Chen ', 'Jie ', 'E ', 'Su ', 'Huai ', 'Nie ', 'Yu ', 'Long ', 'Lai ', '[?] ', 'Xian ', 'Kwi ', 'Ju ', 'Xiao ', 'Ling ', 'Ying ', 'Jian ', 'Yin ', 'You ', 'Ying '];
<?php return ['Xiang ', 'Nong ', 'Bo ', 'Chan ', 'Lan ', 'Ju ', 'Shuang ', 'She ', 'Wei ', 'Cong ', 'Quan ', 'Qu ', 'Cang ', '[?] ', 'Yu ', 'Luo ', 'Li ', 'Zan ', 'Luan ', 'Dang ', 'Jue ', 'Em ', 'Lan ', 'Lan ', 'Zhu ', 'Lei ', 'Li ', 'Ba ', 'Nang ', 'Yu ', 'Ling ', 'Tsuki ', 'Qian ', 'Ci ', 'Huan ', 'Xin ', 'Yu ', 'Yu ', 'Qian ', 'Ou ', 'Xu ', 'Chao ', 'Chu ', 'Chi ', 'Kai ', 'Yi ', 'Jue ', 'Xi ', 'Xu ', 'Xia ', 'Yu ', 'Kuai ', 'Lang ', 'Kuan ', 'Shuo ', 'Xi ', 'Ai ', 'Yi ', 'Qi ', 'Hu ', 'Chi ', 'Qin ', 'Kuan ', 'Kan ', 'Kuan ', 'Kan ', 'Chuan ', 'Sha ', 'Gua ', 'Yin ', 'Xin ', 'Xie ', 'Yu ', 'Qian ', 'Xiao ', 'Yi ', 'Ge ', 'Wu ', 'Tan ', 'Jin ', 'Ou ', 'Hu ', 'Ti ', 'Huan ', 'Xu ', 'Pen ', 'Xi ', 'Xiao ', 'Xu ', 'Xi ', 'Sen ', 'Lian ', 'Chu ', 'Yi ', 'Kan ', 'Yu ', 'Chuo ', 'Huan ', 'Zhi ', 'Zheng ', 'Ci ', 'Bu ', 'Wu ', 'Qi ', 'Bu ', 'Bu ', 'Wai ', 'Ju ', 'Qian ', 'Chi ', 'Se ', 'Chi ', 'Se ', 'Zhong ', 'Sui ', 'Sui ', 'Li ', 'Cuo ', 'Yu ', 'Li ', 'Gui ', 'Dai ', 'Dai ', 'Si ', 'Jian ', 'Zhe ', 'Mo ', 'Mo ', 'Yao ', 'Mo ', 'Cu ', 'Yang ', 'Tian ', 'Sheng ', 'Dai ', 'Shang ', 'Xu ', 'Xun ', 'Shu ', 'Can ', 'Jue ', 'Piao ', 'Qia ', 'Qiu ', 'Su ', 'Qing ', 'Yun ', 'Lian ', 'Yi ', 'Fou ', 'Zhi ', 'Ye ', 'Can ', 'Hun ', 'Dan ', 'Ji ', 'Ye ', 'Zhen ', 'Yun ', 'Wen ', 'Chou ', 'Bin ', 'Ti ', 'Jin ', 'Shang ', 'Yin ', 'Diao ', 'Cu ', 'Hui ', 'Cuan ', 'Yi ', 'Dan ', 'Du ', 'Jiang ', 'Lian ', 'Bin ', 'Du ', 'Tsukusu ', 'Jian ', 'Shu ', 'Ou ', 'Duan ', 'Zhu ', 'Yin ', 'Qing ', 'Yi ', 'Sha ', 'Que ', 'Ke ', 'Yao ', 'Jun ', 'Dian ', 'Hui ', 'Hui ', 'Gu ', 'Que ', 'Ji ', 'Yi ', 'Ou ', 'Hui ', 'Duan ', 'Yi ', 'Xiao ', 'Wu ', 'Guan ', 'Mu ', 'Mei ', 'Mei ', 'Ai ', 'Zuo ', 'Du ', 'Yu ', 'Bi ', 'Bi ', 'Bi ', 'Pi ', 'Pi ', 'Bi ', 'Chan ', 'Mao ', '[?] ', '[?] ', 'Pu ', 'Mushiru ', 'Jia ', 'Zhan ', 'Sai ', 'Mu ', 'Tuo ', 'Xun ', 'Er ', 'Rong ', 'Xian ', 'Ju ', 'Mu ', 'Hao ', 'Qiu ', 'Dou ', 'Mushiru ', 'Tan ', 'Pei ', 'Ju ', 'Duo ', 'Cui ', 'Bi ', 'San ', '[?] ', 'Mao ', 'Sui ', 'Yu ', 'Yu ', 'Tuo ', 'He ', 'Jian ', 'Ta ', 'San '];
<?php return ['Lu ', 'Mu ', 'Li ', 'Tong ', 'Rong ', 'Chang ', 'Pu ', 'Luo ', 'Zhan ', 'Sao ', 'Zhan ', 'Meng ', 'Luo ', 'Qu ', 'Die ', 'Shi ', 'Di ', 'Min ', 'Jue ', 'Mang ', 'Qi ', 'Pie ', 'Nai ', 'Qi ', 'Dao ', 'Xian ', 'Chuan ', 'Fen ', 'Ri ', 'Nei ', '[?] ', 'Fu ', 'Shen ', 'Dong ', 'Qing ', 'Qi ', 'Yin ', 'Xi ', 'Hai ', 'Yang ', 'An ', 'Ya ', 'Ke ', 'Qing ', 'Ya ', 'Dong ', 'Dan ', 'Lu ', 'Qing ', 'Yang ', 'Yun ', 'Yun ', 'Shui ', 'San ', 'Zheng ', 'Bing ', 'Yong ', 'Dang ', 'Shitamizu ', 'Le ', 'Ni ', 'Tun ', 'Fan ', 'Gui ', 'Ting ', 'Zhi ', 'Qiu ', 'Bin ', 'Ze ', 'Mian ', 'Cuan ', 'Hui ', 'Diao ', 'Yi ', 'Cha ', 'Zhuo ', 'Chuan ', 'Wan ', 'Fan ', 'Dai ', 'Xi ', 'Tuo ', 'Mang ', 'Qiu ', 'Qi ', 'Shan ', 'Pai ', 'Han ', 'Qian ', 'Wu ', 'Wu ', 'Xun ', 'Si ', 'Ru ', 'Gong ', 'Jiang ', 'Chi ', 'Wu ', 'Tsuchi ', '[?] ', 'Tang ', 'Zhi ', 'Chi ', 'Qian ', 'Mi ', 'Yu ', 'Wang ', 'Qing ', 'Jing ', 'Rui ', 'Jun ', 'Hong ', 'Tai ', 'Quan ', 'Ji ', 'Bian ', 'Bian ', 'Gan ', 'Wen ', 'Zhong ', 'Fang ', 'Xiong ', 'Jue ', 'Hang ', 'Niou ', 'Qi ', 'Fen ', 'Xu ', 'Xu ', 'Qin ', 'Yi ', 'Wo ', 'Yun ', 'Yuan ', 'Hang ', 'Yan ', 'Chen ', 'Chen ', 'Dan ', 'You ', 'Dun ', 'Hu ', 'Huo ', 'Qie ', 'Mu ', 'Rou ', 'Mei ', 'Ta ', 'Mian ', 'Wu ', 'Chong ', 'Tian ', 'Bi ', 'Sha ', 'Zhi ', 'Pei ', 'Pan ', 'Zhui ', 'Za ', 'Gou ', 'Liu ', 'Mei ', 'Ze ', 'Feng ', 'Ou ', 'Li ', 'Lun ', 'Cang ', 'Feng ', 'Wei ', 'Hu ', 'Mo ', 'Mei ', 'Shu ', 'Ju ', 'Zan ', 'Tuo ', 'Tuo ', 'Tuo ', 'He ', 'Li ', 'Mi ', 'Yi ', 'Fa ', 'Fei ', 'You ', 'Tian ', 'Zhi ', 'Zhao ', 'Gu ', 'Zhan ', 'Yan ', 'Si ', 'Kuang ', 'Jiong ', 'Ju ', 'Xie ', 'Qiu ', 'Yi ', 'Jia ', 'Zhong ', 'Quan ', 'Bo ', 'Hui ', 'Mi ', 'Ben ', 'Zhuo ', 'Chu ', 'Le ', 'You ', 'Gu ', 'Hong ', 'Gan ', 'Fa ', 'Mao ', 'Si ', 'Hu ', 'Ping ', 'Ci ', 'Fan ', 'Chi ', 'Su ', 'Ning ', 'Cheng ', 'Ling ', 'Pao ', 'Bo ', 'Qi ', 'Si ', 'Ni ', 'Ju ', 'Yue ', 'Zhu ', 'Sheng ', 'Lei ', 'Xuan ', 'Xue ', 'Fu ', 'Pan ', 'Min ', 'Tai ', 'Yang ', 'Ji ', 'Yong ', 'Guan ', 'Beng ', 'Xue ', 'Long ', 'Lu ', '[?] ', 'Bo ', 'Xie ', 'Po ', 'Ze ', 'Jing ', 'Yin '];
<?php return ['Zhou ', 'Ji ', 'Yi ', 'Hui ', 'Hui ', 'Zui ', 'Cheng ', 'Yin ', 'Wei ', 'Hou ', 'Jian ', 'Yang ', 'Lie ', 'Si ', 'Ji ', 'Er ', 'Xing ', 'Fu ', 'Sa ', 'Suo ', 'Zhi ', 'Yin ', 'Wu ', 'Xi ', 'Kao ', 'Zhu ', 'Jiang ', 'Luo ', '[?] ', 'An ', 'Dong ', 'Yi ', 'Mou ', 'Lei ', 'Yi ', 'Mi ', 'Quan ', 'Jin ', 'Mo ', 'Wei ', 'Xiao ', 'Xie ', 'Hong ', 'Xu ', 'Shuo ', 'Kuang ', 'Tao ', 'Qie ', 'Ju ', 'Er ', 'Zhou ', 'Ru ', 'Ping ', 'Xun ', 'Xiong ', 'Zhi ', 'Guang ', 'Huan ', 'Ming ', 'Huo ', 'Wa ', 'Qia ', 'Pai ', 'Wu ', 'Qu ', 'Liu ', 'Yi ', 'Jia ', 'Jing ', 'Qian ', 'Jiang ', 'Jiao ', 'Cheng ', 'Shi ', 'Zhuo ', 'Ce ', 'Pal ', 'Kuai ', 'Ji ', 'Liu ', 'Chan ', 'Hun ', 'Hu ', 'Nong ', 'Xun ', 'Jin ', 'Lie ', 'Qiu ', 'Wei ', 'Zhe ', 'Jun ', 'Han ', 'Bang ', 'Mang ', 'Zhuo ', 'You ', 'Xi ', 'Bo ', 'Dou ', 'Wan ', 'Hong ', 'Yi ', 'Pu ', 'Ying ', 'Lan ', 'Hao ', 'Lang ', 'Han ', 'Li ', 'Geng ', 'Fu ', 'Wu ', 'Lian ', 'Chun ', 'Feng ', 'Yi ', 'Yu ', 'Tong ', 'Lao ', 'Hai ', 'Jin ', 'Jia ', 'Chong ', 'Weng ', 'Mei ', 'Sui ', 'Cheng ', 'Pei ', 'Xian ', 'Shen ', 'Tu ', 'Kun ', 'Pin ', 'Nie ', 'Han ', 'Jing ', 'Xiao ', 'She ', 'Nian ', 'Tu ', 'Yong ', 'Xiao ', 'Xian ', 'Ting ', 'E ', 'Su ', 'Tun ', 'Juan ', 'Cen ', 'Ti ', 'Li ', 'Shui ', 'Si ', 'Lei ', 'Shui ', 'Tao ', 'Du ', 'Lao ', 'Lai ', 'Lian ', 'Wei ', 'Wo ', 'Yun ', 'Huan ', 'Di ', '[?] ', 'Run ', 'Jian ', 'Zhang ', 'Se ', 'Fu ', 'Guan ', 'Xing ', 'Shou ', 'Shuan ', 'Ya ', 'Chuo ', 'Zhang ', 'Ye ', 'Kong ', 'Wo ', 'Han ', 'Tuo ', 'Dong ', 'He ', 'Wo ', 'Ju ', 'Gan ', 'Liang ', 'Hun ', 'Ta ', 'Zhuo ', 'Dian ', 'Qie ', 'De ', 'Juan ', 'Zi ', 'Xi ', 'Yao ', 'Qi ', 'Gu ', 'Guo ', 'Han ', 'Lin ', 'Tang ', 'Zhou ', 'Peng ', 'Hao ', 'Chang ', 'Shu ', 'Qi ', 'Fang ', 'Chi ', 'Lu ', 'Nao ', 'Ju ', 'Tao ', 'Cong ', 'Lei ', 'Zhi ', 'Peng ', 'Fei ', 'Song ', 'Tian ', 'Pi ', 'Dan ', 'Yu ', 'Ni ', 'Yu ', 'Lu ', 'Gan ', 'Mi ', 'Jing ', 'Ling ', 'Lun ', 'Yin ', 'Cui ', 'Qu ', 'Huai ', 'Yu ', 'Nian ', 'Shen ', 'Piao ', 'Chun ', 'Wa ', 'Yuan ', 'Lai ', 'Hun ', 'Qing ', 'Yan ', 'Qian ', 'Tian ', 'Miao ', 'Zhi ', 'Yin ', 'Mi '];
<?php return ['Ben ', 'Yuan ', 'Wen ', 'Re ', 'Fei ', 'Qing ', 'Yuan ', 'Ke ', 'Ji ', 'She ', 'Yuan ', 'Shibui ', 'Lu ', 'Zi ', 'Du ', '[?] ', 'Jian ', 'Min ', 'Pi ', 'Tani ', 'Yu ', 'Yuan ', 'Shen ', 'Shen ', 'Rou ', 'Huan ', 'Zhu ', 'Jian ', 'Nuan ', 'Yu ', 'Qiu ', 'Ting ', 'Qu ', 'Du ', 'Feng ', 'Zha ', 'Bo ', 'Wo ', 'Wo ', 'Di ', 'Wei ', 'Wen ', 'Ru ', 'Xie ', 'Ce ', 'Wei ', 'Ge ', 'Gang ', 'Yan ', 'Hong ', 'Xuan ', 'Mi ', 'Ke ', 'Mao ', 'Ying ', 'Yan ', 'You ', 'Hong ', 'Miao ', 'Xing ', 'Mei ', 'Zai ', 'Hun ', 'Nai ', 'Kui ', 'Shi ', 'E ', 'Pai ', 'Mei ', 'Lian ', 'Qi ', 'Qi ', 'Mei ', 'Tian ', 'Cou ', 'Wei ', 'Can ', 'Tuan ', 'Mian ', 'Hui ', 'Mo ', 'Xu ', 'Ji ', 'Pen ', 'Jian ', 'Jian ', 'Hu ', 'Feng ', 'Xiang ', 'Yi ', 'Yin ', 'Zhan ', 'Shi ', 'Jie ', 'Cheng ', 'Huang ', 'Tan ', 'Yu ', 'Bi ', 'Min ', 'Shi ', 'Tu ', 'Sheng ', 'Yong ', 'Qu ', 'Zhong ', 'Suei ', 'Jiu ', 'Jiao ', 'Qiou ', 'Yin ', 'Tang ', 'Long ', 'Huo ', 'Yuan ', 'Nan ', 'Ban ', 'You ', 'Quan ', 'Chui ', 'Liang ', 'Chan ', 'Yan ', 'Chun ', 'Nie ', 'Zi ', 'Wan ', 'Shi ', 'Man ', 'Ying ', 'Ratsu ', 'Kui ', '[?] ', 'Jian ', 'Xu ', 'Lu ', 'Gui ', 'Gai ', '[?] ', '[?] ', 'Po ', 'Jin ', 'Gui ', 'Tang ', 'Yuan ', 'Suo ', 'Yuan ', 'Lian ', 'Yao ', 'Meng ', 'Zhun ', 'Sheng ', 'Ke ', 'Tai ', 'Da ', 'Wa ', 'Liu ', 'Gou ', 'Sao ', 'Ming ', 'Zha ', 'Shi ', 'Yi ', 'Lun ', 'Ma ', 'Pu ', 'Wei ', 'Li ', 'Cai ', 'Wu ', 'Xi ', 'Wen ', 'Qiang ', 'Ze ', 'Shi ', 'Su ', 'Yi ', 'Zhen ', 'Sou ', 'Yun ', 'Xiu ', 'Yin ', 'Rong ', 'Hun ', 'Su ', 'Su ', 'Ni ', 'Ta ', 'Shi ', 'Ru ', 'Wei ', 'Pan ', 'Chu ', 'Chu ', 'Pang ', 'Weng ', 'Cang ', 'Mie ', 'He ', 'Dian ', 'Hao ', 'Huang ', 'Xi ', 'Zi ', 'Di ', 'Zhi ', 'Ying ', 'Fu ', 'Jie ', 'Hua ', 'Ge ', 'Zi ', 'Tao ', 'Teng ', 'Sui ', 'Bi ', 'Jiao ', 'Hui ', 'Gun ', 'Yin ', 'Gao ', 'Long ', 'Zhi ', 'Yan ', 'She ', 'Man ', 'Ying ', 'Chun ', 'Lu ', 'Lan ', 'Luan ', '[?] ', 'Bin ', 'Tan ', 'Yu ', 'Sou ', 'Hu ', 'Bi ', 'Biao ', 'Zhi ', 'Jiang ', 'Kou ', 'Shen ', 'Shang ', 'Di ', 'Mi ', 'Ao ', 'Lu ', 'Hu ', 'Hu ', 'You ', 'Chan ', 'Fan ', 'Yong ', 'Gun ', 'Man '];
<?php return ['Qing ', 'Yu ', 'Piao ', 'Ji ', 'Ya ', 'Jiao ', 'Qi ', 'Xi ', 'Ji ', 'Lu ', 'Lu ', 'Long ', 'Jin ', 'Guo ', 'Cong ', 'Lou ', 'Zhi ', 'Gai ', 'Qiang ', 'Li ', 'Yan ', 'Cao ', 'Jiao ', 'Cong ', 'Qun ', 'Tuan ', 'Ou ', 'Teng ', 'Ye ', 'Xi ', 'Mi ', 'Tang ', 'Mo ', 'Shang ', 'Han ', 'Lian ', 'Lan ', 'Wa ', 'Li ', 'Qian ', 'Feng ', 'Xuan ', 'Yi ', 'Man ', 'Zi ', 'Mang ', 'Kang ', 'Lei ', 'Peng ', 'Shu ', 'Zhang ', 'Zhang ', 'Chong ', 'Xu ', 'Huan ', 'Kuo ', 'Jian ', 'Yan ', 'Chuang ', 'Liao ', 'Cui ', 'Ti ', 'Yang ', 'Jiang ', 'Cong ', 'Ying ', 'Hong ', 'Xun ', 'Shu ', 'Guan ', 'Ying ', 'Xiao ', '[?] ', '[?] ', 'Xu ', 'Lian ', 'Zhi ', 'Wei ', 'Pi ', 'Jue ', 'Jiao ', 'Po ', 'Dang ', 'Hui ', 'Jie ', 'Wu ', 'Pa ', 'Ji ', 'Pan ', 'Gui ', 'Xiao ', 'Qian ', 'Qian ', 'Xi ', 'Lu ', 'Xi ', 'Xuan ', 'Dun ', 'Huang ', 'Min ', 'Run ', 'Su ', 'Liao ', 'Zhen ', 'Zhong ', 'Yi ', 'Di ', 'Wan ', 'Dan ', 'Tan ', 'Chao ', 'Xun ', 'Kui ', 'Yie ', 'Shao ', 'Tu ', 'Zhu ', 'San ', 'Hei ', 'Bi ', 'Shan ', 'Chan ', 'Chan ', 'Shu ', 'Tong ', 'Pu ', 'Lin ', 'Wei ', 'Se ', 'Se ', 'Cheng ', 'Jiong ', 'Cheng ', 'Hua ', 'Jiao ', 'Lao ', 'Che ', 'Gan ', 'Cun ', 'Heng ', 'Si ', 'Shu ', 'Peng ', 'Han ', 'Yun ', 'Liu ', 'Hong ', 'Fu ', 'Hao ', 'He ', 'Xian ', 'Jian ', 'Shan ', 'Xi ', 'Oki ', '[?] ', 'Lan ', '[?] ', 'Yu ', 'Lin ', 'Min ', 'Zao ', 'Dang ', 'Wan ', 'Ze ', 'Xie ', 'Yu ', 'Li ', 'Shi ', 'Xue ', 'Ling ', 'Man ', 'Zi ', 'Yong ', 'Kuai ', 'Can ', 'Lian ', 'Dian ', 'Ye ', 'Ao ', 'Huan ', 'Zhen ', 'Chan ', 'Man ', 'Dan ', 'Dan ', 'Yi ', 'Sui ', 'Pi ', 'Ju ', 'Ta ', 'Qin ', 'Ji ', 'Zhuo ', 'Lian ', 'Nong ', 'Guo ', 'Jin ', 'Fen ', 'Se ', 'Ji ', 'Sui ', 'Hui ', 'Chu ', 'Ta ', 'Song ', 'Ding ', '[?] ', 'Zhu ', 'Lai ', 'Bin ', 'Lian ', 'Mi ', 'Shi ', 'Shu ', 'Mi ', 'Ning ', 'Ying ', 'Ying ', 'Meng ', 'Jin ', 'Qi ', 'Pi ', 'Ji ', 'Hao ', 'Ru ', 'Zui ', 'Wo ', 'Tao ', 'Yin ', 'Yin ', 'Dui ', 'Ci ', 'Huo ', 'Jing ', 'Lan ', 'Jun ', 'Ai ', 'Pu ', 'Zhuo ', 'Wei ', 'Bin ', 'Gu ', 'Qian ', 'Xing ', 'Hama ', 'Kuo ', 'Fei ', '[?] ', 'Boku ', 'Jian ', 'Wei ', 'Luo ', 'Zan ', 'Lu ', 'Li '];
<?php return ['You ', 'Yang ', 'Lu ', 'Si ', 'Jie ', 'Ying ', 'Du ', 'Wang ', 'Hui ', 'Xie ', 'Pan ', 'Shen ', 'Biao ', 'Chan ', 'Mo ', 'Liu ', 'Jian ', 'Pu ', 'Se ', 'Cheng ', 'Gu ', 'Bin ', 'Huo ', 'Xian ', 'Lu ', 'Qin ', 'Han ', 'Ying ', 'Yong ', 'Li ', 'Jing ', 'Xiao ', 'Ying ', 'Sui ', 'Wei ', 'Xie ', 'Huai ', 'Hao ', 'Zhu ', 'Long ', 'Lai ', 'Dui ', 'Fan ', 'Hu ', 'Lai ', '[?] ', '[?] ', 'Ying ', 'Mi ', 'Ji ', 'Lian ', 'Jian ', 'Ying ', 'Fen ', 'Lin ', 'Yi ', 'Jian ', 'Yue ', 'Chan ', 'Dai ', 'Rang ', 'Jian ', 'Lan ', 'Fan ', 'Shuang ', 'Yuan ', 'Zhuo ', 'Feng ', 'She ', 'Lei ', 'Lan ', 'Cong ', 'Qu ', 'Yong ', 'Qian ', 'Fa ', 'Guan ', 'Que ', 'Yan ', 'Hao ', 'Hyeng ', 'Sa ', 'Zan ', 'Luan ', 'Yan ', 'Li ', 'Mi ', 'Shan ', 'Tan ', 'Dang ', 'Jiao ', 'Chan ', '[?] ', 'Hao ', 'Ba ', 'Zhu ', 'Lan ', 'Lan ', 'Nang ', 'Wan ', 'Luan ', 'Xun ', 'Xian ', 'Yan ', 'Gan ', 'Yan ', 'Yu ', 'Huo ', 'Si ', 'Mie ', 'Guang ', 'Deng ', 'Hui ', 'Xiao ', 'Xiao ', 'Hu ', 'Hong ', 'Ling ', 'Zao ', 'Zhuan ', 'Jiu ', 'Zha ', 'Xie ', 'Chi ', 'Zhuo ', 'Zai ', 'Zai ', 'Can ', 'Yang ', 'Qi ', 'Zhong ', 'Fen ', 'Niu ', 'Jiong ', 'Wen ', 'Po ', 'Yi ', 'Lu ', 'Chui ', 'Pi ', 'Kai ', 'Pan ', 'Yan ', 'Kai ', 'Pang ', 'Mu ', 'Chao ', 'Liao ', 'Gui ', 'Kang ', 'Tun ', 'Guang ', 'Xin ', 'Zhi ', 'Guang ', 'Guang ', 'Wei ', 'Qiang ', '[?] ', 'Da ', 'Xia ', 'Zheng ', 'Zhu ', 'Ke ', 'Zhao ', 'Fu ', 'Ba ', 'Duo ', 'Duo ', 'Ling ', 'Zhuo ', 'Xuan ', 'Ju ', 'Tan ', 'Pao ', 'Jiong ', 'Pao ', 'Tai ', 'Tai ', 'Bing ', 'Yang ', 'Tong ', 'Han ', 'Zhu ', 'Zha ', 'Dian ', 'Wei ', 'Shi ', 'Lian ', 'Chi ', 'Huang ', '[?] ', 'Hu ', 'Shuo ', 'Lan ', 'Jing ', 'Jiao ', 'Xu ', 'Xing ', 'Quan ', 'Lie ', 'Huan ', 'Yang ', 'Xiao ', 'Xiu ', 'Xian ', 'Yin ', 'Wu ', 'Zhou ', 'Yao ', 'Shi ', 'Wei ', 'Tong ', 'Xue ', 'Zai ', 'Kai ', 'Hong ', 'Luo ', 'Xia ', 'Zhu ', 'Xuan ', 'Zheng ', 'Po ', 'Yan ', 'Hui ', 'Guang ', 'Zhe ', 'Hui ', 'Kao ', '[?] ', 'Fan ', 'Shao ', 'Ye ', 'Hui ', '[?] ', 'Tang ', 'Jin ', 'Re ', '[?] ', 'Xi ', 'Fu ', 'Jiong ', 'Che ', 'Pu ', 'Jing ', 'Zhuo ', 'Ting ', 'Wan ', 'Hai ', 'Peng ', 'Lang ', 'Shan ', 'Hu ', 'Feng ', 'Chi ', 'Rong '];
<?php return ['Hu ', 'Xi ', 'Shu ', 'He ', 'Xun ', 'Ku ', 'Jue ', 'Xiao ', 'Xi ', 'Yan ', 'Han ', 'Zhuang ', 'Jun ', 'Di ', 'Xie ', 'Ji ', 'Wu ', '[?] ', '[?] ', 'Han ', 'Yan ', 'Huan ', 'Men ', 'Ju ', 'Chou ', 'Bei ', 'Fen ', 'Lin ', 'Kun ', 'Hun ', 'Tun ', 'Xi ', 'Cui ', 'Wu ', 'Hong ', 'Ju ', 'Fu ', 'Wo ', 'Jiao ', 'Cong ', 'Feng ', 'Ping ', 'Qiong ', 'Ruo ', 'Xi ', 'Qiong ', 'Xin ', 'Zhuo ', 'Yan ', 'Yan ', 'Yi ', 'Jue ', 'Yu ', 'Gang ', 'Ran ', 'Pi ', 'Gu ', '[?] ', 'Sheng ', 'Chang ', 'Shao ', '[?] ', '[?] ', '[?] ', '[?] ', 'Chen ', 'He ', 'Kui ', 'Zhong ', 'Duan ', 'Xia ', 'Hui ', 'Feng ', 'Lian ', 'Xuan ', 'Xing ', 'Huang ', 'Jiao ', 'Jian ', 'Bi ', 'Ying ', 'Zhu ', 'Wei ', 'Tuan ', 'Tian ', 'Xi ', 'Nuan ', 'Nuan ', 'Chan ', 'Yan ', 'Jiong ', 'Jiong ', 'Yu ', 'Mei ', 'Sha ', 'Wei ', 'Ye ', 'Xin ', 'Qiong ', 'Rou ', 'Mei ', 'Huan ', 'Xu ', 'Zhao ', 'Wei ', 'Fan ', 'Qiu ', 'Sui ', 'Yang ', 'Lie ', 'Zhu ', 'Jie ', 'Gao ', 'Gua ', 'Bao ', 'Hu ', 'Yun ', 'Xia ', '[?] ', '[?] ', 'Bian ', 'Gou ', 'Tui ', 'Tang ', 'Chao ', 'Shan ', 'N ', 'Bo ', 'Huang ', 'Xie ', 'Xi ', 'Wu ', 'Xi ', 'Yun ', 'He ', 'He ', 'Xi ', 'Yun ', 'Xiong ', 'Nai ', 'Shan ', 'Qiong ', 'Yao ', 'Xun ', 'Mi ', 'Lian ', 'Ying ', 'Wen ', 'Rong ', 'Oozutsu ', '[?] ', 'Qiang ', 'Liu ', 'Xi ', 'Bi ', 'Biao ', 'Zong ', 'Lu ', 'Jian ', 'Shou ', 'Yi ', 'Lou ', 'Feng ', 'Sui ', 'Yi ', 'Tong ', 'Jue ', 'Zong ', 'Yun ', 'Hu ', 'Yi ', 'Zhi ', 'Ao ', 'Wei ', 'Liao ', 'Han ', 'Ou ', 'Re ', 'Jiong ', 'Man ', '[?] ', 'Shang ', 'Cuan ', 'Zeng ', 'Jian ', 'Xi ', 'Xi ', 'Xi ', 'Yi ', 'Xiao ', 'Chi ', 'Huang ', 'Chan ', 'Ye ', 'Qian ', 'Ran ', 'Yan ', 'Xian ', 'Qiao ', 'Zun ', 'Deng ', 'Dun ', 'Shen ', 'Jiao ', 'Fen ', 'Si ', 'Liao ', 'Yu ', 'Lin ', 'Tong ', 'Shao ', 'Fen ', 'Fan ', 'Yan ', 'Xun ', 'Lan ', 'Mei ', 'Tang ', 'Yi ', 'Jing ', 'Men ', '[?] ', '[?] ', 'Ying ', 'Yu ', 'Yi ', 'Xue ', 'Lan ', 'Tai ', 'Zao ', 'Can ', 'Sui ', 'Xi ', 'Que ', 'Cong ', 'Lian ', 'Hui ', 'Zhu ', 'Xie ', 'Ling ', 'Wei ', 'Yi ', 'Xie ', 'Zhao ', 'Hui ', 'Tatsu ', 'Nung ', 'Lan ', 'Ru ', 'Xian ', 'Kao ', 'Xun ', 'Jin ', 'Chou ', 'Chou ', 'Yao '];
<?php return ['He ', 'Lan ', 'Biao ', 'Rong ', 'Li ', 'Mo ', 'Bao ', 'Ruo ', 'Lu ', 'La ', 'Ao ', 'Xun ', 'Kuang ', 'Shuo ', '[?] ', 'Li ', 'Lu ', 'Jue ', 'Liao ', 'Yan ', 'Xi ', 'Xie ', 'Long ', 'Ye ', '[?] ', 'Rang ', 'Yue ', 'Lan ', 'Cong ', 'Jue ', 'Tong ', 'Guan ', '[?] ', 'Che ', 'Mi ', 'Tang ', 'Lan ', 'Zhu ', '[?] ', 'Ling ', 'Cuan ', 'Yu ', 'Zhua ', 'Tsumekanmuri ', 'Pa ', 'Zheng ', 'Pao ', 'Cheng ', 'Yuan ', 'Ai ', 'Wei ', '[?] ', 'Jue ', 'Jue ', 'Fu ', 'Ye ', 'Ba ', 'Die ', 'Ye ', 'Yao ', 'Zu ', 'Shuang ', 'Er ', 'Qiang ', 'Chuang ', 'Ge ', 'Zang ', 'Die ', 'Qiang ', 'Yong ', 'Qiang ', 'Pian ', 'Ban ', 'Pan ', 'Shao ', 'Jian ', 'Pai ', 'Du ', 'Chuang ', 'Tou ', 'Zha ', 'Bian ', 'Die ', 'Bang ', 'Bo ', 'Chuang ', 'You ', '[?] ', 'Du ', 'Ya ', 'Cheng ', 'Niu ', 'Ushihen ', 'Pin ', 'Jiu ', 'Mou ', 'Tuo ', 'Mu ', 'Lao ', 'Ren ', 'Mang ', 'Fang ', 'Mao ', 'Mu ', 'Gang ', 'Wu ', 'Yan ', 'Ge ', 'Bei ', 'Si ', 'Jian ', 'Gu ', 'You ', 'Ge ', 'Sheng ', 'Mu ', 'Di ', 'Qian ', 'Quan ', 'Quan ', 'Zi ', 'Te ', 'Xi ', 'Mang ', 'Keng ', 'Qian ', 'Wu ', 'Gu ', 'Xi ', 'Li ', 'Li ', 'Pou ', 'Ji ', 'Gang ', 'Zhi ', 'Ben ', 'Quan ', 'Run ', 'Du ', 'Ju ', 'Jia ', 'Jian ', 'Feng ', 'Pian ', 'Ke ', 'Ju ', 'Kao ', 'Chu ', 'Xi ', 'Bei ', 'Luo ', 'Jie ', 'Ma ', 'San ', 'Wei ', 'Li ', 'Dun ', 'Tong ', '[?] ', 'Jiang ', 'Ikenie ', 'Li ', 'Du ', 'Lie ', 'Pi ', 'Piao ', 'Bao ', 'Xi ', 'Chou ', 'Wei ', 'Kui ', 'Chou ', 'Quan ', 'Fan ', 'Ba ', 'Fan ', 'Qiu ', 'Ji ', 'Cai ', 'Chuo ', 'An ', 'Jie ', 'Zhuang ', 'Guang ', 'Ma ', 'You ', 'Kang ', 'Bo ', 'Hou ', 'Ya ', 'Yin ', 'Huan ', 'Zhuang ', 'Yun ', 'Kuang ', 'Niu ', 'Di ', 'Qing ', 'Zhong ', 'Mu ', 'Bei ', 'Pi ', 'Ju ', 'Ni ', 'Sheng ', 'Pao ', 'Xia ', 'Tuo ', 'Hu ', 'Ling ', 'Fei ', 'Pi ', 'Ni ', 'Ao ', 'You ', 'Gou ', 'Yue ', 'Ju ', 'Dan ', 'Po ', 'Gu ', 'Xian ', 'Ning ', 'Huan ', 'Hen ', 'Jiao ', 'He ', 'Zhao ', 'Ji ', 'Xun ', 'Shan ', 'Ta ', 'Rong ', 'Shou ', 'Tong ', 'Lao ', 'Du ', 'Xia ', 'Shi ', 'Hua ', 'Zheng ', 'Yu ', 'Sun ', 'Yu ', 'Bi ', 'Mang ', 'Xi ', 'Juan ', 'Li ', 'Xia ', 'Yin ', 'Suan ', 'Lang ', 'Bei ', 'Zhi ', 'Yan '];
<?php return ['Sha ', 'Li ', 'Han ', 'Xian ', 'Jing ', 'Pai ', 'Fei ', 'Yao ', 'Ba ', 'Qi ', 'Ni ', 'Biao ', 'Yin ', 'Lai ', 'Xi ', 'Jian ', 'Qiang ', 'Kun ', 'Yan ', 'Guo ', 'Zong ', 'Mi ', 'Chang ', 'Yi ', 'Zhi ', 'Zheng ', 'Ya ', 'Meng ', 'Cai ', 'Cu ', 'She ', 'Kari ', 'Cen ', 'Luo ', 'Hu ', 'Zong ', 'Ji ', 'Wei ', 'Feng ', 'Wo ', 'Yuan ', 'Xing ', 'Zhu ', 'Mao ', 'Wei ', 'Yuan ', 'Xian ', 'Tuan ', 'Ya ', 'Nao ', 'Xie ', 'Jia ', 'Hou ', 'Bian ', 'You ', 'You ', 'Mei ', 'Zha ', 'Yao ', 'Sun ', 'Bo ', 'Ming ', 'Hua ', 'Yuan ', 'Sou ', 'Ma ', 'Yuan ', 'Dai ', 'Yu ', 'Shi ', 'Hao ', '[?] ', 'Yi ', 'Zhen ', 'Chuang ', 'Hao ', 'Man ', 'Jing ', 'Jiang ', 'Mu ', 'Zhang ', 'Chan ', 'Ao ', 'Ao ', 'Hao ', 'Cui ', 'Fen ', 'Jue ', 'Bi ', 'Bi ', 'Huang ', 'Pu ', 'Lin ', 'Yu ', 'Tong ', 'Yao ', 'Liao ', 'Shuo ', 'Xiao ', 'Swu ', 'Ton ', 'Xi ', 'Ge ', 'Juan ', 'Du ', 'Hui ', 'Kuai ', 'Xian ', 'Xie ', 'Ta ', 'Xian ', 'Xun ', 'Ning ', 'Pin ', 'Huo ', 'Nou ', 'Meng ', 'Lie ', 'Nao ', 'Guang ', 'Shou ', 'Lu ', 'Ta ', 'Xian ', 'Mi ', 'Rang ', 'Huan ', 'Nao ', 'Luo ', 'Xian ', 'Qi ', 'Jue ', 'Xuan ', 'Miao ', 'Zi ', 'Lu ', 'Lu ', 'Yu ', 'Su ', 'Wang ', 'Qiu ', 'Ga ', 'Ding ', 'Le ', 'Ba ', 'Ji ', 'Hong ', 'Di ', 'Quan ', 'Gan ', 'Jiu ', 'Yu ', 'Ji ', 'Yu ', 'Yang ', 'Ma ', 'Gong ', 'Wu ', 'Fu ', 'Wen ', 'Jie ', 'Ya ', 'Fen ', 'Bian ', 'Beng ', 'Yue ', 'Jue ', 'Yun ', 'Jue ', 'Wan ', 'Jian ', 'Mei ', 'Dan ', 'Pi ', 'Wei ', 'Huan ', 'Xian ', 'Qiang ', 'Ling ', 'Dai ', 'Yi ', 'An ', 'Ping ', 'Dian ', 'Fu ', 'Xuan ', 'Xi ', 'Bo ', 'Ci ', 'Gou ', 'Jia ', 'Shao ', 'Po ', 'Ci ', 'Ke ', 'Ran ', 'Sheng ', 'Shen ', 'Yi ', 'Zu ', 'Jia ', 'Min ', 'Shan ', 'Liu ', 'Bi ', 'Zhen ', 'Zhen ', 'Jue ', 'Fa ', 'Long ', 'Jin ', 'Jiao ', 'Jian ', 'Li ', 'Guang ', 'Xian ', 'Zhou ', 'Gong ', 'Yan ', 'Xiu ', 'Yang ', 'Xu ', 'Luo ', 'Su ', 'Zhu ', 'Qin ', 'Ken ', 'Xun ', 'Bao ', 'Er ', 'Xiang ', 'Yao ', 'Xia ', 'Heng ', 'Gui ', 'Chong ', 'Xu ', 'Ban ', 'Pei ', '[?] ', 'Dang ', 'Ei ', 'Hun ', 'Wen ', 'E ', 'Cheng ', 'Ti ', 'Wu ', 'Wu ', 'Cheng ', 'Jun ', 'Mei ', 'Bei ', 'Ting ', 'Xian ', 'Chuo '];
<?php return ['Han ', 'Xuan ', 'Yan ', 'Qiu ', 'Quan ', 'Lang ', 'Li ', 'Xiu ', 'Fu ', 'Liu ', 'Ye ', 'Xi ', 'Ling ', 'Li ', 'Jin ', 'Lian ', 'Suo ', 'Chiisai ', '[?] ', 'Wan ', 'Dian ', 'Pin ', 'Zhan ', 'Cui ', 'Min ', 'Yu ', 'Ju ', 'Chen ', 'Lai ', 'Wen ', 'Sheng ', 'Wei ', 'Dian ', 'Chu ', 'Zhuo ', 'Pei ', 'Cheng ', 'Hu ', 'Qi ', 'E ', 'Kun ', 'Chang ', 'Qi ', 'Beng ', 'Wan ', 'Lu ', 'Cong ', 'Guan ', 'Yan ', 'Diao ', 'Bei ', 'Lin ', 'Qin ', 'Pi ', 'Pa ', 'Que ', 'Zhuo ', 'Qin ', 'Fa ', '[?] ', 'Qiong ', 'Du ', 'Jie ', 'Hun ', 'Yu ', 'Mao ', 'Mei ', 'Chun ', 'Xuan ', 'Ti ', 'Xing ', 'Dai ', 'Rou ', 'Min ', 'Zhen ', 'Wei ', 'Ruan ', 'Huan ', 'Jie ', 'Chuan ', 'Jian ', 'Zhuan ', 'Yang ', 'Lian ', 'Quan ', 'Xia ', 'Duan ', 'Yuan ', 'Ye ', 'Nao ', 'Hu ', 'Ying ', 'Yu ', 'Huang ', 'Rui ', 'Se ', 'Liu ', 'Shi ', 'Rong ', 'Suo ', 'Yao ', 'Wen ', 'Wu ', 'Jin ', 'Jin ', 'Ying ', 'Ma ', 'Tao ', 'Liu ', 'Tang ', 'Li ', 'Lang ', 'Gui ', 'Zhen ', 'Qiang ', 'Cuo ', 'Jue ', 'Zhao ', 'Yao ', 'Ai ', 'Bin ', 'Tu ', 'Chang ', 'Kun ', 'Zhuan ', 'Cong ', 'Jin ', 'Yi ', 'Cui ', 'Cong ', 'Qi ', 'Li ', 'Ying ', 'Suo ', 'Qiu ', 'Xuan ', 'Ao ', 'Lian ', 'Man ', 'Zhang ', 'Yin ', '[?] ', 'Ying ', 'Zhi ', 'Lu ', 'Wu ', 'Deng ', 'Xiou ', 'Zeng ', 'Xun ', 'Qu ', 'Dang ', 'Lin ', 'Liao ', 'Qiong ', 'Su ', 'Huang ', 'Gui ', 'Pu ', 'Jing ', 'Fan ', 'Jin ', 'Liu ', 'Ji ', '[?] ', 'Jing ', 'Ai ', 'Bi ', 'Can ', 'Qu ', 'Zao ', 'Dang ', 'Jiao ', 'Gun ', 'Tan ', 'Hui ', 'Huan ', 'Se ', 'Sui ', 'Tian ', '[?] ', 'Yu ', 'Jin ', 'Lu ', 'Bin ', 'Shou ', 'Wen ', 'Zui ', 'Lan ', 'Xi ', 'Ji ', 'Xuan ', 'Ruan ', 'Huo ', 'Gai ', 'Lei ', 'Du ', 'Li ', 'Zhi ', 'Rou ', 'Li ', 'Zan ', 'Qiong ', 'Zhe ', 'Gui ', 'Sui ', 'La ', 'Long ', 'Lu ', 'Li ', 'Zan ', 'Lan ', 'Ying ', 'Mi ', 'Xiang ', 'Xi ', 'Guan ', 'Dao ', 'Zan ', 'Huan ', 'Gua ', 'Bo ', 'Die ', 'Bao ', 'Hu ', 'Zhi ', 'Piao ', 'Ban ', 'Rang ', 'Li ', 'Wa ', 'Dekaguramu ', 'Jiang ', 'Qian ', 'Fan ', 'Pen ', 'Fang ', 'Dan ', 'Weng ', 'Ou ', 'Deshiguramu ', 'Miriguramu ', 'Thon ', 'Hu ', 'Ling ', 'Yi ', 'Ping ', 'Ci ', 'Hekutogura ', 'Juan ', 'Chang ', 'Chi ', 'Sarake ', 'Dang ', 'Meng ', 'Pou '];
<?php return ['Zhui ', 'Ping ', 'Bian ', 'Zhou ', 'Zhen ', 'Senchigura ', 'Ci ', 'Ying ', 'Qi ', 'Xian ', 'Lou ', 'Di ', 'Ou ', 'Meng ', 'Zhuan ', 'Peng ', 'Lin ', 'Zeng ', 'Wu ', 'Pi ', 'Dan ', 'Weng ', 'Ying ', 'Yan ', 'Gan ', 'Dai ', 'Shen ', 'Tian ', 'Tian ', 'Han ', 'Chang ', 'Sheng ', 'Qing ', 'Sheng ', 'Chan ', 'Chan ', 'Rui ', 'Sheng ', 'Su ', 'Sen ', 'Yong ', 'Shuai ', 'Lu ', 'Fu ', 'Yong ', 'Beng ', 'Feng ', 'Ning ', 'Tian ', 'You ', 'Jia ', 'Shen ', 'Zha ', 'Dian ', 'Fu ', 'Nan ', 'Dian ', 'Ping ', 'Ting ', 'Hua ', 'Ting ', 'Quan ', 'Zi ', 'Meng ', 'Bi ', 'Qi ', 'Liu ', 'Xun ', 'Liu ', 'Chang ', 'Mu ', 'Yun ', 'Fan ', 'Fu ', 'Geng ', 'Tian ', 'Jie ', 'Jie ', 'Quan ', 'Wei ', 'Fu ', 'Tian ', 'Mu ', 'Tap ', 'Pan ', 'Jiang ', 'Wa ', 'Da ', 'Nan ', 'Liu ', 'Ben ', 'Zhen ', 'Chu ', 'Mu ', 'Mu ', 'Ce ', 'Cen ', 'Gai ', 'Bi ', 'Da ', 'Zhi ', 'Lue ', 'Qi ', 'Lue ', 'Pan ', 'Kesa ', 'Fan ', 'Hua ', 'Yu ', 'Yu ', 'Mu ', 'Jun ', 'Yi ', 'Liu ', 'Yu ', 'Die ', 'Chou ', 'Hua ', 'Dang ', 'Chuo ', 'Ji ', 'Wan ', 'Jiang ', 'Sheng ', 'Chang ', 'Tuan ', 'Lei ', 'Ji ', 'Cha ', 'Liu ', 'Tatamu ', 'Tuan ', 'Lin ', 'Jiang ', 'Jiang ', 'Chou ', 'Bo ', 'Die ', 'Die ', 'Pi ', 'Nie ', 'Dan ', 'Shu ', 'Shu ', 'Zhi ', 'Yi ', 'Chuang ', 'Nai ', 'Ding ', 'Bi ', 'Jie ', 'Liao ', 'Gong ', 'Ge ', 'Jiu ', 'Zhou ', 'Xia ', 'Shan ', 'Xu ', 'Nue ', 'Li ', 'Yang ', 'Chen ', 'You ', 'Ba ', 'Jie ', 'Jue ', 'Zhi ', 'Xia ', 'Cui ', 'Bi ', 'Yi ', 'Li ', 'Zong ', 'Chuang ', 'Feng ', 'Zhu ', 'Pao ', 'Pi ', 'Gan ', 'Ke ', 'Ci ', 'Xie ', 'Qi ', 'Dan ', 'Zhen ', 'Fa ', 'Zhi ', 'Teng ', 'Ju ', 'Ji ', 'Fei ', 'Qu ', 'Dian ', 'Jia ', 'Xian ', 'Cha ', 'Bing ', 'Ni ', 'Zheng ', 'Yong ', 'Jing ', 'Quan ', 'Chong ', 'Tong ', 'Yi ', 'Kai ', 'Wei ', 'Hui ', 'Duo ', 'Yang ', 'Chi ', 'Zhi ', 'Hen ', 'Ya ', 'Mei ', 'Dou ', 'Jing ', 'Xiao ', 'Tong ', 'Tu ', 'Mang ', 'Pi ', 'Xiao ', 'Suan ', 'Pu ', 'Li ', 'Zhi ', 'Cuo ', 'Duo ', 'Wu ', 'Sha ', 'Lao ', 'Shou ', 'Huan ', 'Xian ', 'Yi ', 'Peng ', 'Zhang ', 'Guan ', 'Tan ', 'Fei ', 'Ma ', 'Lin ', 'Chi ', 'Ji ', 'Dian ', 'An ', 'Chi ', 'Bi ', 'Bei ', 'Min ', 'Gu ', 'Dui ', 'E ', 'Wei '];
<?php return ['Yu ', 'Cui ', 'Ya ', 'Zhu ', 'Cu ', 'Dan ', 'Shen ', 'Zhung ', 'Ji ', 'Yu ', 'Hou ', 'Feng ', 'La ', 'Yang ', 'Shen ', 'Tu ', 'Yu ', 'Gua ', 'Wen ', 'Huan ', 'Ku ', 'Jia ', 'Yin ', 'Yi ', 'Lu ', 'Sao ', 'Jue ', 'Chi ', 'Xi ', 'Guan ', 'Yi ', 'Wen ', 'Ji ', 'Chuang ', 'Ban ', 'Lei ', 'Liu ', 'Chai ', 'Shou ', 'Nue ', 'Dian ', 'Da ', 'Pie ', 'Tan ', 'Zhang ', 'Biao ', 'Shen ', 'Cu ', 'Luo ', 'Yi ', 'Zong ', 'Chou ', 'Zhang ', 'Zhai ', 'Sou ', 'Suo ', 'Que ', 'Diao ', 'Lou ', 'Lu ', 'Mo ', 'Jin ', 'Yin ', 'Ying ', 'Huang ', 'Fu ', 'Liao ', 'Long ', 'Qiao ', 'Liu ', 'Lao ', 'Xian ', 'Fei ', 'Dan ', 'Yin ', 'He ', 'Yan ', 'Ban ', 'Xian ', 'Guan ', 'Guai ', 'Nong ', 'Yu ', 'Wei ', 'Yi ', 'Yong ', 'Pi ', 'Lei ', 'Li ', 'Shu ', 'Dan ', 'Lin ', 'Dian ', 'Lin ', 'Lai ', 'Pie ', 'Ji ', 'Chi ', 'Yang ', 'Xian ', 'Jie ', 'Zheng ', '[?] ', 'Li ', 'Huo ', 'Lai ', 'Shaku ', 'Dian ', 'Xian ', 'Ying ', 'Yin ', 'Qu ', 'Yong ', 'Tan ', 'Dian ', 'Luo ', 'Luan ', 'Luan ', 'Bo ', '[?] ', 'Gui ', 'Po ', 'Fa ', 'Deng ', 'Fa ', 'Bai ', 'Bai ', 'Qie ', 'Bi ', 'Zao ', 'Zao ', 'Mao ', 'De ', 'Pa ', 'Jie ', 'Huang ', 'Gui ', 'Ci ', 'Ling ', 'Gao ', 'Mo ', 'Ji ', 'Jiao ', 'Peng ', 'Gao ', 'Ai ', 'E ', 'Hao ', 'Han ', 'Bi ', 'Wan ', 'Chou ', 'Qian ', 'Xi ', 'Ai ', 'Jiong ', 'Hao ', 'Huang ', 'Hao ', 'Ze ', 'Cui ', 'Hao ', 'Xiao ', 'Ye ', 'Po ', 'Hao ', 'Jiao ', 'Ai ', 'Xing ', 'Huang ', 'Li ', 'Piao ', 'He ', 'Jiao ', 'Pi ', 'Gan ', 'Pao ', 'Zhou ', 'Jun ', 'Qiu ', 'Cun ', 'Que ', 'Zha ', 'Gu ', 'Jun ', 'Jun ', 'Zhou ', 'Zha ', 'Gu ', 'Zhan ', 'Du ', 'Min ', 'Qi ', 'Ying ', 'Yu ', 'Bei ', 'Zhao ', 'Zhong ', 'Pen ', 'He ', 'Ying ', 'He ', 'Yi ', 'Bo ', 'Wan ', 'He ', 'Ang ', 'Zhan ', 'Yan ', 'Jian ', 'He ', 'Yu ', 'Kui ', 'Fan ', 'Gai ', 'Dao ', 'Pan ', 'Fu ', 'Qiu ', 'Sheng ', 'Dao ', 'Lu ', 'Zhan ', 'Meng ', 'Li ', 'Jin ', 'Xu ', 'Jian ', 'Pan ', 'Guan ', 'An ', 'Lu ', 'Shu ', 'Zhou ', 'Dang ', 'An ', 'Gu ', 'Li ', 'Mu ', 'Cheng ', 'Gan ', 'Xu ', 'Mang ', 'Mang ', 'Zhi ', 'Qi ', 'Ruan ', 'Tian ', 'Xiang ', 'Dun ', 'Xin ', 'Xi ', 'Pan ', 'Feng ', 'Dun ', 'Min '];
<?php return ['Ming ', 'Sheng ', 'Shi ', 'Yun ', 'Mian ', 'Pan ', 'Fang ', 'Miao ', 'Dan ', 'Mei ', 'Mao ', 'Kan ', 'Xian ', 'Ou ', 'Shi ', 'Yang ', 'Zheng ', 'Yao ', 'Shen ', 'Huo ', 'Da ', 'Zhen ', 'Kuang ', 'Ju ', 'Shen ', 'Chi ', 'Sheng ', 'Mei ', 'Mo ', 'Zhu ', 'Zhen ', 'Zhen ', 'Mian ', 'Di ', 'Yuan ', 'Die ', 'Yi ', 'Zi ', 'Zi ', 'Chao ', 'Zha ', 'Xuan ', 'Bing ', 'Mi ', 'Long ', 'Sui ', 'Dong ', 'Mi ', 'Die ', 'Yi ', 'Er ', 'Ming ', 'Xuan ', 'Chi ', 'Kuang ', 'Juan ', 'Mou ', 'Zhen ', 'Tiao ', 'Yang ', 'Yan ', 'Mo ', 'Zhong ', 'Mai ', 'Zhao ', 'Zheng ', 'Mei ', 'Jun ', 'Shao ', 'Han ', 'Huan ', 'Di ', 'Cheng ', 'Cuo ', 'Juan ', 'E ', 'Wan ', 'Xian ', 'Xi ', 'Kun ', 'Lai ', 'Jian ', 'Shan ', 'Tian ', 'Hun ', 'Wan ', 'Ling ', 'Shi ', 'Qiong ', 'Lie ', 'Yai ', 'Jing ', 'Zheng ', 'Li ', 'Lai ', 'Sui ', 'Juan ', 'Shui ', 'Sui ', 'Du ', 'Bi ', 'Bi ', 'Mu ', 'Hun ', 'Ni ', 'Lu ', 'Yi ', 'Jie ', 'Cai ', 'Zhou ', 'Yu ', 'Hun ', 'Ma ', 'Xia ', 'Xing ', 'Xi ', 'Gun ', 'Cai ', 'Chun ', 'Jian ', 'Mei ', 'Du ', 'Hou ', 'Xuan ', 'Ti ', 'Kui ', 'Gao ', 'Rui ', 'Mou ', 'Xu ', 'Fa ', 'Wen ', 'Miao ', 'Chou ', 'Kui ', 'Mi ', 'Weng ', 'Kou ', 'Dang ', 'Chen ', 'Ke ', 'Sou ', 'Xia ', 'Qiong ', 'Mao ', 'Ming ', 'Man ', 'Shui ', 'Ze ', 'Zhang ', 'Yi ', 'Diao ', 'Ou ', 'Mo ', 'Shun ', 'Cong ', 'Lou ', 'Chi ', 'Man ', 'Piao ', 'Cheng ', 'Ji ', 'Meng ', '[?] ', 'Run ', 'Pie ', 'Xi ', 'Qiao ', 'Pu ', 'Zhu ', 'Deng ', 'Shen ', 'Shun ', 'Liao ', 'Che ', 'Xian ', 'Kan ', 'Ye ', 'Xu ', 'Tong ', 'Mou ', 'Lin ', 'Kui ', 'Xian ', 'Ye ', 'Ai ', 'Hui ', 'Zhan ', 'Jian ', 'Gu ', 'Zhao ', 'Qu ', 'Wei ', 'Chou ', 'Sao ', 'Ning ', 'Xun ', 'Yao ', 'Huo ', 'Meng ', 'Mian ', 'Bin ', 'Mian ', 'Li ', 'Kuang ', 'Jue ', 'Xuan ', 'Mian ', 'Huo ', 'Lu ', 'Meng ', 'Long ', 'Guan ', 'Man ', 'Xi ', 'Chu ', 'Tang ', 'Kan ', 'Zhu ', 'Mao ', 'Jin ', 'Lin ', 'Yu ', 'Shuo ', 'Ce ', 'Jue ', 'Shi ', 'Yi ', 'Shen ', 'Zhi ', 'Hou ', 'Shen ', 'Ying ', 'Ju ', 'Zhou ', 'Jiao ', 'Cuo ', 'Duan ', 'Ai ', 'Jiao ', 'Zeng ', 'Huo ', 'Bai ', 'Shi ', 'Ding ', 'Qi ', 'Ji ', 'Zi ', 'Gan ', 'Wu ', 'Tuo ', 'Ku ', 'Qiang ', 'Xi ', 'Fan ', 'Kuang '];
<?php return ['Dang ', 'Ma ', 'Sha ', 'Dan ', 'Jue ', 'Li ', 'Fu ', 'Min ', 'Nuo ', 'Huo ', 'Kang ', 'Zhi ', 'Qi ', 'Kan ', 'Jie ', 'Fen ', 'E ', 'Ya ', 'Pi ', 'Zhe ', 'Yan ', 'Sui ', 'Zhuan ', 'Che ', 'Dun ', 'Pan ', 'Yan ', '[?] ', 'Feng ', 'Fa ', 'Mo ', 'Zha ', 'Qu ', 'Yu ', 'Luo ', 'Tuo ', 'Tuo ', 'Di ', 'Zhai ', 'Zhen ', 'Ai ', 'Fei ', 'Mu ', 'Zhu ', 'Li ', 'Bian ', 'Nu ', 'Ping ', 'Peng ', 'Ling ', 'Pao ', 'Le ', 'Po ', 'Bo ', 'Po ', 'Shen ', 'Za ', 'Nuo ', 'Li ', 'Long ', 'Tong ', '[?] ', 'Li ', 'Aragane ', 'Chu ', 'Keng ', 'Quan ', 'Zhu ', 'Kuang ', 'Huo ', 'E ', 'Nao ', 'Jia ', 'Lu ', 'Wei ', 'Ai ', 'Luo ', 'Ken ', 'Xing ', 'Yan ', 'Tong ', 'Peng ', 'Xi ', '[?] ', 'Hong ', 'Shuo ', 'Xia ', 'Qiao ', '[?] ', 'Wei ', 'Qiao ', '[?] ', 'Keng ', 'Xiao ', 'Que ', 'Chan ', 'Lang ', 'Hong ', 'Yu ', 'Xiao ', 'Xia ', 'Mang ', 'Long ', 'Iong ', 'Che ', 'Che ', 'E ', 'Liu ', 'Ying ', 'Mang ', 'Que ', 'Yan ', 'Sha ', 'Kun ', 'Yu ', '[?] ', 'Kaki ', 'Lu ', 'Chen ', 'Jian ', 'Nue ', 'Song ', 'Zhuo ', 'Keng ', 'Peng ', 'Yan ', 'Zhui ', 'Kong ', 'Ceng ', 'Qi ', 'Zong ', 'Qing ', 'Lin ', 'Jun ', 'Bo ', 'Ding ', 'Min ', 'Diao ', 'Jian ', 'He ', 'Lu ', 'Ai ', 'Sui ', 'Que ', 'Ling ', 'Bei ', 'Yin ', 'Dui ', 'Wu ', 'Qi ', 'Lun ', 'Wan ', 'Dian ', 'Gang ', 'Pei ', 'Qi ', 'Chen ', 'Ruan ', 'Yan ', 'Die ', 'Ding ', 'Du ', 'Tuo ', 'Jie ', 'Ying ', 'Bian ', 'Ke ', 'Bi ', 'Wei ', 'Shuo ', 'Zhen ', 'Duan ', 'Xia ', 'Dang ', 'Ti ', 'Nao ', 'Peng ', 'Jian ', 'Di ', 'Tan ', 'Cha ', 'Seki ', 'Qi ', '[?] ', 'Feng ', 'Xuan ', 'Que ', 'Que ', 'Ma ', 'Gong ', 'Nian ', 'Su ', 'E ', 'Ci ', 'Liu ', 'Si ', 'Tang ', 'Bang ', 'Hua ', 'Pi ', 'Wei ', 'Sang ', 'Lei ', 'Cuo ', 'Zhen ', 'Xia ', 'Qi ', 'Lian ', 'Pan ', 'Wei ', 'Yun ', 'Dui ', 'Zhe ', 'Ke ', 'La ', '[?] ', 'Qing ', 'Gun ', 'Zhuan ', 'Chan ', 'Qi ', 'Ao ', 'Peng ', 'Lu ', 'Lu ', 'Kan ', 'Qiang ', 'Chen ', 'Yin ', 'Lei ', 'Biao ', 'Qi ', 'Mo ', 'Qi ', 'Cui ', 'Zong ', 'Qing ', 'Chuo ', '[?] ', 'Ji ', 'Shan ', 'Lao ', 'Qu ', 'Zeng ', 'Deng ', 'Jian ', 'Xi ', 'Lin ', 'Ding ', 'Dian ', 'Huang ', 'Pan ', 'Za ', 'Qiao ', 'Di ', 'Li '];
<?php return ['Tani ', 'Jiao ', '[?] ', 'Zhang ', 'Qiao ', 'Dun ', 'Xian ', 'Yu ', 'Zhui ', 'He ', 'Huo ', 'Zhai ', 'Lei ', 'Ke ', 'Chu ', 'Ji ', 'Que ', 'Dang ', 'Yi ', 'Jiang ', 'Pi ', 'Pi ', 'Yu ', 'Pin ', 'Qi ', 'Ai ', 'Kai ', 'Jian ', 'Yu ', 'Ruan ', 'Meng ', 'Pao ', 'Ci ', '[?] ', '[?] ', 'Mie ', 'Ca ', 'Xian ', 'Kuang ', 'Lei ', 'Lei ', 'Zhi ', 'Li ', 'Li ', 'Fan ', 'Que ', 'Pao ', 'Ying ', 'Li ', 'Long ', 'Long ', 'Mo ', 'Bo ', 'Shuang ', 'Guan ', 'Lan ', 'Zan ', 'Yan ', 'Shi ', 'Shi ', 'Li ', 'Reng ', 'She ', 'Yue ', 'Si ', 'Qi ', 'Ta ', 'Ma ', 'Xie ', 'Xian ', 'Xian ', 'Zhi ', 'Qi ', 'Zhi ', 'Beng ', 'Dui ', 'Zhong ', '[?] ', 'Yi ', 'Shi ', 'You ', 'Zhi ', 'Tiao ', 'Fu ', 'Fu ', 'Mi ', 'Zu ', 'Zhi ', 'Suan ', 'Mei ', 'Zuo ', 'Qu ', 'Hu ', 'Zhu ', 'Shen ', 'Sui ', 'Ci ', 'Chai ', 'Mi ', 'Lu ', 'Yu ', 'Xiang ', 'Wu ', 'Tiao ', 'Piao ', 'Zhu ', 'Gui ', 'Xia ', 'Zhi ', 'Ji ', 'Gao ', 'Zhen ', 'Gao ', 'Shui ', 'Jin ', 'Chen ', 'Gai ', 'Kun ', 'Di ', 'Dao ', 'Huo ', 'Tao ', 'Qi ', 'Gu ', 'Guan ', 'Zui ', 'Ling ', 'Lu ', 'Bing ', 'Jin ', 'Dao ', 'Zhi ', 'Lu ', 'Shan ', 'Bei ', 'Zhe ', 'Hui ', 'You ', 'Xi ', 'Yin ', 'Zi ', 'Huo ', 'Zhen ', 'Fu ', 'Yuan ', 'Wu ', 'Xian ', 'Yang ', 'Ti ', 'Yi ', 'Mei ', 'Si ', 'Di ', '[?] ', 'Zhuo ', 'Zhen ', 'Yong ', 'Ji ', 'Gao ', 'Tang ', 'Si ', 'Ma ', 'Ta ', '[?] ', 'Xuan ', 'Qi ', 'Yu ', 'Xi ', 'Ji ', 'Si ', 'Chan ', 'Tan ', 'Kuai ', 'Sui ', 'Li ', 'Nong ', 'Ni ', 'Dao ', 'Li ', 'Rang ', 'Yue ', 'Ti ', 'Zan ', 'Lei ', 'Rou ', 'Yu ', 'Yu ', 'Chi ', 'Xie ', 'Qin ', 'He ', 'Tu ', 'Xiu ', 'Si ', 'Ren ', 'Tu ', 'Zi ', 'Cha ', 'Gan ', 'Yi ', 'Xian ', 'Bing ', 'Nian ', 'Qiu ', 'Qiu ', 'Chong ', 'Fen ', 'Hao ', 'Yun ', 'Ke ', 'Miao ', 'Zhi ', 'Geng ', 'Bi ', 'Zhi ', 'Yu ', 'Mi ', 'Ku ', 'Ban ', 'Pi ', 'Ni ', 'Li ', 'You ', 'Zu ', 'Pi ', 'Ba ', 'Ling ', 'Mo ', 'Cheng ', 'Nian ', 'Qin ', 'Yang ', 'Zuo ', 'Zhi ', 'Zhi ', 'Shu ', 'Ju ', 'Zi ', 'Huo ', 'Ji ', 'Cheng ', 'Tong ', 'Zhi ', 'Huo ', 'He ', 'Yin ', 'Zi ', 'Zhi ', 'Jie ', 'Ren ', 'Du ', 'Yi ', 'Zhu ', 'Hui ', 'Nong ', 'Fu '];
<?php return ['Xi ', 'Kao ', 'Lang ', 'Fu ', 'Ze ', 'Shui ', 'Lu ', 'Kun ', 'Gan ', 'Geng ', 'Ti ', 'Cheng ', 'Tu ', 'Shao ', 'Shui ', 'Ya ', 'Lun ', 'Lu ', 'Gu ', 'Zuo ', 'Ren ', 'Zhun ', 'Bang ', 'Bai ', 'Ji ', 'Zhi ', 'Zhi ', 'Kun ', 'Leng ', 'Peng ', 'Ke ', 'Bing ', 'Chou ', 'Zu ', 'Yu ', 'Su ', 'Lue ', '[?] ', 'Yi ', 'Xi ', 'Bian ', 'Ji ', 'Fu ', 'Bi ', 'Nuo ', 'Jie ', 'Zhong ', 'Zong ', 'Xu ', 'Cheng ', 'Dao ', 'Wen ', 'Lian ', 'Zi ', 'Yu ', 'Ji ', 'Xu ', 'Zhen ', 'Zhi ', 'Dao ', 'Jia ', 'Ji ', 'Gao ', 'Gao ', 'Gu ', 'Rong ', 'Sui ', 'You ', 'Ji ', 'Kang ', 'Mu ', 'Shan ', 'Men ', 'Zhi ', 'Ji ', 'Lu ', 'Su ', 'Ji ', 'Ying ', 'Wen ', 'Qiu ', 'Se ', '[?] ', 'Yi ', 'Huang ', 'Qie ', 'Ji ', 'Sui ', 'Xiao ', 'Pu ', 'Jiao ', 'Zhuo ', 'Tong ', 'Sai ', 'Lu ', 'Sui ', 'Nong ', 'Se ', 'Hui ', 'Rang ', 'Nuo ', 'Yu ', 'Bin ', 'Ji ', 'Tui ', 'Wen ', 'Cheng ', 'Huo ', 'Gong ', 'Lu ', 'Biao ', '[?] ', 'Rang ', 'Zhuo ', 'Li ', 'Zan ', 'Xue ', 'Wa ', 'Jiu ', 'Qiong ', 'Xi ', 'Qiong ', 'Kong ', 'Yu ', 'Sen ', 'Jing ', 'Yao ', 'Chuan ', 'Zhun ', 'Tu ', 'Lao ', 'Qie ', 'Zhai ', 'Yao ', 'Bian ', 'Bao ', 'Yao ', 'Bing ', 'Wa ', 'Zhu ', 'Jiao ', 'Qiao ', 'Diao ', 'Wu ', 'Gui ', 'Yao ', 'Zhi ', 'Chuang ', 'Yao ', 'Tiao ', 'Jiao ', 'Chuang ', 'Jiong ', 'Xiao ', 'Cheng ', 'Kou ', 'Cuan ', 'Wo ', 'Dan ', 'Ku ', 'Ke ', 'Zhui ', 'Xu ', 'Su ', 'Guan ', 'Kui ', 'Dou ', '[?] ', 'Yin ', 'Wo ', 'Wa ', 'Ya ', 'Yu ', 'Ju ', 'Qiong ', 'Yao ', 'Yao ', 'Tiao ', 'Chao ', 'Yu ', 'Tian ', 'Diao ', 'Ju ', 'Liao ', 'Xi ', 'Wu ', 'Kui ', 'Chuang ', 'Zhao ', '[?] ', 'Kuan ', 'Long ', 'Cheng ', 'Cui ', 'Piao ', 'Zao ', 'Cuan ', 'Qiao ', 'Qiong ', 'Dou ', 'Zao ', 'Long ', 'Qie ', 'Li ', 'Chu ', 'Shi ', 'Fou ', 'Qian ', 'Chu ', 'Hong ', 'Qi ', 'Qian ', 'Gong ', 'Shi ', 'Shu ', 'Miao ', 'Ju ', 'Zhan ', 'Zhu ', 'Ling ', 'Long ', 'Bing ', 'Jing ', 'Jing ', 'Zhang ', 'Yi ', 'Si ', 'Jun ', 'Hong ', 'Tong ', 'Song ', 'Jing ', 'Diao ', 'Yi ', 'Shu ', 'Jing ', 'Qu ', 'Jie ', 'Ping ', 'Duan ', 'Shao ', 'Zhuan ', 'Ceng ', 'Deng ', 'Cui ', 'Huai ', 'Jing ', 'Kan ', 'Jing ', 'Zhu ', 'Zhu ', 'Le ', 'Peng ', 'Yu ', 'Chi ', 'Gan '];
<?php return ['Mang ', 'Zhu ', 'Utsubo ', 'Du ', 'Ji ', 'Xiao ', 'Ba ', 'Suan ', 'Ji ', 'Zhen ', 'Zhao ', 'Sun ', 'Ya ', 'Zhui ', 'Yuan ', 'Hu ', 'Gang ', 'Xiao ', 'Cen ', 'Pi ', 'Bi ', 'Jian ', 'Yi ', 'Dong ', 'Shan ', 'Sheng ', 'Xia ', 'Di ', 'Zhu ', 'Na ', 'Chi ', 'Gu ', 'Li ', 'Qie ', 'Min ', 'Bao ', 'Tiao ', 'Si ', 'Fu ', 'Ce ', 'Ben ', 'Pei ', 'Da ', 'Zi ', 'Di ', 'Ling ', 'Ze ', 'Nu ', 'Fu ', 'Gou ', 'Fan ', 'Jia ', 'Ge ', 'Fan ', 'Shi ', 'Mao ', 'Po ', 'Sey ', 'Jian ', 'Qiong ', 'Long ', 'Souke ', 'Bian ', 'Luo ', 'Gui ', 'Qu ', 'Chi ', 'Yin ', 'Yao ', 'Xian ', 'Bi ', 'Qiong ', 'Gua ', 'Deng ', 'Jiao ', 'Jin ', 'Quan ', 'Sun ', 'Ru ', 'Fa ', 'Kuang ', 'Zhu ', 'Tong ', 'Ji ', 'Da ', 'Xing ', 'Ce ', 'Zhong ', 'Kou ', 'Lai ', 'Bi ', 'Shai ', 'Dang ', 'Zheng ', 'Ce ', 'Fu ', 'Yun ', 'Tu ', 'Pa ', 'Li ', 'Lang ', 'Ju ', 'Guan ', 'Jian ', 'Han ', 'Tong ', 'Xia ', 'Zhi ', 'Cheng ', 'Suan ', 'Shi ', 'Zhu ', 'Zuo ', 'Xiao ', 'Shao ', 'Ting ', 'Ce ', 'Yan ', 'Gao ', 'Kuai ', 'Gan ', 'Chou ', 'Kago ', 'Gang ', 'Yun ', 'O ', 'Qian ', 'Xiao ', 'Jian ', 'Pu ', 'Lai ', 'Zou ', 'Bi ', 'Bi ', 'Bi ', 'Ge ', 'Chi ', 'Guai ', 'Yu ', 'Jian ', 'Zhao ', 'Gu ', 'Chi ', 'Zheng ', 'Jing ', 'Sha ', 'Zhou ', 'Lu ', 'Bo ', 'Ji ', 'Lin ', 'Suan ', 'Jun ', 'Fu ', 'Zha ', 'Gu ', 'Kong ', 'Qian ', 'Quan ', 'Jun ', 'Chui ', 'Guan ', 'Yuan ', 'Ce ', 'Ju ', 'Bo ', 'Ze ', 'Qie ', 'Tuo ', 'Luo ', 'Dan ', 'Xiao ', 'Ruo ', 'Jian ', 'Xuan ', 'Bian ', 'Sun ', 'Xiang ', 'Xian ', 'Ping ', 'Zhen ', 'Sheng ', 'Hu ', 'Shi ', 'Zhu ', 'Yue ', 'Chun ', 'Lu ', 'Wu ', 'Dong ', 'Xiao ', 'Ji ', 'Jie ', 'Huang ', 'Xing ', 'Mei ', 'Fan ', 'Chui ', 'Zhuan ', 'Pian ', 'Feng ', 'Zhu ', 'Hong ', 'Qie ', 'Hou ', 'Qiu ', 'Miao ', 'Qian ', '[?] ', 'Kui ', 'Sik ', 'Lou ', 'Yun ', 'He ', 'Tang ', 'Yue ', 'Chou ', 'Gao ', 'Fei ', 'Ruo ', 'Zheng ', 'Gou ', 'Nie ', 'Qian ', 'Xiao ', 'Cuan ', 'Gong ', 'Pang ', 'Du ', 'Li ', 'Bi ', 'Zhuo ', 'Chu ', 'Shai ', 'Chi ', 'Zhu ', 'Qiang ', 'Long ', 'Lan ', 'Jian ', 'Bu ', 'Li ', 'Hui ', 'Bi ', 'Di ', 'Cong ', 'Yan ', 'Peng ', 'Sen ', 'Zhuan ', 'Pai ', 'Piao ', 'Dou ', 'Yu ', 'Mie ', 'Zhuan '];
<?php return ['Ze ', 'Xi ', 'Guo ', 'Yi ', 'Hu ', 'Chan ', 'Kou ', 'Cu ', 'Ping ', 'Chou ', 'Ji ', 'Gui ', 'Su ', 'Lou ', 'Zha ', 'Lu ', 'Nian ', 'Suo ', 'Cuan ', 'Sasara ', 'Suo ', 'Le ', 'Duan ', 'Yana ', 'Xiao ', 'Bo ', 'Mi ', 'Si ', 'Dang ', 'Liao ', 'Dan ', 'Dian ', 'Fu ', 'Jian ', 'Min ', 'Kui ', 'Dai ', 'Qiao ', 'Deng ', 'Huang ', 'Sun ', 'Lao ', 'Zan ', 'Xiao ', 'Du ', 'Shi ', 'Zan ', '[?] ', 'Pai ', 'Hata ', 'Pai ', 'Gan ', 'Ju ', 'Du ', 'Lu ', 'Yan ', 'Bo ', 'Dang ', 'Sai ', 'Ke ', 'Long ', 'Qian ', 'Lian ', 'Bo ', 'Zhou ', 'Lai ', '[?] ', 'Lan ', 'Kui ', 'Yu ', 'Yue ', 'Hao ', 'Zhen ', 'Tai ', 'Ti ', 'Mi ', 'Chou ', 'Ji ', '[?] ', 'Hata ', 'Teng ', 'Zhuan ', 'Zhou ', 'Fan ', 'Sou ', 'Zhou ', 'Kuji ', 'Zhuo ', 'Teng ', 'Lu ', 'Lu ', 'Jian ', 'Tuo ', 'Ying ', 'Yu ', 'Lai ', 'Long ', 'Shinshi ', 'Lian ', 'Lan ', 'Qian ', 'Yue ', 'Zhong ', 'Qu ', 'Lian ', 'Bian ', 'Duan ', 'Zuan ', 'Li ', 'Si ', 'Luo ', 'Ying ', 'Yue ', 'Zhuo ', 'Xu ', 'Mi ', 'Di ', 'Fan ', 'Shen ', 'Zhe ', 'Shen ', 'Nu ', 'Xie ', 'Lei ', 'Xian ', 'Zi ', 'Ni ', 'Cun ', '[?] ', 'Qian ', 'Kume ', 'Bi ', 'Ban ', 'Wu ', 'Sha ', 'Kang ', 'Rou ', 'Fen ', 'Bi ', 'Cui ', '[?] ', 'Li ', 'Chi ', 'Nukamiso ', 'Ro ', 'Ba ', 'Li ', 'Gan ', 'Ju ', 'Po ', 'Mo ', 'Cu ', 'Nian ', 'Zhou ', 'Li ', 'Su ', 'Tiao ', 'Li ', 'Qi ', 'Su ', 'Hong ', 'Tong ', 'Zi ', 'Ce ', 'Yue ', 'Zhou ', 'Lin ', 'Zhuang ', 'Bai ', '[?] ', 'Fen ', 'Ji ', '[?] ', 'Sukumo ', 'Liang ', 'Xian ', 'Fu ', 'Liang ', 'Can ', 'Geng ', 'Li ', 'Yue ', 'Lu ', 'Ju ', 'Qi ', 'Cui ', 'Bai ', 'Zhang ', 'Lin ', 'Zong ', 'Jing ', 'Guo ', 'Kouji ', 'San ', 'San ', 'Tang ', 'Bian ', 'Rou ', 'Mian ', 'Hou ', 'Xu ', 'Zong ', 'Hu ', 'Jian ', 'Zan ', 'Ci ', 'Li ', 'Xie ', 'Fu ', 'Ni ', 'Bei ', 'Gu ', 'Xiu ', 'Gao ', 'Tang ', 'Qiu ', 'Sukumo ', 'Cao ', 'Zhuang ', 'Tang ', 'Mi ', 'San ', 'Fen ', 'Zao ', 'Kang ', 'Jiang ', 'Mo ', 'San ', 'San ', 'Nuo ', 'Xi ', 'Liang ', 'Jiang ', 'Kuai ', 'Bo ', 'Huan ', '[?] ', 'Zong ', 'Xian ', 'Nuo ', 'Tuan ', 'Nie ', 'Li ', 'Zuo ', 'Di ', 'Nie ', 'Tiao ', 'Lan ', 'Mi ', 'Jiao ', 'Jiu ', 'Xi ', 'Gong ', 'Zheng ', 'Jiu ', 'You '];
<?php return ['Ji ', 'Cha ', 'Zhou ', 'Xun ', 'Yue ', 'Hong ', 'Yu ', 'He ', 'Wan ', 'Ren ', 'Wen ', 'Wen ', 'Qiu ', 'Na ', 'Zi ', 'Tou ', 'Niu ', 'Fou ', 'Jie ', 'Shu ', 'Chun ', 'Pi ', 'Yin ', 'Sha ', 'Hong ', 'Zhi ', 'Ji ', 'Fen ', 'Yun ', 'Ren ', 'Dan ', 'Jin ', 'Su ', 'Fang ', 'Suo ', 'Cui ', 'Jiu ', 'Zha ', 'Kinu ', 'Jin ', 'Fu ', 'Zhi ', 'Ci ', 'Zi ', 'Chou ', 'Hong ', 'Zha ', 'Lei ', 'Xi ', 'Fu ', 'Xie ', 'Shen ', 'Bei ', 'Zhu ', 'Qu ', 'Ling ', 'Zhu ', 'Shao ', 'Gan ', 'Yang ', 'Fu ', 'Tuo ', 'Zhen ', 'Dai ', 'Zhuo ', 'Shi ', 'Zhong ', 'Xian ', 'Zu ', 'Jiong ', 'Ban ', 'Ju ', 'Mo ', 'Shu ', 'Zui ', 'Wata ', 'Jing ', 'Ren ', 'Heng ', 'Xie ', 'Jie ', 'Zhu ', 'Chou ', 'Gua ', 'Bai ', 'Jue ', 'Kuang ', 'Hu ', 'Ci ', 'Geng ', 'Geng ', 'Tao ', 'Xie ', 'Ku ', 'Jiao ', 'Quan ', 'Gai ', 'Luo ', 'Xuan ', 'Bing ', 'Xian ', 'Fu ', 'Gei ', 'Tong ', 'Rong ', 'Tiao ', 'Yin ', 'Lei ', 'Xie ', 'Quan ', 'Xu ', 'Lun ', 'Die ', 'Tong ', 'Si ', 'Jiang ', 'Xiang ', 'Hui ', 'Jue ', 'Zhi ', 'Jian ', 'Juan ', 'Chi ', 'Mian ', 'Zhen ', 'Lu ', 'Cheng ', 'Qiu ', 'Shu ', 'Bang ', 'Tong ', 'Xiao ', 'Wan ', 'Qin ', 'Geng ', 'Xiu ', 'Ti ', 'Xiu ', 'Xie ', 'Hong ', 'Xi ', 'Fu ', 'Ting ', 'Sui ', 'Dui ', 'Kun ', 'Fu ', 'Jing ', 'Hu ', 'Zhi ', 'Yan ', 'Jiong ', 'Feng ', 'Ji ', 'Sok ', 'Kase ', 'Zong ', 'Lin ', 'Duo ', 'Li ', 'Lu ', 'Liang ', 'Chou ', 'Quan ', 'Shao ', 'Qi ', 'Qi ', 'Zhun ', 'Qi ', 'Wan ', 'Qian ', 'Xian ', 'Shou ', 'Wei ', 'Qi ', 'Tao ', 'Wan ', 'Gang ', 'Wang ', 'Beng ', 'Zhui ', 'Cai ', 'Guo ', 'Cui ', 'Lun ', 'Liu ', 'Qi ', 'Zhan ', 'Bei ', 'Chuo ', 'Ling ', 'Mian ', 'Qi ', 'Qie ', 'Tan ', 'Zong ', 'Gun ', 'Zou ', 'Yi ', 'Zi ', 'Xing ', 'Liang ', 'Jin ', 'Fei ', 'Rui ', 'Min ', 'Yu ', 'Zong ', 'Fan ', 'Lu ', 'Xu ', 'Yingl ', 'Zhang ', 'Kasuri ', 'Xu ', 'Xiang ', 'Jian ', 'Ke ', 'Xian ', 'Ruan ', 'Mian ', 'Qi ', 'Duan ', 'Zhong ', 'Di ', 'Min ', 'Miao ', 'Yuan ', 'Xie ', 'Bao ', 'Si ', 'Qiu ', 'Bian ', 'Huan ', 'Geng ', 'Cong ', 'Mian ', 'Wei ', 'Fu ', 'Wei ', 'Yu ', 'Gou ', 'Miao ', 'Xie ', 'Lian ', 'Zong ', 'Bian ', 'Yun ', 'Yin ', 'Ti ', 'Gua ', 'Zhi ', 'Yun ', 'Cheng ', 'Chan ', 'Dai '];
<?php return ['Xia ', 'Yuan ', 'Zong ', 'Xu ', 'Nawa ', 'Odoshi ', 'Geng ', 'Sen ', 'Ying ', 'Jin ', 'Yi ', 'Zhui ', 'Ni ', 'Bang ', 'Gu ', 'Pan ', 'Zhou ', 'Jian ', 'Cuo ', 'Quan ', 'Shuang ', 'Yun ', 'Xia ', 'Shuai ', 'Xi ', 'Rong ', 'Tao ', 'Fu ', 'Yun ', 'Zhen ', 'Gao ', 'Ru ', 'Hu ', 'Zai ', 'Teng ', 'Xian ', 'Su ', 'Zhen ', 'Zong ', 'Tao ', 'Horo ', 'Cai ', 'Bi ', 'Feng ', 'Cu ', 'Li ', 'Suo ', 'Yin ', 'Xi ', 'Zong ', 'Lei ', 'Zhuan ', 'Qian ', 'Man ', 'Zhi ', 'Lu ', 'Mo ', 'Piao ', 'Lian ', 'Mi ', 'Xuan ', 'Zong ', 'Ji ', 'Shan ', 'Sui ', 'Fan ', 'Shuai ', 'Beng ', 'Yi ', 'Sao ', 'Mou ', 'Zhou ', 'Qiang ', 'Hun ', 'Sem ', 'Xi ', 'Jung ', 'Xiu ', 'Ran ', 'Xuan ', 'Hui ', 'Qiao ', 'Zeng ', 'Zuo ', 'Zhi ', 'Shan ', 'San ', 'Lin ', 'Yu ', 'Fan ', 'Liao ', 'Chuo ', 'Zun ', 'Jian ', 'Rao ', 'Chan ', 'Rui ', 'Xiu ', 'Hui ', 'Hua ', 'Zuan ', 'Xi ', 'Qiang ', 'Un ', 'Da ', 'Sheng ', 'Hui ', 'Xi ', 'Se ', 'Jian ', 'Jiang ', 'Huan ', 'Zao ', 'Cong ', 'Jie ', 'Jiao ', 'Bo ', 'Chan ', 'Yi ', 'Nao ', 'Sui ', 'Yi ', 'Shai ', 'Xu ', 'Ji ', 'Bin ', 'Qian ', 'Lan ', 'Pu ', 'Xun ', 'Zuan ', 'Qi ', 'Peng ', 'Li ', 'Mo ', 'Lei ', 'Xie ', 'Zuan ', 'Kuang ', 'You ', 'Xu ', 'Lei ', 'Xian ', 'Chan ', 'Kou ', 'Lu ', 'Chan ', 'Ying ', 'Cai ', 'Xiang ', 'Xian ', 'Zui ', 'Zuan ', 'Luo ', 'Xi ', 'Dao ', 'Lan ', 'Lei ', 'Lian ', 'Si ', 'Jiu ', 'Yu ', 'Hong ', 'Zhou ', 'Xian ', 'He ', 'Yue ', 'Ji ', 'Wan ', 'Kuang ', 'Ji ', 'Ren ', 'Wei ', 'Yun ', 'Hong ', 'Chun ', 'Pi ', 'Sha ', 'Gang ', 'Na ', 'Ren ', 'Zong ', 'Lun ', 'Fen ', 'Zhi ', 'Wen ', 'Fang ', 'Zhu ', 'Yin ', 'Niu ', 'Shu ', 'Xian ', 'Gan ', 'Xie ', 'Fu ', 'Lian ', 'Zu ', 'Shen ', 'Xi ', 'Zhi ', 'Zhong ', 'Zhou ', 'Ban ', 'Fu ', 'Zhuo ', 'Shao ', 'Yi ', 'Jing ', 'Dai ', 'Bang ', 'Rong ', 'Jie ', 'Ku ', 'Rao ', 'Die ', 'Heng ', 'Hui ', 'Gei ', 'Xuan ', 'Jiang ', 'Luo ', 'Jue ', 'Jiao ', 'Tong ', 'Geng ', 'Xiao ', 'Juan ', 'Xiu ', 'Xi ', 'Sui ', 'Tao ', 'Ji ', 'Ti ', 'Ji ', 'Xu ', 'Ling ', '[?] ', 'Xu ', 'Qi ', 'Fei ', 'Chuo ', 'Zhang ', 'Gun ', 'Sheng ', 'Wei ', 'Mian ', 'Shou ', 'Beng ', 'Chou ', 'Tao ', 'Liu ', 'Quan ', 'Zong ', 'Zhan ', 'Wan ', 'Lu '];
<?php return ['Zhui ', 'Zi ', 'Ke ', 'Xiang ', 'Jian ', 'Mian ', 'Lan ', 'Ti ', 'Miao ', 'Qi ', 'Yun ', 'Hui ', 'Si ', 'Duo ', 'Duan ', 'Bian ', 'Xian ', 'Gou ', 'Zhui ', 'Huan ', 'Di ', 'Lu ', 'Bian ', 'Min ', 'Yuan ', 'Jin ', 'Fu ', 'Ru ', 'Zhen ', 'Feng ', 'Shuai ', 'Gao ', 'Chan ', 'Li ', 'Yi ', 'Jian ', 'Bin ', 'Piao ', 'Man ', 'Lei ', 'Ying ', 'Suo ', 'Mou ', 'Sao ', 'Xie ', 'Liao ', 'Shan ', 'Zeng ', 'Jiang ', 'Qian ', 'Zao ', 'Huan ', 'Jiao ', 'Zuan ', 'Fou ', 'Xie ', 'Gang ', 'Fou ', 'Que ', 'Fou ', 'Kaakeru ', 'Bo ', 'Ping ', 'Hou ', '[?] ', 'Gang ', 'Ying ', 'Ying ', 'Qing ', 'Xia ', 'Guan ', 'Zun ', 'Tan ', 'Chang ', 'Qi ', 'Weng ', 'Ying ', 'Lei ', 'Tan ', 'Lu ', 'Guan ', 'Wang ', 'Wang ', 'Gang ', 'Wang ', 'Han ', '[?] ', 'Luo ', 'Fu ', 'Mi ', 'Fa ', 'Gu ', 'Zhu ', 'Ju ', 'Mao ', 'Gu ', 'Min ', 'Gang ', 'Ba ', 'Gua ', 'Ti ', 'Juan ', 'Fu ', 'Lin ', 'Yan ', 'Zhao ', 'Zui ', 'Gua ', 'Zhuo ', 'Yu ', 'Zhi ', 'An ', 'Fa ', 'Nan ', 'Shu ', 'Si ', 'Pi ', 'Ma ', 'Liu ', 'Ba ', 'Fa ', 'Li ', 'Chao ', 'Wei ', 'Bi ', 'Ji ', 'Zeng ', 'Tong ', 'Liu ', 'Ji ', 'Juan ', 'Mi ', 'Zhao ', 'Luo ', 'Pi ', 'Ji ', 'Ji ', 'Luan ', 'Yang ', 'Mie ', 'Qiang ', 'Ta ', 'Mei ', 'Yang ', 'You ', 'You ', 'Fen ', 'Ba ', 'Gao ', 'Yang ', 'Gu ', 'Qiang ', 'Zang ', 'Gao ', 'Ling ', 'Yi ', 'Zhu ', 'Di ', 'Xiu ', 'Qian ', 'Yi ', 'Xian ', 'Rong ', 'Qun ', 'Qun ', 'Qian ', 'Huan ', 'Zui ', 'Xian ', 'Yi ', 'Yashinau ', 'Qiang ', 'Xian ', 'Yu ', 'Geng ', 'Jie ', 'Tang ', 'Yuan ', 'Xi ', 'Fan ', 'Shan ', 'Fen ', 'Shan ', 'Lian ', 'Lei ', 'Geng ', 'Nou ', 'Qiang ', 'Chan ', 'Yu ', 'Gong ', 'Yi ', 'Chong ', 'Weng ', 'Fen ', 'Hong ', 'Chi ', 'Chi ', 'Cui ', 'Fu ', 'Xia ', 'Pen ', 'Yi ', 'La ', 'Yi ', 'Pi ', 'Ling ', 'Liu ', 'Zhi ', 'Qu ', 'Xi ', 'Xie ', 'Xiang ', 'Xi ', 'Xi ', 'Qi ', 'Qiao ', 'Hui ', 'Hui ', 'Xiao ', 'Se ', 'Hong ', 'Jiang ', 'Di ', 'Cui ', 'Fei ', 'Tao ', 'Sha ', 'Chi ', 'Zhu ', 'Jian ', 'Xuan ', 'Shi ', 'Pian ', 'Zong ', 'Wan ', 'Hui ', 'Hou ', 'He ', 'He ', 'Han ', 'Ao ', 'Piao ', 'Yi ', 'Lian ', 'Qu ', '[?] ', 'Lin ', 'Pen ', 'Qiao ', 'Ao ', 'Fan ', 'Yi ', 'Hui ', 'Xuan ', 'Dao '];
<?php return ['Yao ', 'Lao ', '[?] ', 'Kao ', 'Mao ', 'Zhe ', 'Qi ', 'Gou ', 'Gou ', 'Gou ', 'Die ', 'Die ', 'Er ', 'Shua ', 'Ruan ', 'Er ', 'Nai ', 'Zhuan ', 'Lei ', 'Ting ', 'Zi ', 'Geng ', 'Chao ', 'Hao ', 'Yun ', 'Pa ', 'Pi ', 'Chi ', 'Si ', 'Chu ', 'Jia ', 'Ju ', 'He ', 'Chu ', 'Lao ', 'Lun ', 'Ji ', 'Tang ', 'Ou ', 'Lou ', 'Nou ', 'Gou ', 'Pang ', 'Ze ', 'Lou ', 'Ji ', 'Lao ', 'Huo ', 'You ', 'Mo ', 'Huai ', 'Er ', 'Zhe ', 'Ting ', 'Ye ', 'Da ', 'Song ', 'Qin ', 'Yun ', 'Chi ', 'Dan ', 'Dan ', 'Hong ', 'Geng ', 'Zhi ', '[?] ', 'Nie ', 'Dan ', 'Zhen ', 'Che ', 'Ling ', 'Zheng ', 'You ', 'Wa ', 'Liao ', 'Long ', 'Zhi ', 'Ning ', 'Tiao ', 'Er ', 'Ya ', 'Die ', 'Gua ', '[?] ', 'Lian ', 'Hao ', 'Sheng ', 'Lie ', 'Pin ', 'Jing ', 'Ju ', 'Bi ', 'Di ', 'Guo ', 'Wen ', 'Xu ', 'Ping ', 'Cong ', 'Shikato ', '[?] ', 'Ting ', 'Yu ', 'Cong ', 'Kui ', 'Tsuraneru ', 'Kui ', 'Cong ', 'Lian ', 'Weng ', 'Kui ', 'Lian ', 'Lian ', 'Cong ', 'Ao ', 'Sheng ', 'Song ', 'Ting ', 'Kui ', 'Nie ', 'Zhi ', 'Dan ', 'Ning ', 'Qie ', 'Ji ', 'Ting ', 'Ting ', 'Long ', 'Yu ', 'Yu ', 'Zhao ', 'Si ', 'Su ', 'Yi ', 'Su ', 'Si ', 'Zhao ', 'Zhao ', 'Rou ', 'Yi ', 'Le ', 'Ji ', 'Qiu ', 'Ken ', 'Cao ', 'Ge ', 'Di ', 'Huan ', 'Huang ', 'Yi ', 'Ren ', 'Xiao ', 'Ru ', 'Zhou ', 'Yuan ', 'Du ', 'Gang ', 'Rong ', 'Gan ', 'Cha ', 'Wo ', 'Chang ', 'Gu ', 'Zhi ', 'Han ', 'Fu ', 'Fei ', 'Fen ', 'Pei ', 'Pang ', 'Jian ', 'Fang ', 'Zhun ', 'You ', 'Na ', 'Hang ', 'Ken ', 'Ran ', 'Gong ', 'Yu ', 'Wen ', 'Yao ', 'Jin ', 'Pi ', 'Qian ', 'Xi ', 'Xi ', 'Fei ', 'Ken ', 'Jing ', 'Tai ', 'Shen ', 'Zhong ', 'Zhang ', 'Xie ', 'Shen ', 'Wei ', 'Zhou ', 'Die ', 'Dan ', 'Fei ', 'Ba ', 'Bo ', 'Qu ', 'Tian ', 'Bei ', 'Gua ', 'Tai ', 'Zi ', 'Ku ', 'Zhi ', 'Ni ', 'Ping ', 'Zi ', 'Fu ', 'Pang ', 'Zhen ', 'Xian ', 'Zuo ', 'Pei ', 'Jia ', 'Sheng ', 'Zhi ', 'Bao ', 'Mu ', 'Qu ', 'Hu ', 'Ke ', 'Yi ', 'Yin ', 'Xu ', 'Yang ', 'Long ', 'Dong ', 'Ka ', 'Lu ', 'Jing ', 'Nu ', 'Yan ', 'Pang ', 'Kua ', 'Yi ', 'Guang ', 'Gai ', 'Ge ', 'Dong ', 'Zhi ', 'Xiao ', 'Xiong ', 'Xiong ', 'Er ', 'E ', 'Xing ', 'Pian ', 'Neng ', 'Zi ', 'Gui '];
<?php return ['Cheng ', 'Tiao ', 'Zhi ', 'Cui ', 'Mei ', 'Xie ', 'Cui ', 'Xie ', 'Mo ', 'Mai ', 'Ji ', 'Obiyaakasu ', '[?] ', 'Kuai ', 'Sa ', 'Zang ', 'Qi ', 'Nao ', 'Mi ', 'Nong ', 'Luan ', 'Wan ', 'Bo ', 'Wen ', 'Guan ', 'Qiu ', 'Jiao ', 'Jing ', 'Rou ', 'Heng ', 'Cuo ', 'Lie ', 'Shan ', 'Ting ', 'Mei ', 'Chun ', 'Shen ', 'Xie ', 'De ', 'Zui ', 'Cu ', 'Xiu ', 'Xin ', 'Tuo ', 'Pao ', 'Cheng ', 'Nei ', 'Fu ', 'Dou ', 'Tuo ', 'Niao ', 'Noy ', 'Pi ', 'Gu ', 'Gua ', 'Li ', 'Lian ', 'Zhang ', 'Cui ', 'Jie ', 'Liang ', 'Zhou ', 'Pi ', 'Biao ', 'Lun ', 'Pian ', 'Guo ', 'Kui ', 'Chui ', 'Dan ', 'Tian ', 'Nei ', 'Jing ', 'Jie ', 'La ', 'Yi ', 'An ', 'Ren ', 'Shen ', 'Chuo ', 'Fu ', 'Fu ', 'Ju ', 'Fei ', 'Qiang ', 'Wan ', 'Dong ', 'Pi ', 'Guo ', 'Zong ', 'Ding ', 'Wu ', 'Mei ', 'Ruan ', 'Zhuan ', 'Zhi ', 'Cou ', 'Gua ', 'Ou ', 'Di ', 'An ', 'Xing ', 'Nao ', 'Yu ', 'Chuan ', 'Nan ', 'Yun ', 'Zhong ', 'Rou ', 'E ', 'Sai ', 'Tu ', 'Yao ', 'Jian ', 'Wei ', 'Jiao ', 'Yu ', 'Jia ', 'Duan ', 'Bi ', 'Chang ', 'Fu ', 'Xian ', 'Ni ', 'Mian ', 'Wa ', 'Teng ', 'Tui ', 'Bang ', 'Qian ', 'Lu ', 'Wa ', 'Sou ', 'Tang ', 'Su ', 'Zhui ', 'Ge ', 'Yi ', 'Bo ', 'Liao ', 'Ji ', 'Pi ', 'Xie ', 'Gao ', 'Lu ', 'Bin ', 'Ou ', 'Chang ', 'Lu ', 'Guo ', 'Pang ', 'Chuai ', 'Piao ', 'Jiang ', 'Fu ', 'Tang ', 'Mo ', 'Xi ', 'Zhuan ', 'Lu ', 'Jiao ', 'Ying ', 'Lu ', 'Zhi ', 'Tara ', 'Chun ', 'Lian ', 'Tong ', 'Peng ', 'Ni ', 'Zha ', 'Liao ', 'Cui ', 'Gui ', 'Xiao ', 'Teng ', 'Fan ', 'Zhi ', 'Jiao ', 'Shan ', 'Wu ', 'Cui ', 'Run ', 'Xiang ', 'Sui ', 'Fen ', 'Ying ', 'Tan ', 'Zhua ', 'Dan ', 'Kuai ', 'Nong ', 'Tun ', 'Lian ', 'Bi ', 'Yong ', 'Jue ', 'Chu ', 'Yi ', 'Juan ', 'La ', 'Lian ', 'Sao ', 'Tun ', 'Gu ', 'Qi ', 'Cui ', 'Bin ', 'Xun ', 'Ru ', 'Huo ', 'Zang ', 'Xian ', 'Biao ', 'Xing ', 'Kuan ', 'La ', 'Yan ', 'Lu ', 'Huo ', 'Zang ', 'Luo ', 'Qu ', 'Zang ', 'Luan ', 'Ni ', 'Zang ', 'Chen ', 'Qian ', 'Wo ', 'Guang ', 'Zang ', 'Lin ', 'Guang ', 'Zi ', 'Jiao ', 'Nie ', 'Chou ', 'Ji ', 'Gao ', 'Chou ', 'Mian ', 'Nie ', 'Zhi ', 'Zhi ', 'Ge ', 'Jian ', 'Die ', 'Zhi ', 'Xiu ', 'Tai ', 'Zhen ', 'Jiu ', 'Xian ', 'Yu ', 'Cha '];
<?php return ['Yao ', 'Yu ', 'Chong ', 'Xi ', 'Xi ', 'Jiu ', 'Yu ', 'Yu ', 'Xing ', 'Ju ', 'Jiu ', 'Xin ', 'She ', 'She ', 'Yadoru ', 'Jiu ', 'Shi ', 'Tan ', 'Shu ', 'Shi ', 'Tian ', 'Dan ', 'Pu ', 'Pu ', 'Guan ', 'Hua ', 'Tan ', 'Chuan ', 'Shun ', 'Xia ', 'Wu ', 'Zhou ', 'Dao ', 'Gang ', 'Shan ', 'Yi ', '[?] ', 'Pa ', 'Tai ', 'Fan ', 'Ban ', 'Chuan ', 'Hang ', 'Fang ', 'Ban ', 'Que ', 'Hesaki ', 'Zhong ', 'Jian ', 'Cang ', 'Ling ', 'Zhu ', 'Ze ', 'Duo ', 'Bo ', 'Xian ', 'Ge ', 'Chuan ', 'Jia ', 'Lu ', 'Hong ', 'Pang ', 'Xi ', '[?] ', 'Fu ', 'Zao ', 'Feng ', 'Li ', 'Shao ', 'Yu ', 'Lang ', 'Ting ', '[?] ', 'Wei ', 'Bo ', 'Meng ', 'Nian ', 'Ju ', 'Huang ', 'Shou ', 'Zong ', 'Bian ', 'Mao ', 'Die ', '[?] ', 'Bang ', 'Cha ', 'Yi ', 'Sao ', 'Cang ', 'Cao ', 'Lou ', 'Dai ', 'Sori ', 'Yao ', 'Tong ', 'Yofune ', 'Dang ', 'Tan ', 'Lu ', 'Yi ', 'Jie ', 'Jian ', 'Huo ', 'Meng ', 'Qi ', 'Lu ', 'Lu ', 'Chan ', 'Shuang ', 'Gen ', 'Liang ', 'Jian ', 'Jian ', 'Se ', 'Yan ', 'Fu ', 'Ping ', 'Yan ', 'Yan ', 'Cao ', 'Cao ', 'Yi ', 'Le ', 'Ting ', 'Qiu ', 'Ai ', 'Nai ', 'Tiao ', 'Jiao ', 'Jie ', 'Peng ', 'Wan ', 'Yi ', 'Chai ', 'Mian ', 'Mie ', 'Gan ', 'Qian ', 'Yu ', 'Yu ', 'Shuo ', 'Qiong ', 'Tu ', 'Xia ', 'Qi ', 'Mang ', 'Zi ', 'Hui ', 'Sui ', 'Zhi ', 'Xiang ', 'Bi ', 'Fu ', 'Tun ', 'Wei ', 'Wu ', 'Zhi ', 'Qi ', 'Shan ', 'Wen ', 'Qian ', 'Ren ', 'Fou ', 'Kou ', 'Jie ', 'Lu ', 'Xu ', 'Ji ', 'Qin ', 'Qi ', 'Yuan ', 'Fen ', 'Ba ', 'Rui ', 'Xin ', 'Ji ', 'Hua ', 'Hua ', 'Fang ', 'Wu ', 'Jue ', 'Gou ', 'Zhi ', 'Yun ', 'Qin ', 'Ao ', 'Chu ', 'Mao ', 'Ya ', 'Fei ', 'Reng ', 'Hang ', 'Cong ', 'Yin ', 'You ', 'Bian ', 'Yi ', 'Susa ', 'Wei ', 'Li ', 'Pi ', 'E ', 'Xian ', 'Chang ', 'Cang ', 'Meng ', 'Su ', 'Yi ', 'Yuan ', 'Ran ', 'Ling ', 'Tai ', 'Tiao ', 'Di ', 'Miao ', 'Qiong ', 'Li ', 'Yong ', 'Ke ', 'Mu ', 'Pei ', 'Bao ', 'Gou ', 'Min ', 'Yi ', 'Yi ', 'Ju ', 'Pi ', 'Ruo ', 'Ku ', 'Zhu ', 'Ni ', 'Bo ', 'Bing ', 'Shan ', 'Qiu ', 'Yao ', 'Xian ', 'Ben ', 'Hong ', 'Ying ', 'Zha ', 'Dong ', 'Ju ', 'Die ', 'Nie ', 'Gan ', 'Hu ', 'Ping ', 'Mei ', 'Fu ', 'Sheng ', 'Gu ', 'Bi ', 'Wei '];
<?php return ['Fu ', 'Zhuo ', 'Mao ', 'Fan ', 'Qie ', 'Mao ', 'Mao ', 'Ba ', 'Zi ', 'Mo ', 'Zi ', 'Di ', 'Chi ', 'Ji ', 'Jing ', 'Long ', '[?] ', 'Niao ', '[?] ', 'Xue ', 'Ying ', 'Qiong ', 'Ge ', 'Ming ', 'Li ', 'Rong ', 'Yin ', 'Gen ', 'Qian ', 'Chai ', 'Chen ', 'Yu ', 'Xiu ', 'Zi ', 'Lie ', 'Wu ', 'Ji ', 'Kui ', 'Ce ', 'Chong ', 'Ci ', 'Gou ', 'Guang ', 'Mang ', 'Chi ', 'Jiao ', 'Jiao ', 'Fu ', 'Yu ', 'Zhu ', 'Zi ', 'Jiang ', 'Hui ', 'Yin ', 'Cha ', 'Fa ', 'Rong ', 'Ru ', 'Chong ', 'Mang ', 'Tong ', 'Zhong ', '[?] ', 'Zhu ', 'Xun ', 'Huan ', 'Kua ', 'Quan ', 'Gai ', 'Da ', 'Jing ', 'Xing ', 'Quan ', 'Cao ', 'Jing ', 'Er ', 'An ', 'Shou ', 'Chi ', 'Ren ', 'Jian ', 'Ti ', 'Huang ', 'Ping ', 'Li ', 'Jin ', 'Lao ', 'Shu ', 'Zhuang ', 'Da ', 'Jia ', 'Rao ', 'Bi ', 'Ze ', 'Qiao ', 'Hui ', 'Qi ', 'Dang ', '[?] ', 'Rong ', 'Hun ', 'Ying ', 'Luo ', 'Ying ', 'Xun ', 'Jin ', 'Sun ', 'Yin ', 'Mai ', 'Hong ', 'Zhou ', 'Yao ', 'Du ', 'Wei ', 'Chu ', 'Dou ', 'Fu ', 'Ren ', 'Yin ', 'He ', 'Bi ', 'Bu ', 'Yun ', 'Di ', 'Tu ', 'Sui ', 'Sui ', 'Cheng ', 'Chen ', 'Wu ', 'Bie ', 'Xi ', 'Geng ', 'Li ', 'Fu ', 'Zhu ', 'Mo ', 'Li ', 'Zhuang ', 'Ji ', 'Duo ', 'Qiu ', 'Sha ', 'Suo ', 'Chen ', 'Feng ', 'Ju ', 'Mei ', 'Meng ', 'Xing ', 'Jing ', 'Che ', 'Xin ', 'Jun ', 'Yan ', 'Ting ', 'Diao ', 'Cuo ', 'Wan ', 'Han ', 'You ', 'Cuo ', 'Jia ', 'Wang ', 'You ', 'Niu ', 'Shao ', 'Xian ', 'Lang ', 'Fu ', 'E ', 'Mo ', 'Wen ', 'Jie ', 'Nan ', 'Mu ', 'Kan ', 'Lai ', 'Lian ', 'Shi ', 'Wo ', 'Usagi ', 'Lian ', 'Huo ', 'You ', 'Ying ', 'Ying ', 'Nuc ', 'Chun ', 'Mang ', 'Mang ', 'Ci ', 'Wan ', 'Jing ', 'Di ', 'Qu ', 'Dong ', 'Jian ', 'Zou ', 'Gu ', 'La ', 'Lu ', 'Ju ', 'Wei ', 'Jun ', 'Nie ', 'Kun ', 'He ', 'Pu ', 'Zi ', 'Gao ', 'Guo ', 'Fu ', 'Lun ', 'Chang ', 'Chou ', 'Song ', 'Chui ', 'Zhan ', 'Men ', 'Cai ', 'Ba ', 'Li ', 'Tu ', 'Bo ', 'Han ', 'Bao ', 'Qin ', 'Juan ', 'Xi ', 'Qin ', 'Di ', 'Jie ', 'Pu ', 'Dang ', 'Jin ', 'Zhao ', 'Tai ', 'Geng ', 'Hua ', 'Gu ', 'Ling ', 'Fei ', 'Jin ', 'An ', 'Wang ', 'Beng ', 'Zhou ', 'Yan ', 'Ju ', 'Jian ', 'Lin ', 'Tan ', 'Shu ', 'Tian ', 'Dao '];
<?php return ['Hu ', 'Qi ', 'He ', 'Cui ', 'Tao ', 'Chun ', 'Bei ', 'Chang ', 'Huan ', 'Fei ', 'Lai ', 'Qi ', 'Meng ', 'Ping ', 'Wei ', 'Dan ', 'Sha ', 'Huan ', 'Yan ', 'Yi ', 'Tiao ', 'Qi ', 'Wan ', 'Ce ', 'Nai ', 'Kutabireru ', 'Tuo ', 'Jiu ', 'Tie ', 'Luo ', '[?] ', '[?] ', 'Meng ', '[?] ', 'Yaji ', '[?] ', 'Ying ', 'Ying ', 'Ying ', 'Xiao ', 'Sa ', 'Qiu ', 'Ke ', 'Xiang ', 'Wan ', 'Yu ', 'Yu ', 'Fu ', 'Lian ', 'Xuan ', 'Yuan ', 'Nan ', 'Ze ', 'Wo ', 'Chun ', 'Xiao ', 'Yu ', 'Pian ', 'Mao ', 'An ', 'E ', 'Luo ', 'Ying ', 'Huo ', 'Gua ', 'Jiang ', 'Mian ', 'Zuo ', 'Zuo ', 'Ju ', 'Bao ', 'Rou ', 'Xi ', 'Xie ', 'An ', 'Qu ', 'Jian ', 'Fu ', 'Lu ', 'Jing ', 'Pen ', 'Feng ', 'Hong ', 'Hong ', 'Hou ', 'Yan ', 'Tu ', 'Zhu ', 'Zi ', 'Xiang ', 'Shen ', 'Ge ', 'Jie ', 'Jing ', 'Mi ', 'Huang ', 'Shen ', 'Pu ', 'Gai ', 'Dong ', 'Zhou ', 'Qian ', 'Wei ', 'Bo ', 'Wei ', 'Pa ', 'Ji ', 'Hu ', 'Zang ', 'Jia ', 'Duan ', 'Yao ', 'Jun ', 'Cong ', 'Quan ', 'Wei ', 'Xian ', 'Kui ', 'Ting ', 'Hun ', 'Xi ', 'Shi ', 'Qi ', 'Lan ', 'Zong ', 'Yao ', 'Yuan ', 'Mei ', 'Yun ', 'Shu ', 'Di ', 'Zhuan ', 'Guan ', 'Sukumo ', 'Xue ', 'Chan ', 'Kai ', 'Kui ', '[?] ', 'Jiang ', 'Lou ', 'Wei ', 'Pai ', '[?] ', 'Sou ', 'Yin ', 'Shi ', 'Chun ', 'Shi ', 'Yun ', 'Zhen ', 'Lang ', 'Nu ', 'Meng ', 'He ', 'Que ', 'Suan ', 'Yuan ', 'Li ', 'Ju ', 'Xi ', 'Pang ', 'Chu ', 'Xu ', 'Tu ', 'Liu ', 'Wo ', 'Zhen ', 'Qian ', 'Zu ', 'Po ', 'Cuo ', 'Yuan ', 'Chu ', 'Yu ', 'Kuai ', 'Pan ', 'Pu ', 'Pu ', 'Na ', 'Shuo ', 'Xi ', 'Fen ', 'Yun ', 'Zheng ', 'Jian ', 'Ji ', 'Ruo ', 'Cang ', 'En ', 'Mi ', 'Hao ', 'Sun ', 'Zhen ', 'Ming ', 'Sou ', 'Xu ', 'Liu ', 'Xi ', 'Gu ', 'Lang ', 'Rong ', 'Weng ', 'Gai ', 'Cuo ', 'Shi ', 'Tang ', 'Luo ', 'Ru ', 'Suo ', 'Xian ', 'Bei ', 'Yao ', 'Gui ', 'Bi ', 'Zong ', 'Gun ', 'Za ', 'Xiu ', 'Ce ', 'Hai ', 'Lan ', '[?] ', 'Ji ', 'Li ', 'Can ', 'Lang ', 'Yu ', '[?] ', 'Ying ', 'Mo ', 'Diao ', 'Tiao ', 'Mao ', 'Tong ', 'Zhu ', 'Peng ', 'An ', 'Lian ', 'Cong ', 'Xi ', 'Ping ', 'Qiu ', 'Jin ', 'Chun ', 'Jie ', 'Wei ', 'Tui ', 'Cao ', 'Yu ', 'Yi ', 'Ji ', 'Liao ', 'Bi ', 'Lu ', 'Su '];
<?php return ['Bu ', 'Zhang ', 'Luo ', 'Jiang ', 'Man ', 'Yan ', 'Ling ', 'Ji ', 'Piao ', 'Gun ', 'Han ', 'Di ', 'Su ', 'Lu ', 'She ', 'Shang ', 'Di ', 'Mie ', 'Xun ', 'Man ', 'Bo ', 'Di ', 'Cuo ', 'Zhe ', 'Sen ', 'Xuan ', 'Wei ', 'Hu ', 'Ao ', 'Mi ', 'Lou ', 'Cu ', 'Zhong ', 'Cai ', 'Po ', 'Jiang ', 'Mi ', 'Cong ', 'Niao ', 'Hui ', 'Jun ', 'Yin ', 'Jian ', 'Yan ', 'Shu ', 'Yin ', 'Kui ', 'Chen ', 'Hu ', 'Sha ', 'Kou ', 'Qian ', 'Ma ', 'Zang ', 'Sonoko ', 'Qiang ', 'Dou ', 'Lian ', 'Lin ', 'Kou ', 'Ai ', 'Bi ', 'Li ', 'Wei ', 'Ji ', 'Xun ', 'Sheng ', 'Fan ', 'Meng ', 'Ou ', 'Chan ', 'Dian ', 'Xun ', 'Jiao ', 'Rui ', 'Rui ', 'Lei ', 'Yu ', 'Qiao ', 'Chu ', 'Hua ', 'Jian ', 'Mai ', 'Yun ', 'Bao ', 'You ', 'Qu ', 'Lu ', 'Rao ', 'Hui ', 'E ', 'Teng ', 'Fei ', 'Jue ', 'Zui ', 'Fa ', 'Ru ', 'Fen ', 'Kui ', 'Shun ', 'Rui ', 'Ya ', 'Xu ', 'Fu ', 'Jue ', 'Dang ', 'Wu ', 'Tong ', 'Si ', 'Xiao ', 'Xi ', 'Long ', 'Yun ', '[?] ', 'Qi ', 'Jian ', 'Yun ', 'Sun ', 'Ling ', 'Yu ', 'Xia ', 'Yong ', 'Ji ', 'Hong ', 'Si ', 'Nong ', 'Lei ', 'Xuan ', 'Yun ', 'Yu ', 'Xi ', 'Hao ', 'Bo ', 'Hao ', 'Ai ', 'Wei ', 'Hui ', 'Wei ', 'Ji ', 'Ci ', 'Xiang ', 'Luan ', 'Mie ', 'Yi ', 'Leng ', 'Jiang ', 'Can ', 'Shen ', 'Qiang ', 'Lian ', 'Ke ', 'Yuan ', 'Da ', 'Ti ', 'Tang ', 'Xie ', 'Bi ', 'Zhan ', 'Sun ', 'Lian ', 'Fan ', 'Ding ', 'Jie ', 'Gu ', 'Xie ', 'Shu ', 'Jian ', 'Kao ', 'Hong ', 'Sa ', 'Xin ', 'Xun ', 'Yao ', 'Hie ', 'Sou ', 'Shu ', 'Xun ', 'Dui ', 'Pin ', 'Wei ', 'Neng ', 'Chou ', 'Mai ', 'Ru ', 'Piao ', 'Tai ', 'Qi ', 'Zao ', 'Chen ', 'Zhen ', 'Er ', 'Ni ', 'Ying ', 'Gao ', 'Cong ', 'Xiao ', 'Qi ', 'Fa ', 'Jian ', 'Xu ', 'Kui ', 'Jie ', 'Bian ', 'Diao ', 'Mi ', 'Lan ', 'Jin ', 'Cang ', 'Miao ', 'Qiong ', 'Qie ', 'Xian ', '[?] ', 'Ou ', 'Xian ', 'Su ', 'Lu ', 'Yi ', 'Xu ', 'Xie ', 'Li ', 'Yi ', 'La ', 'Lei ', 'Xiao ', 'Di ', 'Zhi ', 'Bei ', 'Teng ', 'Yao ', 'Mo ', 'Huan ', 'Piao ', 'Fan ', 'Sou ', 'Tan ', 'Tui ', 'Qiong ', 'Qiao ', 'Wei ', 'Liu ', 'Hui ', '[?] ', 'Gao ', 'Yun ', '[?] ', 'Li ', 'Shu ', 'Chu ', 'Ai ', 'Lin ', 'Zao ', 'Xuan ', 'Chen ', 'Lai ', 'Huo '];
<?php return ['Tuo ', 'Wu ', 'Rui ', 'Rui ', 'Qi ', 'Heng ', 'Lu ', 'Su ', 'Tui ', 'Mang ', 'Yun ', 'Pin ', 'Yu ', 'Xun ', 'Ji ', 'Jiong ', 'Xian ', 'Mo ', 'Hagi ', 'Su ', 'Jiong ', '[?] ', 'Nie ', 'Bo ', 'Rang ', 'Yi ', 'Xian ', 'Yu ', 'Ju ', 'Lian ', 'Lian ', 'Yin ', 'Qiang ', 'Ying ', 'Long ', 'Tong ', 'Wei ', 'Yue ', 'Ling ', 'Qu ', 'Yao ', 'Fan ', 'Mi ', 'Lan ', 'Kui ', 'Lan ', 'Ji ', 'Dang ', 'Katsura ', 'Lei ', 'Lei ', 'Hua ', 'Feng ', 'Zhi ', 'Wei ', 'Kui ', 'Zhan ', 'Huai ', 'Li ', 'Ji ', 'Mi ', 'Lei ', 'Huai ', 'Luo ', 'Ji ', 'Kui ', 'Lu ', 'Jian ', 'San ', '[?] ', 'Lei ', 'Quan ', 'Xiao ', 'Yi ', 'Luan ', 'Men ', 'Bie ', 'Hu ', 'Hu ', 'Lu ', 'Nue ', 'Lu ', 'Si ', 'Xiao ', 'Qian ', 'Chu ', 'Hu ', 'Xu ', 'Cuo ', 'Fu ', 'Xu ', 'Xu ', 'Lu ', 'Hu ', 'Yu ', 'Hao ', 'Jiao ', 'Ju ', 'Guo ', 'Bao ', 'Yan ', 'Zhan ', 'Zhan ', 'Kui ', 'Ban ', 'Xi ', 'Shu ', 'Chong ', 'Qiu ', 'Diao ', 'Ji ', 'Qiu ', 'Cheng ', 'Shi ', '[?] ', 'Di ', 'Zhe ', 'She ', 'Yu ', 'Gan ', 'Zi ', 'Hong ', 'Hui ', 'Meng ', 'Ge ', 'Sui ', 'Xia ', 'Chai ', 'Shi ', 'Yi ', 'Ma ', 'Xiang ', 'Fang ', 'E ', 'Pa ', 'Chi ', 'Qian ', 'Wen ', 'Wen ', 'Rui ', 'Bang ', 'Bi ', 'Yue ', 'Yue ', 'Jun ', 'Qi ', 'Ran ', 'Yin ', 'Qi ', 'Tian ', 'Yuan ', 'Jue ', 'Hui ', 'Qin ', 'Qi ', 'Zhong ', 'Ya ', 'Ci ', 'Mu ', 'Wang ', 'Fen ', 'Fen ', 'Hang ', 'Gong ', 'Zao ', 'Fu ', 'Ran ', 'Jie ', 'Fu ', 'Chi ', 'Dou ', 'Piao ', 'Xian ', 'Ni ', 'Te ', 'Qiu ', 'You ', 'Zha ', 'Ping ', 'Chi ', 'You ', 'He ', 'Han ', 'Ju ', 'Li ', 'Fu ', 'Ran ', 'Zha ', 'Gou ', 'Pi ', 'Bo ', 'Xian ', 'Zhu ', 'Diao ', 'Bie ', 'Bing ', 'Gu ', 'Ran ', 'Qu ', 'She ', 'Tie ', 'Ling ', 'Gu ', 'Dan ', 'Gu ', 'Ying ', 'Li ', 'Cheng ', 'Qu ', 'Mou ', 'Ge ', 'Ci ', 'Hui ', 'Hui ', 'Mang ', 'Fu ', 'Yang ', 'Wa ', 'Lie ', 'Zhu ', 'Yi ', 'Xian ', 'Kuo ', 'Jiao ', 'Li ', 'Yi ', 'Ping ', 'Ji ', 'Ha ', 'She ', 'Yi ', 'Wang ', 'Mo ', 'Qiong ', 'Qie ', 'Gui ', 'Gong ', 'Zhi ', 'Man ', 'Ebi ', 'Zhi ', 'Jia ', 'Rao ', 'Si ', 'Qi ', 'Xing ', 'Lie ', 'Qiu ', 'Shao ', 'Yong ', 'Jia ', 'Shui ', 'Che ', 'Bai ', 'E ', 'Han '];
<?php return ['Shu ', 'Xuan ', 'Feng ', 'Shen ', 'Zhen ', 'Fu ', 'Xian ', 'Zhe ', 'Wu ', 'Fu ', 'Li ', 'Lang ', 'Bi ', 'Chu ', 'Yuan ', 'You ', 'Jie ', 'Dan ', 'Yan ', 'Ting ', 'Dian ', 'Shui ', 'Hui ', 'Gua ', 'Zhi ', 'Song ', 'Fei ', 'Ju ', 'Mi ', 'Qi ', 'Qi ', 'Yu ', 'Jun ', 'Zha ', 'Meng ', 'Qiang ', 'Si ', 'Xi ', 'Lun ', 'Li ', 'Die ', 'Tiao ', 'Tao ', 'Kun ', 'Gan ', 'Han ', 'Yu ', 'Bang ', 'Fei ', 'Pi ', 'Wei ', 'Dun ', 'Yi ', 'Yuan ', 'Su ', 'Quan ', 'Qian ', 'Rui ', 'Ni ', 'Qing ', 'Wei ', 'Liang ', 'Guo ', 'Wan ', 'Dong ', 'E ', 'Ban ', 'Di ', 'Wang ', 'Can ', 'Yang ', 'Ying ', 'Guo ', 'Chan ', '[?] ', 'La ', 'Ke ', 'Ji ', 'He ', 'Ting ', 'Mai ', 'Xu ', 'Mian ', 'Yu ', 'Jie ', 'Shi ', 'Xuan ', 'Huang ', 'Yan ', 'Bian ', 'Rou ', 'Wei ', 'Fu ', 'Yuan ', 'Mei ', 'Wei ', 'Fu ', 'Ruan ', 'Xie ', 'You ', 'Qiu ', 'Mao ', 'Xia ', 'Ying ', 'Shi ', 'Chong ', 'Tang ', 'Zhu ', 'Zong ', 'Ti ', 'Fu ', 'Yuan ', 'Hui ', 'Meng ', 'La ', 'Du ', 'Hu ', 'Qiu ', 'Die ', 'Li ', 'Gua ', 'Yun ', 'Ju ', 'Nan ', 'Lou ', 'Qun ', 'Rong ', 'Ying ', 'Jiang ', '[?] ', 'Lang ', 'Pang ', 'Si ', 'Xi ', 'Ci ', 'Xi ', 'Yuan ', 'Weng ', 'Lian ', 'Sou ', 'Ban ', 'Rong ', 'Rong ', 'Ji ', 'Wu ', 'Qiu ', 'Han ', 'Qin ', 'Yi ', 'Bi ', 'Hua ', 'Tang ', 'Yi ', 'Du ', 'Nai ', 'He ', 'Hu ', 'Hui ', 'Ma ', 'Ming ', 'Yi ', 'Wen ', 'Ying ', 'Teng ', 'Yu ', 'Cang ', 'So ', 'Ebi ', 'Man ', '[?] ', 'Shang ', 'Zhe ', 'Cao ', 'Chi ', 'Di ', 'Ao ', 'Lu ', 'Wei ', 'Zhi ', 'Tang ', 'Chen ', 'Piao ', 'Qu ', 'Pi ', 'Yu ', 'Jian ', 'Luo ', 'Lou ', 'Qin ', 'Zhong ', 'Yin ', 'Jiang ', 'Shuai ', 'Wen ', 'Jiao ', 'Wan ', 'Zhi ', 'Zhe ', 'Ma ', 'Ma ', 'Guo ', 'Liu ', 'Mao ', 'Xi ', 'Cong ', 'Li ', 'Man ', 'Xiao ', 'Kamakiri ', 'Zhang ', 'Mang ', 'Xiang ', 'Mo ', 'Zui ', 'Si ', 'Qiu ', 'Te ', 'Zhi ', 'Peng ', 'Peng ', 'Jiao ', 'Qu ', 'Bie ', 'Liao ', 'Pan ', 'Gui ', 'Xi ', 'Ji ', 'Zhuan ', 'Huang ', 'Fei ', 'Lao ', 'Jue ', 'Jue ', 'Hui ', 'Yin ', 'Chan ', 'Jiao ', 'Shan ', 'Rao ', 'Xiao ', 'Mou ', 'Chong ', 'Xun ', 'Si ', '[?] ', 'Cheng ', 'Dang ', 'Li ', 'Xie ', 'Shan ', 'Yi ', 'Jing ', 'Da ', 'Chan ', 'Qi '];
<?php return ['Ci ', 'Xiang ', 'She ', 'Luo ', 'Qin ', 'Ying ', 'Chai ', 'Li ', 'Ze ', 'Xuan ', 'Lian ', 'Zhu ', 'Ze ', 'Xie ', 'Mang ', 'Xie ', 'Qi ', 'Rong ', 'Jian ', 'Meng ', 'Hao ', 'Ruan ', 'Huo ', 'Zhuo ', 'Jie ', 'Bin ', 'He ', 'Mie ', 'Fan ', 'Lei ', 'Jie ', 'La ', 'Mi ', 'Li ', 'Chun ', 'Li ', 'Qiu ', 'Nie ', 'Lu ', 'Du ', 'Xiao ', 'Zhu ', 'Long ', 'Li ', 'Long ', 'Feng ', 'Ye ', 'Beng ', 'Shang ', 'Gu ', 'Juan ', 'Ying ', '[?] ', 'Xi ', 'Can ', 'Qu ', 'Quan ', 'Du ', 'Can ', 'Man ', 'Jue ', 'Jie ', 'Zhu ', 'Zha ', 'Xie ', 'Huang ', 'Niu ', 'Pei ', 'Nu ', 'Xin ', 'Zhong ', 'Mo ', 'Er ', 'Ke ', 'Mie ', 'Xi ', 'Xing ', 'Yan ', 'Kan ', 'Yuan ', '[?] ', 'Ling ', 'Xuan ', 'Shu ', 'Xian ', 'Tong ', 'Long ', 'Jie ', 'Xian ', 'Ya ', 'Hu ', 'Wei ', 'Dao ', 'Chong ', 'Wei ', 'Dao ', 'Zhun ', 'Heng ', 'Qu ', 'Yi ', 'Yi ', 'Bu ', 'Gan ', 'Yu ', 'Biao ', 'Cha ', 'Yi ', 'Shan ', 'Chen ', 'Fu ', 'Gun ', 'Fen ', 'Shuai ', 'Jie ', 'Na ', 'Zhong ', 'Dan ', 'Ri ', 'Zhong ', 'Zhong ', 'Xie ', 'Qi ', 'Xie ', 'Ran ', 'Zhi ', 'Ren ', 'Qin ', 'Jin ', 'Jun ', 'Yuan ', 'Mei ', 'Chai ', 'Ao ', 'Niao ', 'Hui ', 'Ran ', 'Jia ', 'Tuo ', 'Ling ', 'Dai ', 'Bao ', 'Pao ', 'Yao ', 'Zuo ', 'Bi ', 'Shao ', 'Tan ', 'Ju ', 'He ', 'Shu ', 'Xiu ', 'Zhen ', 'Yi ', 'Pa ', 'Bo ', 'Di ', 'Wa ', 'Fu ', 'Gun ', 'Zhi ', 'Zhi ', 'Ran ', 'Pan ', 'Yi ', 'Mao ', 'Tuo ', 'Na ', 'Kou ', 'Xian ', 'Chan ', 'Qu ', 'Bei ', 'Gun ', 'Xi ', 'Ne ', 'Bo ', 'Horo ', 'Fu ', 'Yi ', 'Chi ', 'Ku ', 'Ren ', 'Jiang ', 'Jia ', 'Cun ', 'Mo ', 'Jie ', 'Er ', 'Luo ', 'Ru ', 'Zhu ', 'Gui ', 'Yin ', 'Cai ', 'Lie ', 'Kamishimo ', 'Yuki ', 'Zhuang ', 'Dang ', '[?] ', 'Kun ', 'Ken ', 'Niao ', 'Shu ', 'Jia ', 'Kun ', 'Cheng ', 'Li ', 'Juan ', 'Shen ', 'Pou ', 'Ge ', 'Yi ', 'Yu ', 'Zhen ', 'Liu ', 'Qiu ', 'Qun ', 'Ji ', 'Yi ', 'Bu ', 'Zhuang ', 'Shui ', 'Sha ', 'Qun ', 'Li ', 'Lian ', 'Lian ', 'Ku ', 'Jian ', 'Fou ', 'Chan ', 'Bi ', 'Gun ', 'Tao ', 'Yuan ', 'Ling ', 'Chi ', 'Chang ', 'Chou ', 'Duo ', 'Biao ', 'Liang ', 'Chang ', 'Pei ', 'Pei ', 'Fei ', 'Yuan ', 'Luo ', 'Guo ', 'Yan ', 'Du ', 'Xi ', 'Zhi ', 'Ju ', 'Qi '];
<?php return ['Ji ', 'Zhi ', 'Gua ', 'Ken ', 'Che ', 'Ti ', 'Ti ', 'Fu ', 'Chong ', 'Xie ', 'Bian ', 'Die ', 'Kun ', 'Duan ', 'Xiu ', 'Xiu ', 'He ', 'Yuan ', 'Bao ', 'Bao ', 'Fu ', 'Yu ', 'Tuan ', 'Yan ', 'Hui ', 'Bei ', 'Chu ', 'Lu ', 'Ena ', 'Hitoe ', 'Yun ', 'Da ', 'Gou ', 'Da ', 'Huai ', 'Rong ', 'Yuan ', 'Ru ', 'Nai ', 'Jiong ', 'Suo ', 'Ban ', 'Tun ', 'Chi ', 'Sang ', 'Niao ', 'Ying ', 'Jie ', 'Qian ', 'Huai ', 'Ku ', 'Lian ', 'Bao ', 'Li ', 'Zhe ', 'Shi ', 'Lu ', 'Yi ', 'Die ', 'Xie ', 'Xian ', 'Wei ', 'Biao ', 'Cao ', 'Ji ', 'Jiang ', 'Sen ', 'Bao ', 'Xiang ', 'Chihaya ', 'Pu ', 'Jian ', 'Zhuan ', 'Jian ', 'Zui ', 'Ji ', 'Dan ', 'Za ', 'Fan ', 'Bo ', 'Xiang ', 'Xin ', 'Bie ', 'Rao ', 'Man ', 'Lan ', 'Ao ', 'Duo ', 'Gui ', 'Cao ', 'Sui ', 'Nong ', 'Chan ', 'Lian ', 'Bi ', 'Jin ', 'Dang ', 'Shu ', 'Tan ', 'Bi ', 'Lan ', 'Pu ', 'Ru ', 'Zhi ', '[?] ', 'Shu ', 'Wa ', 'Shi ', 'Bai ', 'Xie ', 'Bo ', 'Chen ', 'Lai ', 'Long ', 'Xi ', 'Xian ', 'Lan ', 'Zhe ', 'Dai ', 'Tasuki ', 'Zan ', 'Shi ', 'Jian ', 'Pan ', 'Yi ', 'Ran ', 'Ya ', 'Xi ', 'Xi ', 'Yao ', 'Feng ', 'Tan ', '[?] ', 'Biao ', 'Fu ', 'Ba ', 'He ', 'Ji ', 'Ji ', 'Jian ', 'Guan ', 'Bian ', 'Yan ', 'Gui ', 'Jue ', 'Pian ', 'Mao ', 'Mi ', 'Mi ', 'Mie ', 'Shi ', 'Si ', 'Zhan ', 'Luo ', 'Jue ', 'Mi ', 'Tiao ', 'Lian ', 'Yao ', 'Zhi ', 'Jun ', 'Xi ', 'Shan ', 'Wei ', 'Xi ', 'Tian ', 'Yu ', 'Lan ', 'E ', 'Du ', 'Qin ', 'Pang ', 'Ji ', 'Ming ', 'Ying ', 'Gou ', 'Qu ', 'Zhan ', 'Jin ', 'Guan ', 'Deng ', 'Jian ', 'Luo ', 'Qu ', 'Jian ', 'Wei ', 'Jue ', 'Qu ', 'Luo ', 'Lan ', 'Shen ', 'Di ', 'Guan ', 'Jian ', 'Guan ', 'Yan ', 'Gui ', 'Mi ', 'Shi ', 'Zhan ', 'Lan ', 'Jue ', 'Ji ', 'Xi ', 'Di ', 'Tian ', 'Yu ', 'Gou ', 'Jin ', 'Qu ', 'Jiao ', 'Jiu ', 'Jin ', 'Cu ', 'Jue ', 'Zhi ', 'Chao ', 'Ji ', 'Gu ', 'Dan ', 'Zui ', 'Di ', 'Shang ', 'Hua ', 'Quan ', 'Ge ', 'Chi ', 'Jie ', 'Gui ', 'Gong ', 'Hong ', 'Jie ', 'Hun ', 'Qiu ', 'Xing ', 'Su ', 'Ni ', 'Ji ', 'Lu ', 'Zhi ', 'Zha ', 'Bi ', 'Xing ', 'Hu ', 'Shang ', 'Gong ', 'Zhi ', 'Xue ', 'Chu ', 'Xi ', 'Yi ', 'Lu ', 'Jue ', 'Xi ', 'Yan ', 'Xi '];
<?php return ['Yan ', 'Yan ', 'Ding ', 'Fu ', 'Qiu ', 'Qiu ', 'Jiao ', 'Hong ', 'Ji ', 'Fan ', 'Xun ', 'Diao ', 'Hong ', 'Cha ', 'Tao ', 'Xu ', 'Jie ', 'Yi ', 'Ren ', 'Xun ', 'Yin ', 'Shan ', 'Qi ', 'Tuo ', 'Ji ', 'Xun ', 'Yin ', 'E ', 'Fen ', 'Ya ', 'Yao ', 'Song ', 'Shen ', 'Yin ', 'Xin ', 'Jue ', 'Xiao ', 'Ne ', 'Chen ', 'You ', 'Zhi ', 'Xiong ', 'Fang ', 'Xin ', 'Chao ', 'She ', 'Xian ', 'Sha ', 'Tun ', 'Xu ', 'Yi ', 'Yi ', 'Su ', 'Chi ', 'He ', 'Shen ', 'He ', 'Xu ', 'Zhen ', 'Zhu ', 'Zheng ', 'Gou ', 'Zi ', 'Zi ', 'Zhan ', 'Gu ', 'Fu ', 'Quan ', 'Die ', 'Ling ', 'Di ', 'Yang ', 'Li ', 'Nao ', 'Pan ', 'Zhou ', 'Gan ', 'Yi ', 'Ju ', 'Ao ', 'Zha ', 'Tuo ', 'Yi ', 'Qu ', 'Zhao ', 'Ping ', 'Bi ', 'Xiong ', 'Qu ', 'Ba ', 'Da ', 'Zu ', 'Tao ', 'Zhu ', 'Ci ', 'Zhe ', 'Yong ', 'Xu ', 'Xun ', 'Yi ', 'Huang ', 'He ', 'Shi ', 'Cha ', 'Jiao ', 'Shi ', 'Hen ', 'Cha ', 'Gou ', 'Gui ', 'Quan ', 'Hui ', 'Jie ', 'Hua ', 'Gai ', 'Xiang ', 'Wei ', 'Shen ', 'Chou ', 'Tong ', 'Mi ', 'Zhan ', 'Ming ', 'E ', 'Hui ', 'Yan ', 'Xiong ', 'Gua ', 'Er ', 'Beng ', 'Tiao ', 'Chi ', 'Lei ', 'Zhu ', 'Kuang ', 'Kua ', 'Wu ', 'Yu ', 'Teng ', 'Ji ', 'Zhi ', 'Ren ', 'Su ', 'Lang ', 'E ', 'Kuang ', 'E ', 'Shi ', 'Ting ', 'Dan ', 'Bo ', 'Chan ', 'You ', 'Heng ', 'Qiao ', 'Qin ', 'Shua ', 'An ', 'Yu ', 'Xiao ', 'Cheng ', 'Jie ', 'Xian ', 'Wu ', 'Wu ', 'Gao ', 'Song ', 'Pu ', 'Hui ', 'Jing ', 'Shuo ', 'Zhen ', 'Shuo ', 'Du ', 'Yasashi ', 'Chang ', 'Shui ', 'Jie ', 'Ke ', 'Qu ', 'Cong ', 'Xiao ', 'Sui ', 'Wang ', 'Xuan ', 'Fei ', 'Chi ', 'Ta ', 'Yi ', 'Na ', 'Yin ', 'Diao ', 'Pi ', 'Chuo ', 'Chan ', 'Chen ', 'Zhun ', 'Ji ', 'Qi ', 'Tan ', 'Zhui ', 'Wei ', 'Ju ', 'Qing ', 'Jian ', 'Zheng ', 'Ze ', 'Zou ', 'Qian ', 'Zhuo ', 'Liang ', 'Jian ', 'Zhu ', 'Hao ', 'Lun ', 'Shen ', 'Biao ', 'Huai ', 'Pian ', 'Yu ', 'Die ', 'Xu ', 'Pian ', 'Shi ', 'Xuan ', 'Shi ', 'Hun ', 'Hua ', 'E ', 'Zhong ', 'Di ', 'Xie ', 'Fu ', 'Pu ', 'Ting ', 'Jian ', 'Qi ', 'Yu ', 'Zi ', 'Chuan ', 'Xi ', 'Hui ', 'Yin ', 'An ', 'Xian ', 'Nan ', 'Chen ', 'Feng ', 'Zhu ', 'Yang ', 'Yan ', 'Heng ', 'Xuan ', 'Ge ', 'Nuo ', 'Qi '];
<?php return ['Mou ', 'Ye ', 'Wei ', '[?] ', 'Teng ', 'Zou ', 'Shan ', 'Jian ', 'Bo ', 'Ku ', 'Huang ', 'Huo ', 'Ge ', 'Ying ', 'Mi ', 'Xiao ', 'Mi ', 'Xi ', 'Qiang ', 'Chen ', 'Nue ', 'Ti ', 'Su ', 'Bang ', 'Chi ', 'Qian ', 'Shi ', 'Jiang ', 'Yuan ', 'Xie ', 'Xue ', 'Tao ', 'Yao ', 'Yao ', '[?] ', 'Yu ', 'Biao ', 'Cong ', 'Qing ', 'Li ', 'Mo ', 'Mo ', 'Shang ', 'Zhe ', 'Miu ', 'Jian ', 'Ze ', 'Jie ', 'Lian ', 'Lou ', 'Can ', 'Ou ', 'Guan ', 'Xi ', 'Zhuo ', 'Ao ', 'Ao ', 'Jin ', 'Zhe ', 'Yi ', 'Hu ', 'Jiang ', 'Man ', 'Chao ', 'Han ', 'Hua ', 'Chan ', 'Xu ', 'Zeng ', 'Se ', 'Xi ', 'She ', 'Dui ', 'Zheng ', 'Nao ', 'Lan ', 'E ', 'Ying ', 'Jue ', 'Ji ', 'Zun ', 'Jiao ', 'Bo ', 'Hui ', 'Zhuan ', 'Mu ', 'Zen ', 'Zha ', 'Shi ', 'Qiao ', 'Tan ', 'Zen ', 'Pu ', 'Sheng ', 'Xuan ', 'Zao ', 'Tan ', 'Dang ', 'Sui ', 'Qian ', 'Ji ', 'Jiao ', 'Jing ', 'Lian ', 'Nou ', 'Yi ', 'Ai ', 'Zhan ', 'Pi ', 'Hui ', 'Hua ', 'Yi ', 'Yi ', 'Shan ', 'Rang ', 'Nou ', 'Qian ', 'Zhui ', 'Ta ', 'Hu ', 'Zhou ', 'Hao ', 'Ye ', 'Ying ', 'Jian ', 'Yu ', 'Jian ', 'Hui ', 'Du ', 'Zhe ', 'Xuan ', 'Zan ', 'Lei ', 'Shen ', 'Wei ', 'Chan ', 'Li ', 'Yi ', 'Bian ', 'Zhe ', 'Yan ', 'E ', 'Chou ', 'Wei ', 'Chou ', 'Yao ', 'Chan ', 'Rang ', 'Yin ', 'Lan ', 'Chen ', 'Huo ', 'Zhe ', 'Huan ', 'Zan ', 'Yi ', 'Dang ', 'Zhan ', 'Yan ', 'Du ', 'Yan ', 'Ji ', 'Ding ', 'Fu ', 'Ren ', 'Ji ', 'Jie ', 'Hong ', 'Tao ', 'Rang ', 'Shan ', 'Qi ', 'Tuo ', 'Xun ', 'Yi ', 'Xun ', 'Ji ', 'Ren ', 'Jiang ', 'Hui ', 'Ou ', 'Ju ', 'Ya ', 'Ne ', 'Xu ', 'E ', 'Lun ', 'Xiong ', 'Song ', 'Feng ', 'She ', 'Fang ', 'Jue ', 'Zheng ', 'Gu ', 'He ', 'Ping ', 'Zu ', 'Shi ', 'Xiong ', 'Zha ', 'Su ', 'Zhen ', 'Di ', 'Zou ', 'Ci ', 'Qu ', 'Zhao ', 'Bi ', 'Yi ', 'Yi ', 'Kuang ', 'Lei ', 'Shi ', 'Gua ', 'Shi ', 'Jie ', 'Hui ', 'Cheng ', 'Zhu ', 'Shen ', 'Hua ', 'Dan ', 'Gou ', 'Quan ', 'Gui ', 'Xun ', 'Yi ', 'Zheng ', 'Gai ', 'Xiang ', 'Cha ', 'Hun ', 'Xu ', 'Zhou ', 'Jie ', 'Wu ', 'Yu ', 'Qiao ', 'Wu ', 'Gao ', 'You ', 'Hui ', 'Kuang ', 'Shuo ', 'Song ', 'Ai ', 'Qing ', 'Zhu ', 'Zou ', 'Nuo ', 'Du ', 'Zhuo ', 'Fei ', 'Ke ', 'Wei '];
<?php return ['Yu ', 'Shui ', 'Shen ', 'Diao ', 'Chan ', 'Liang ', 'Zhun ', 'Sui ', 'Tan ', 'Shen ', 'Yi ', 'Mou ', 'Chen ', 'Die ', 'Huang ', 'Jian ', 'Xie ', 'Nue ', 'Ye ', 'Wei ', 'E ', 'Yu ', 'Xuan ', 'Chan ', 'Zi ', 'An ', 'Yan ', 'Di ', 'Mi ', 'Pian ', 'Xu ', 'Mo ', 'Dang ', 'Su ', 'Xie ', 'Yao ', 'Bang ', 'Shi ', 'Qian ', 'Mi ', 'Jin ', 'Man ', 'Zhe ', 'Jian ', 'Miu ', 'Tan ', 'Zen ', 'Qiao ', 'Lan ', 'Pu ', 'Jue ', 'Yan ', 'Qian ', 'Zhan ', 'Chen ', 'Gu ', 'Qian ', 'Hong ', 'Xia ', 'Jue ', 'Hong ', 'Han ', 'Hong ', 'Xi ', 'Xi ', 'Huo ', 'Liao ', 'Han ', 'Du ', 'Long ', 'Dou ', 'Jiang ', 'Qi ', 'Shi ', 'Li ', 'Deng ', 'Wan ', 'Bi ', 'Shu ', 'Xian ', 'Feng ', 'Zhi ', 'Zhi ', 'Yan ', 'Yan ', 'Shi ', 'Chu ', 'Hui ', 'Tun ', 'Yi ', 'Tun ', 'Yi ', 'Jian ', 'Ba ', 'Hou ', 'E ', 'Cu ', 'Xiang ', 'Huan ', 'Jian ', 'Ken ', 'Gai ', 'Qu ', 'Fu ', 'Xi ', 'Bin ', 'Hao ', 'Yu ', 'Zhu ', 'Jia ', '[?] ', 'Xi ', 'Bo ', 'Wen ', 'Huan ', 'Bin ', 'Di ', 'Zong ', 'Fen ', 'Yi ', 'Zhi ', 'Bao ', 'Chai ', 'Han ', 'Pi ', 'Na ', 'Pi ', 'Gou ', 'Na ', 'You ', 'Diao ', 'Mo ', 'Si ', 'Xiu ', 'Huan ', 'Kun ', 'He ', 'He ', 'Mo ', 'Han ', 'Mao ', 'Li ', 'Ni ', 'Bi ', 'Yu ', 'Jia ', 'Tuan ', 'Mao ', 'Pi ', 'Xi ', 'E ', 'Ju ', 'Mo ', 'Chu ', 'Tan ', 'Huan ', 'Jue ', 'Bei ', 'Zhen ', 'Yuan ', 'Fu ', 'Cai ', 'Gong ', 'Te ', 'Yi ', 'Hang ', 'Wan ', 'Pin ', 'Huo ', 'Fan ', 'Tan ', 'Guan ', 'Ze ', 'Zhi ', 'Er ', 'Zhu ', 'Shi ', 'Bi ', 'Zi ', 'Er ', 'Gui ', 'Pian ', 'Bian ', 'Mai ', 'Dai ', 'Sheng ', 'Kuang ', 'Fei ', 'Tie ', 'Yi ', 'Chi ', 'Mao ', 'He ', 'Bi ', 'Lu ', 'Ren ', 'Hui ', 'Gai ', 'Pian ', 'Zi ', 'Jia ', 'Xu ', 'Zei ', 'Jiao ', 'Gai ', 'Zang ', 'Jian ', 'Ying ', 'Xun ', 'Zhen ', 'She ', 'Bin ', 'Bin ', 'Qiu ', 'She ', 'Chuan ', 'Zang ', 'Zhou ', 'Lai ', 'Zan ', 'Si ', 'Chen ', 'Shang ', 'Tian ', 'Pei ', 'Geng ', 'Xian ', 'Mai ', 'Jian ', 'Sui ', 'Fu ', 'Tan ', 'Cong ', 'Cong ', 'Zhi ', 'Ji ', 'Zhang ', 'Du ', 'Jin ', 'Xiong ', 'Shun ', 'Yun ', 'Bao ', 'Zai ', 'Lai ', 'Feng ', 'Cang ', 'Ji ', 'Sheng ', 'Ai ', 'Zhuan ', 'Fu ', 'Gou ', 'Sai ', 'Ze ', 'Liao '];
<?php return ['Wei ', 'Bai ', 'Chen ', 'Zhuan ', 'Zhi ', 'Zhui ', 'Biao ', 'Yun ', 'Zeng ', 'Tan ', 'Zan ', 'Yan ', '[?] ', 'Shan ', 'Wan ', 'Ying ', 'Jin ', 'Gan ', 'Xian ', 'Zang ', 'Bi ', 'Du ', 'Shu ', 'Yan ', '[?] ', 'Xuan ', 'Long ', 'Gan ', 'Zang ', 'Bei ', 'Zhen ', 'Fu ', 'Yuan ', 'Gong ', 'Cai ', 'Ze ', 'Xian ', 'Bai ', 'Zhang ', 'Huo ', 'Zhi ', 'Fan ', 'Tan ', 'Pin ', 'Bian ', 'Gou ', 'Zhu ', 'Guan ', 'Er ', 'Jian ', 'Bi ', 'Shi ', 'Tie ', 'Gui ', 'Kuang ', 'Dai ', 'Mao ', 'Fei ', 'He ', 'Yi ', 'Zei ', 'Zhi ', 'Jia ', 'Hui ', 'Zi ', 'Ren ', 'Lu ', 'Zang ', 'Zi ', 'Gai ', 'Jin ', 'Qiu ', 'Zhen ', 'Lai ', 'She ', 'Fu ', 'Du ', 'Ji ', 'Shu ', 'Shang ', 'Si ', 'Bi ', 'Zhou ', 'Geng ', 'Pei ', 'Tan ', 'Lai ', 'Feng ', 'Zhui ', 'Fu ', 'Zhuan ', 'Sai ', 'Ze ', 'Yan ', 'Zan ', 'Yun ', 'Zeng ', 'Shan ', 'Ying ', 'Gan ', 'Chi ', 'Xi ', 'She ', 'Nan ', 'Xiong ', 'Xi ', 'Cheng ', 'He ', 'Cheng ', 'Zhe ', 'Xia ', 'Tang ', 'Zou ', 'Zou ', 'Li ', 'Jiu ', 'Fu ', 'Zhao ', 'Gan ', 'Qi ', 'Shan ', 'Qiong ', 'Qin ', 'Xian ', 'Ci ', 'Jue ', 'Qin ', 'Chi ', 'Ci ', 'Chen ', 'Chen ', 'Die ', 'Ju ', 'Chao ', 'Di ', 'Se ', 'Zhan ', 'Zhu ', 'Yue ', 'Qu ', 'Jie ', 'Chi ', 'Chu ', 'Gua ', 'Xue ', 'Ci ', 'Tiao ', 'Duo ', 'Lie ', 'Gan ', 'Suo ', 'Cu ', 'Xi ', 'Zhao ', 'Su ', 'Yin ', 'Ju ', 'Jian ', 'Que ', 'Tang ', 'Chuo ', 'Cui ', 'Lu ', 'Qu ', 'Dang ', 'Qiu ', 'Zi ', 'Ti ', 'Qu ', 'Chi ', 'Huang ', 'Qiao ', 'Qiao ', 'Yao ', 'Zao ', 'Ti ', '[?] ', 'Zan ', 'Zan ', 'Zu ', 'Pa ', 'Bao ', 'Ku ', 'Ke ', 'Dun ', 'Jue ', 'Fu ', 'Chen ', 'Jian ', 'Fang ', 'Zhi ', 'Sa ', 'Yue ', 'Pa ', 'Qi ', 'Yue ', 'Qiang ', 'Tuo ', 'Tai ', 'Yi ', 'Nian ', 'Ling ', 'Mei ', 'Ba ', 'Die ', 'Ku ', 'Tuo ', 'Jia ', 'Ci ', 'Pao ', 'Qia ', 'Zhu ', 'Ju ', 'Die ', 'Zhi ', 'Fu ', 'Pan ', 'Ju ', 'Shan ', 'Bo ', 'Ni ', 'Ju ', 'Li ', 'Gen ', 'Yi ', 'Ji ', 'Dai ', 'Xian ', 'Jiao ', 'Duo ', 'Zhu ', 'Zhuan ', 'Kua ', 'Zhuai ', 'Gui ', 'Qiong ', 'Kui ', 'Xiang ', 'Chi ', 'Lu ', 'Beng ', 'Zhi ', 'Jia ', 'Tiao ', 'Cai ', 'Jian ', 'Ta ', 'Qiao ', 'Bi ', 'Xian ', 'Duo ', 'Ji ', 'Ju ', 'Ji ', 'Shu ', 'Tu '];
<?php return ['Chu ', 'Jing ', 'Nie ', 'Xiao ', 'Bo ', 'Chi ', 'Qun ', 'Mou ', 'Shu ', 'Lang ', 'Yong ', 'Jiao ', 'Chou ', 'Qiao ', '[?] ', 'Ta ', 'Jian ', 'Qi ', 'Wo ', 'Wei ', 'Zhuo ', 'Jie ', 'Ji ', 'Nie ', 'Ju ', 'Ju ', 'Lun ', 'Lu ', 'Leng ', 'Huai ', 'Ju ', 'Chi ', 'Wan ', 'Quan ', 'Ti ', 'Bo ', 'Zu ', 'Qie ', 'Ji ', 'Cu ', 'Zong ', 'Cai ', 'Zong ', 'Peng ', 'Zhi ', 'Zheng ', 'Dian ', 'Zhi ', 'Yu ', 'Duo ', 'Dun ', 'Chun ', 'Yong ', 'Zhong ', 'Di ', 'Zhe ', 'Chen ', 'Chuai ', 'Jian ', 'Gua ', 'Tang ', 'Ju ', 'Fu ', 'Zu ', 'Die ', 'Pian ', 'Rou ', 'Nuo ', 'Ti ', 'Cha ', 'Tui ', 'Jian ', 'Dao ', 'Cuo ', 'Xi ', 'Ta ', 'Qiang ', 'Zhan ', 'Dian ', 'Ti ', 'Ji ', 'Nie ', 'Man ', 'Liu ', 'Zhan ', 'Bi ', 'Chong ', 'Lu ', 'Liao ', 'Cu ', 'Tang ', 'Dai ', 'Suo ', 'Xi ', 'Kui ', 'Ji ', 'Zhi ', 'Qiang ', 'Di ', 'Man ', 'Zong ', 'Lian ', 'Beng ', 'Zao ', 'Nian ', 'Bie ', 'Tui ', 'Ju ', 'Deng ', 'Ceng ', 'Xian ', 'Fan ', 'Chu ', 'Zhong ', 'Dun ', 'Bo ', 'Cu ', 'Zu ', 'Jue ', 'Jue ', 'Lin ', 'Ta ', 'Qiao ', 'Qiao ', 'Pu ', 'Liao ', 'Dun ', 'Cuan ', 'Kuang ', 'Zao ', 'Ta ', 'Bi ', 'Bi ', 'Zhu ', 'Ju ', 'Chu ', 'Qiao ', 'Dun ', 'Chou ', 'Ji ', 'Wu ', 'Yue ', 'Nian ', 'Lin ', 'Lie ', 'Zhi ', 'Li ', 'Zhi ', 'Chan ', 'Chu ', 'Duan ', 'Wei ', 'Long ', 'Lin ', 'Xian ', 'Wei ', 'Zuan ', 'Lan ', 'Xie ', 'Rang ', 'Xie ', 'Nie ', 'Ta ', 'Qu ', 'Jie ', 'Cuan ', 'Zuan ', 'Xi ', 'Kui ', 'Jue ', 'Lin ', 'Shen ', 'Gong ', 'Dan ', 'Segare ', 'Qu ', 'Ti ', 'Duo ', 'Duo ', 'Gong ', 'Lang ', 'Nerau ', 'Luo ', 'Ai ', 'Ji ', 'Ju ', 'Tang ', 'Utsuke ', '[?] ', 'Yan ', 'Shitsuke ', 'Kang ', 'Qu ', 'Lou ', 'Lao ', 'Tuo ', 'Zhi ', 'Yagate ', 'Ti ', 'Dao ', 'Yagate ', 'Yu ', 'Che ', 'Ya ', 'Gui ', 'Jun ', 'Wei ', 'Yue ', 'Xin ', 'Di ', 'Xuan ', 'Fan ', 'Ren ', 'Shan ', 'Qiang ', 'Shu ', 'Tun ', 'Chen ', 'Dai ', 'E ', 'Na ', 'Qi ', 'Mao ', 'Ruan ', 'Ren ', 'Fan ', 'Zhuan ', 'Hong ', 'Hu ', 'Qu ', 'Huang ', 'Di ', 'Ling ', 'Dai ', 'Ao ', 'Zhen ', 'Fan ', 'Kuang ', 'Ang ', 'Peng ', 'Bei ', 'Gu ', 'Ku ', 'Pao ', 'Zhu ', 'Rong ', 'E ', 'Ba ', 'Zhou ', 'Zhi ', 'Yao ', 'Ke ', 'Yi ', 'Qing ', 'Shi ', 'Ping '];
<?php return ['Er ', 'Qiong ', 'Ju ', 'Jiao ', 'Guang ', 'Lu ', 'Kai ', 'Quan ', 'Zhou ', 'Zai ', 'Zhi ', 'She ', 'Liang ', 'Yu ', 'Shao ', 'You ', 'Huan ', 'Yun ', 'Zhe ', 'Wan ', 'Fu ', 'Qing ', 'Zhou ', 'Ni ', 'Ling ', 'Zhe ', 'Zhan ', 'Liang ', 'Zi ', 'Hui ', 'Wang ', 'Chuo ', 'Guo ', 'Kan ', 'Yi ', 'Peng ', 'Qian ', 'Gun ', 'Nian ', 'Pian ', 'Guan ', 'Bei ', 'Lun ', 'Pai ', 'Liang ', 'Ruan ', 'Rou ', 'Ji ', 'Yang ', 'Xian ', 'Chuan ', 'Cou ', 'Qun ', 'Ge ', 'You ', 'Hong ', 'Shu ', 'Fu ', 'Zi ', 'Fu ', 'Wen ', 'Ben ', 'Zhan ', 'Yu ', 'Wen ', 'Tao ', 'Gu ', 'Zhen ', 'Xia ', 'Yuan ', 'Lu ', 'Jiu ', 'Chao ', 'Zhuan ', 'Wei ', 'Hun ', 'Sori ', 'Che ', 'Jiao ', 'Zhan ', 'Pu ', 'Lao ', 'Fen ', 'Fan ', 'Lin ', 'Ge ', 'Se ', 'Kan ', 'Huan ', 'Yi ', 'Ji ', 'Dui ', 'Er ', 'Yu ', 'Xian ', 'Hong ', 'Lei ', 'Pei ', 'Li ', 'Li ', 'Lu ', 'Lin ', 'Che ', 'Ya ', 'Gui ', 'Xuan ', 'Di ', 'Ren ', 'Zhuan ', 'E ', 'Lun ', 'Ruan ', 'Hong ', 'Ku ', 'Ke ', 'Lu ', 'Zhou ', 'Zhi ', 'Yi ', 'Hu ', 'Zhen ', 'Li ', 'Yao ', 'Qing ', 'Shi ', 'Zai ', 'Zhi ', 'Jiao ', 'Zhou ', 'Quan ', 'Lu ', 'Jiao ', 'Zhe ', 'Fu ', 'Liang ', 'Nian ', 'Bei ', 'Hui ', 'Gun ', 'Wang ', 'Liang ', 'Chuo ', 'Zi ', 'Cou ', 'Fu ', 'Ji ', 'Wen ', 'Shu ', 'Pei ', 'Yuan ', 'Xia ', 'Zhan ', 'Lu ', 'Che ', 'Lin ', 'Xin ', 'Gu ', 'Ci ', 'Ci ', 'Pi ', 'Zui ', 'Bian ', 'La ', 'La ', 'Ci ', 'Xue ', 'Ban ', 'Bian ', 'Bian ', 'Bian ', '[?] ', 'Bian ', 'Ban ', 'Ci ', 'Bian ', 'Bian ', 'Chen ', 'Ru ', 'Nong ', 'Nong ', 'Zhen ', 'Chuo ', 'Chuo ', 'Suberu ', 'Reng ', 'Bian ', 'Bian ', 'Sip ', 'Ip ', 'Liao ', 'Da ', 'Chan ', 'Gan ', 'Qian ', 'Yu ', 'Yu ', 'Qi ', 'Xun ', 'Yi ', 'Guo ', 'Mai ', 'Qi ', 'Za ', 'Wang ', 'Jia ', 'Zhun ', 'Ying ', 'Ti ', 'Yun ', 'Jin ', 'Hang ', 'Ya ', 'Fan ', 'Wu ', 'Da ', 'E ', 'Huan ', 'Zhe ', 'Totemo ', 'Jin ', 'Yuan ', 'Wei ', 'Lian ', 'Chi ', 'Che ', 'Ni ', 'Tiao ', 'Zhi ', 'Yi ', 'Jiong ', 'Jia ', 'Chen ', 'Dai ', 'Er ', 'Di ', 'Po ', 'Wang ', 'Die ', 'Ze ', 'Tao ', 'Shu ', 'Tuo ', 'Kep ', 'Jing ', 'Hui ', 'Tong ', 'You ', 'Mi ', 'Beng ', 'Ji ', 'Nai ', 'Yi ', 'Jie ', 'Zhui ', 'Lie ', 'Xun '];
<?php return ['Tui ', 'Song ', 'Gua ', 'Tao ', 'Pang ', 'Hou ', 'Ni ', 'Dun ', 'Jiong ', 'Xuan ', 'Xun ', 'Bu ', 'You ', 'Xiao ', 'Qiu ', 'Tou ', 'Zhu ', 'Qiu ', 'Di ', 'Di ', 'Tu ', 'Jing ', 'Ti ', 'Dou ', 'Yi ', 'Zhe ', 'Tong ', 'Guang ', 'Wu ', 'Shi ', 'Cheng ', 'Su ', 'Zao ', 'Qun ', 'Feng ', 'Lian ', 'Suo ', 'Hui ', 'Li ', 'Sako ', 'Lai ', 'Ben ', 'Cuo ', 'Jue ', 'Beng ', 'Huan ', 'Dai ', 'Lu ', 'You ', 'Zhou ', 'Jin ', 'Yu ', 'Chuo ', 'Kui ', 'Wei ', 'Ti ', 'Yi ', 'Da ', 'Yuan ', 'Luo ', 'Bi ', 'Nuo ', 'Yu ', 'Dang ', 'Sui ', 'Dun ', 'Sui ', 'Yan ', 'Chuan ', 'Chi ', 'Ti ', 'Yu ', 'Shi ', 'Zhen ', 'You ', 'Yun ', 'E ', 'Bian ', 'Guo ', 'E ', 'Xia ', 'Huang ', 'Qiu ', 'Dao ', 'Da ', 'Wei ', 'Appare ', 'Yi ', 'Gou ', 'Yao ', 'Chu ', 'Liu ', 'Xun ', 'Ta ', 'Di ', 'Chi ', 'Yuan ', 'Su ', 'Ta ', 'Qian ', '[?] ', 'Yao ', 'Guan ', 'Zhang ', 'Ao ', 'Shi ', 'Ce ', 'Chi ', 'Su ', 'Zao ', 'Zhe ', 'Dun ', 'Di ', 'Lou ', 'Chi ', 'Cuo ', 'Lin ', 'Zun ', 'Rao ', 'Qian ', 'Xuan ', 'Yu ', 'Yi ', 'Wu ', 'Liao ', 'Ju ', 'Shi ', 'Bi ', 'Yao ', 'Mai ', 'Xie ', 'Sui ', 'Huan ', 'Zhan ', 'Teng ', 'Er ', 'Miao ', 'Bian ', 'Bian ', 'La ', 'Li ', 'Yuan ', 'Yao ', 'Luo ', 'Li ', 'Yi ', 'Ting ', 'Deng ', 'Qi ', 'Yong ', 'Shan ', 'Han ', 'Yu ', 'Mang ', 'Ru ', 'Qiong ', '[?] ', 'Kuang ', 'Fu ', 'Kang ', 'Bin ', 'Fang ', 'Xing ', 'Na ', 'Xin ', 'Shen ', 'Bang ', 'Yuan ', 'Cun ', 'Huo ', 'Xie ', 'Bang ', 'Wu ', 'Ju ', 'You ', 'Han ', 'Tai ', 'Qiu ', 'Bi ', 'Pei ', 'Bing ', 'Shao ', 'Bei ', 'Wa ', 'Di ', 'Zou ', 'Ye ', 'Lin ', 'Kuang ', 'Gui ', 'Zhu ', 'Shi ', 'Ku ', 'Yu ', 'Gai ', 'Ge ', 'Xi ', 'Zhi ', 'Ji ', 'Xun ', 'Hou ', 'Xing ', 'Jiao ', 'Xi ', 'Gui ', 'Nuo ', 'Lang ', 'Jia ', 'Kuai ', 'Zheng ', 'Otoko ', 'Yun ', 'Yan ', 'Cheng ', 'Dou ', 'Chi ', 'Lu ', 'Fu ', 'Wu ', 'Fu ', 'Gao ', 'Hao ', 'Lang ', 'Jia ', 'Geng ', 'Jun ', 'Ying ', 'Bo ', 'Xi ', 'Bei ', 'Li ', 'Yun ', 'Bu ', 'Xiao ', 'Qi ', 'Pi ', 'Qing ', 'Guo ', 'Zhou ', 'Tan ', 'Zou ', 'Ping ', 'Lai ', 'Ni ', 'Chen ', 'You ', 'Bu ', 'Xiang ', 'Dan ', 'Ju ', 'Yong ', 'Qiao ', 'Yi ', 'Du ', 'Yan ', 'Mei '];
<?php return ['Ruo ', 'Bei ', 'E ', 'Yu ', 'Juan ', 'Yu ', 'Yun ', 'Hou ', 'Kui ', 'Xiang ', 'Xiang ', 'Sou ', 'Tang ', 'Ming ', 'Xi ', 'Ru ', 'Chu ', 'Zi ', 'Zou ', 'Ju ', 'Wu ', 'Xiang ', 'Yun ', 'Hao ', 'Yong ', 'Bi ', 'Mo ', 'Chao ', 'Fu ', 'Liao ', 'Yin ', 'Zhuan ', 'Hu ', 'Qiao ', 'Yan ', 'Zhang ', 'Fan ', 'Qiao ', 'Xu ', 'Deng ', 'Bi ', 'Xin ', 'Bi ', 'Ceng ', 'Wei ', 'Zheng ', 'Mao ', 'Shan ', 'Lin ', 'Po ', 'Dan ', 'Meng ', 'Ye ', 'Cao ', 'Kuai ', 'Feng ', 'Meng ', 'Zou ', 'Kuang ', 'Lian ', 'Zan ', 'Chan ', 'You ', 'Qi ', 'Yan ', 'Chan ', 'Zan ', 'Ling ', 'Huan ', 'Xi ', 'Feng ', 'Zan ', 'Li ', 'You ', 'Ding ', 'Qiu ', 'Zhuo ', 'Pei ', 'Zhou ', 'Yi ', 'Hang ', 'Yu ', 'Jiu ', 'Yan ', 'Zui ', 'Mao ', 'Dan ', 'Xu ', 'Tou ', 'Zhen ', 'Fen ', 'Sakenomoto ', '[?] ', 'Yun ', 'Tai ', 'Tian ', 'Qia ', 'Tuo ', 'Zuo ', 'Han ', 'Gu ', 'Su ', 'Po ', 'Chou ', 'Zai ', 'Ming ', 'Luo ', 'Chuo ', 'Chou ', 'You ', 'Tong ', 'Zhi ', 'Xian ', 'Jiang ', 'Cheng ', 'Yin ', 'Tu ', 'Xiao ', 'Mei ', 'Ku ', 'Suan ', 'Lei ', 'Pu ', 'Zui ', 'Hai ', 'Yan ', 'Xi ', 'Niang ', 'Wei ', 'Lu ', 'Lan ', 'Yan ', 'Tao ', 'Pei ', 'Zhan ', 'Chun ', 'Tan ', 'Zui ', 'Chuo ', 'Cu ', 'Kun ', 'Ti ', 'Mian ', 'Du ', 'Hu ', 'Xu ', 'Xing ', 'Tan ', 'Jiu ', 'Chun ', 'Yun ', 'Po ', 'Ke ', 'Sou ', 'Mi ', 'Quan ', 'Chou ', 'Cuo ', 'Yun ', 'Yong ', 'Ang ', 'Zha ', 'Hai ', 'Tang ', 'Jiang ', 'Piao ', 'Shan ', 'Yu ', 'Li ', 'Zao ', 'Lao ', 'Yi ', 'Jiang ', 'Pu ', 'Jiao ', 'Xi ', 'Tan ', 'Po ', 'Nong ', 'Yi ', 'Li ', 'Ju ', 'Jiao ', 'Yi ', 'Niang ', 'Ru ', 'Xun ', 'Chou ', 'Yan ', 'Ling ', 'Mi ', 'Mi ', 'Niang ', 'Xin ', 'Jiao ', 'Xi ', 'Mi ', 'Yan ', 'Bian ', 'Cai ', 'Shi ', 'You ', 'Shi ', 'Shi ', 'Li ', 'Zhong ', 'Ye ', 'Liang ', 'Li ', 'Jin ', 'Jin ', 'Qiu ', 'Yi ', 'Diao ', 'Dao ', 'Zhao ', 'Ding ', 'Po ', 'Qiu ', 'He ', 'Fu ', 'Zhen ', 'Zhi ', 'Ba ', 'Luan ', 'Fu ', 'Nai ', 'Diao ', 'Shan ', 'Qiao ', 'Kou ', 'Chuan ', 'Zi ', 'Fan ', 'Yu ', 'Hua ', 'Han ', 'Gong ', 'Qi ', 'Mang ', 'Ri ', 'Di ', 'Si ', 'Xi ', 'Yi ', 'Chai ', 'Shi ', 'Tu ', 'Xi ', 'Nu ', 'Qian ', 'Ishiyumi ', 'Jian ', 'Pi ', 'Ye ', 'Yin '];
<?php return ['Ba ', 'Fang ', 'Chen ', 'Xing ', 'Tou ', 'Yue ', 'Yan ', 'Fu ', 'Pi ', 'Na ', 'Xin ', 'E ', 'Jue ', 'Dun ', 'Gou ', 'Yin ', 'Qian ', 'Ban ', 'Ji ', 'Ren ', 'Chao ', 'Niu ', 'Fen ', 'Yun ', 'Ji ', 'Qin ', 'Pi ', 'Guo ', 'Hong ', 'Yin ', 'Jun ', 'Shi ', 'Yi ', 'Zhong ', 'Nie ', 'Gai ', 'Ri ', 'Huo ', 'Tai ', 'Kang ', 'Habaki ', 'Irori ', 'Ngaak ', '[?] ', 'Duo ', 'Zi ', 'Ni ', 'Tu ', 'Shi ', 'Min ', 'Gu ', 'E ', 'Ling ', 'Bing ', 'Yi ', 'Gu ', 'Ba ', 'Pi ', 'Yu ', 'Si ', 'Zuo ', 'Bu ', 'You ', 'Dian ', 'Jia ', 'Zhen ', 'Shi ', 'Shi ', 'Tie ', 'Ju ', 'Zhan ', 'Shi ', 'She ', 'Xuan ', 'Zhao ', 'Bao ', 'He ', 'Bi ', 'Sheng ', 'Chu ', 'Shi ', 'Bo ', 'Zhu ', 'Chi ', 'Za ', 'Po ', 'Tong ', 'Qian ', 'Fu ', 'Zhai ', 'Liu ', 'Qian ', 'Fu ', 'Li ', 'Yue ', 'Pi ', 'Yang ', 'Ban ', 'Bo ', 'Jie ', 'Gou ', 'Shu ', 'Zheng ', 'Mu ', 'Ni ', 'Nie ', 'Di ', 'Jia ', 'Mu ', 'Dan ', 'Shen ', 'Yi ', 'Si ', 'Kuang ', 'Ka ', 'Bei ', 'Jian ', 'Tong ', 'Xing ', 'Hong ', 'Jiao ', 'Chi ', 'Er ', 'Ge ', 'Bing ', 'Shi ', 'Mou ', 'Jia ', 'Yin ', 'Jun ', 'Zhou ', 'Chong ', 'Shang ', 'Tong ', 'Mo ', 'Lei ', 'Ji ', 'Yu ', 'Xu ', 'Ren ', 'Zun ', 'Zhi ', 'Qiong ', 'Shan ', 'Chi ', 'Xian ', 'Xing ', 'Quan ', 'Pi ', 'Tie ', 'Zhu ', 'Hou ', 'Ming ', 'Kua ', 'Yao ', 'Xian ', 'Xian ', 'Xiu ', 'Jun ', 'Cha ', 'Lao ', 'Ji ', 'Pi ', 'Ru ', 'Mi ', 'Yi ', 'Yin ', 'Guang ', 'An ', 'Diou ', 'You ', 'Se ', 'Kao ', 'Qian ', 'Luan ', 'Kasugai ', 'Ai ', 'Diao ', 'Han ', 'Rui ', 'Shi ', 'Keng ', 'Qiu ', 'Xiao ', 'Zhe ', 'Xiu ', 'Zang ', 'Ti ', 'Cuo ', 'Gua ', 'Gong ', 'Zhong ', 'Dou ', 'Lu ', 'Mei ', 'Lang ', 'Wan ', 'Xin ', 'Yun ', 'Bei ', 'Wu ', 'Su ', 'Yu ', 'Chan ', 'Ting ', 'Bo ', 'Han ', 'Jia ', 'Hong ', 'Cuan ', 'Feng ', 'Chan ', 'Wan ', 'Zhi ', 'Si ', 'Xuan ', 'Wu ', 'Wu ', 'Tiao ', 'Gong ', 'Zhuo ', 'Lue ', 'Xing ', 'Qian ', 'Shen ', 'Han ', 'Lue ', 'Xie ', 'Chu ', 'Zheng ', 'Ju ', 'Xian ', 'Tie ', 'Mang ', 'Pu ', 'Li ', 'Pan ', 'Rui ', 'Cheng ', 'Gao ', 'Li ', 'Te ', 'Pyeng ', 'Zhu ', '[?] ', 'Tu ', 'Liu ', 'Zui ', 'Ju ', 'Chang ', 'Yuan ', 'Jian ', 'Gang ', 'Diao ', 'Tao ', 'Chang '];
<?php return ['Lun ', 'Kua ', 'Ling ', 'Bei ', 'Lu ', 'Li ', 'Qiang ', 'Pou ', 'Juan ', 'Min ', 'Zui ', 'Peng ', 'An ', 'Pi ', 'Xian ', 'Ya ', 'Zhui ', 'Lei ', 'A ', 'Kong ', 'Ta ', 'Kun ', 'Du ', 'Wei ', 'Chui ', 'Zi ', 'Zheng ', 'Ben ', 'Nie ', 'Cong ', 'Qun ', 'Tan ', 'Ding ', 'Qi ', 'Qian ', 'Zhuo ', 'Qi ', 'Yu ', 'Jin ', 'Guan ', 'Mao ', 'Chang ', 'Tian ', 'Xi ', 'Lian ', 'Tao ', 'Gu ', 'Cuo ', 'Shu ', 'Zhen ', 'Lu ', 'Meng ', 'Lu ', 'Hua ', 'Biao ', 'Ga ', 'Lai ', 'Ken ', 'Kazari ', 'Bu ', 'Nai ', 'Wan ', 'Zan ', '[?] ', 'De ', 'Xian ', '[?] ', 'Huo ', 'Liang ', '[?] ', 'Men ', 'Kai ', 'Ying ', 'Di ', 'Lian ', 'Guo ', 'Xian ', 'Du ', 'Tu ', 'Wei ', 'Cong ', 'Fu ', 'Rou ', 'Ji ', 'E ', 'Rou ', 'Chen ', 'Ti ', 'Zha ', 'Hong ', 'Yang ', 'Duan ', 'Xia ', 'Yu ', 'Keng ', 'Xing ', 'Huang ', 'Wei ', 'Fu ', 'Zhao ', 'Cha ', 'Qie ', 'She ', 'Hong ', 'Kui ', 'Tian ', 'Mou ', 'Qiao ', 'Qiao ', 'Hou ', 'Tou ', 'Cong ', 'Huan ', 'Ye ', 'Min ', 'Jian ', 'Duan ', 'Jian ', 'Song ', 'Kui ', 'Hu ', 'Xuan ', 'Duo ', 'Jie ', 'Zhen ', 'Bian ', 'Zhong ', 'Zi ', 'Xiu ', 'Ye ', 'Mei ', 'Pai ', 'Ai ', 'Jie ', '[?] ', 'Mei ', 'Chuo ', 'Ta ', 'Bang ', 'Xia ', 'Lian ', 'Suo ', 'Xi ', 'Liu ', 'Zu ', 'Ye ', 'Nou ', 'Weng ', 'Rong ', 'Tang ', 'Suo ', 'Qiang ', 'Ge ', 'Shuo ', 'Chui ', 'Bo ', 'Pan ', 'Sa ', 'Bi ', 'Sang ', 'Gang ', 'Zi ', 'Wu ', 'Ying ', 'Huang ', 'Tiao ', 'Liu ', 'Kai ', 'Sun ', 'Sha ', 'Sou ', 'Wan ', 'Hao ', 'Zhen ', 'Zhen ', 'Luo ', 'Yi ', 'Yuan ', 'Tang ', 'Nie ', 'Xi ', 'Jia ', 'Ge ', 'Ma ', 'Juan ', 'Kasugai ', 'Habaki ', 'Suo ', '[?] ', '[?] ', '[?] ', 'Na ', 'Lu ', 'Suo ', 'Ou ', 'Zu ', 'Tuan ', 'Xiu ', 'Guan ', 'Xuan ', 'Lian ', 'Shou ', 'Ao ', 'Man ', 'Mo ', 'Luo ', 'Bi ', 'Wei ', 'Liu ', 'Di ', 'Qiao ', 'Cong ', 'Yi ', 'Lu ', 'Ao ', 'Keng ', 'Qiang ', 'Cui ', 'Qi ', 'Chang ', 'Tang ', 'Man ', 'Yong ', 'Chan ', 'Feng ', 'Jing ', 'Biao ', 'Shu ', 'Lou ', 'Xiu ', 'Cong ', 'Long ', 'Zan ', 'Jian ', 'Cao ', 'Li ', 'Xia ', 'Xi ', 'Kang ', '[?] ', 'Beng ', '[?] ', '[?] ', 'Zheng ', 'Lu ', 'Hua ', 'Ji ', 'Pu ', 'Hui ', 'Qiang ', 'Po ', 'Lin ', 'Suo ', 'Xiu ', 'San ', 'Cheng '];
<?php return ['Kui ', 'Si ', 'Liu ', 'Nao ', 'Heng ', 'Pie ', 'Sui ', 'Fan ', 'Qiao ', 'Quan ', 'Yang ', 'Tang ', 'Xiang ', 'Jue ', 'Jiao ', 'Zun ', 'Liao ', 'Jie ', 'Lao ', 'Dui ', 'Tan ', 'Zan ', 'Ji ', 'Jian ', 'Zhong ', 'Deng ', 'Ya ', 'Ying ', 'Dui ', 'Jue ', 'Nou ', 'Ti ', 'Pu ', 'Tie ', '[?] ', '[?] ', 'Ding ', 'Shan ', 'Kai ', 'Jian ', 'Fei ', 'Sui ', 'Lu ', 'Juan ', 'Hui ', 'Yu ', 'Lian ', 'Zhuo ', 'Qiao ', 'Qian ', 'Zhuo ', 'Lei ', 'Bi ', 'Tie ', 'Huan ', 'Ye ', 'Duo ', 'Guo ', 'Dang ', 'Ju ', 'Fen ', 'Da ', 'Bei ', 'Yi ', 'Ai ', 'Zong ', 'Xun ', 'Diao ', 'Zhu ', 'Heng ', 'Zhui ', 'Ji ', 'Nie ', 'Ta ', 'Huo ', 'Qing ', 'Bin ', 'Ying ', 'Kui ', 'Ning ', 'Xu ', 'Jian ', 'Jian ', 'Yari ', 'Cha ', 'Zhi ', 'Mie ', 'Li ', 'Lei ', 'Ji ', 'Zuan ', 'Kuang ', 'Shang ', 'Peng ', 'La ', 'Du ', 'Shuo ', 'Chuo ', 'Lu ', 'Biao ', 'Bao ', 'Lu ', '[?] ', '[?] ', 'Long ', 'E ', 'Lu ', 'Xin ', 'Jian ', 'Lan ', 'Bo ', 'Jian ', 'Yao ', 'Chan ', 'Xiang ', 'Jian ', 'Xi ', 'Guan ', 'Cang ', 'Nie ', 'Lei ', 'Cuan ', 'Qu ', 'Pan ', 'Luo ', 'Zuan ', 'Luan ', 'Zao ', 'Nie ', 'Jue ', 'Tang ', 'Shu ', 'Lan ', 'Jin ', 'Qiu ', 'Yi ', 'Zhen ', 'Ding ', 'Zhao ', 'Po ', 'Diao ', 'Tu ', 'Qian ', 'Chuan ', 'Shan ', 'Ji ', 'Fan ', 'Diao ', 'Men ', 'Nu ', 'Xi ', 'Chai ', 'Xing ', 'Gai ', 'Bu ', 'Tai ', 'Ju ', 'Dun ', 'Chao ', 'Zhong ', 'Na ', 'Bei ', 'Gang ', 'Ban ', 'Qian ', 'Yao ', 'Qin ', 'Jun ', 'Wu ', 'Gou ', 'Kang ', 'Fang ', 'Huo ', 'Tou ', 'Niu ', 'Ba ', 'Yu ', 'Qian ', 'Zheng ', 'Qian ', 'Gu ', 'Bo ', 'E ', 'Po ', 'Bu ', 'Ba ', 'Yue ', 'Zuan ', 'Mu ', 'Dan ', 'Jia ', 'Dian ', 'You ', 'Tie ', 'Bo ', 'Ling ', 'Shuo ', 'Qian ', 'Liu ', 'Bao ', 'Shi ', 'Xuan ', 'She ', 'Bi ', 'Ni ', 'Pi ', 'Duo ', 'Xing ', 'Kao ', 'Lao ', 'Er ', 'Mang ', 'Ya ', 'You ', 'Cheng ', 'Jia ', 'Ye ', 'Nao ', 'Zhi ', 'Dang ', 'Tong ', 'Lu ', 'Diao ', 'Yin ', 'Kai ', 'Zha ', 'Zhu ', 'Xian ', 'Ting ', 'Diu ', 'Xian ', 'Hua ', 'Quan ', 'Sha ', 'Jia ', 'Yao ', 'Ge ', 'Ming ', 'Zheng ', 'Se ', 'Jiao ', 'Yi ', 'Chan ', 'Chong ', 'Tang ', 'An ', 'Yin ', 'Ru ', 'Zhu ', 'Lao ', 'Pu ', 'Wu ', 'Lai ', 'Te ', 'Lian ', 'Keng '];
<?php return ['Xiao ', 'Suo ', 'Li ', 'Zheng ', 'Chu ', 'Guo ', 'Gao ', 'Tie ', 'Xiu ', 'Cuo ', 'Lue ', 'Feng ', 'Xin ', 'Liu ', 'Kai ', 'Jian ', 'Rui ', 'Ti ', 'Lang ', 'Qian ', 'Ju ', 'A ', 'Qiang ', 'Duo ', 'Tian ', 'Cuo ', 'Mao ', 'Ben ', 'Qi ', 'De ', 'Kua ', 'Kun ', 'Chang ', 'Xi ', 'Gu ', 'Luo ', 'Chui ', 'Zhui ', 'Jin ', 'Zhi ', 'Xian ', 'Juan ', 'Huo ', 'Pou ', 'Tan ', 'Ding ', 'Jian ', 'Ju ', 'Meng ', 'Zi ', 'Qie ', 'Ying ', 'Kai ', 'Qiang ', 'Song ', 'E ', 'Cha ', 'Qiao ', 'Zhong ', 'Duan ', 'Sou ', 'Huang ', 'Huan ', 'Ai ', 'Du ', 'Mei ', 'Lou ', 'Zi ', 'Fei ', 'Mei ', 'Mo ', 'Zhen ', 'Bo ', 'Ge ', 'Nie ', 'Tang ', 'Juan ', 'Nie ', 'Na ', 'Liu ', 'Hao ', 'Bang ', 'Yi ', 'Jia ', 'Bin ', 'Rong ', 'Biao ', 'Tang ', 'Man ', 'Luo ', 'Beng ', 'Yong ', 'Jing ', 'Di ', 'Zu ', 'Xuan ', 'Liu ', 'Tan ', 'Jue ', 'Liao ', 'Pu ', 'Lu ', 'Dui ', 'Lan ', 'Pu ', 'Cuan ', 'Qiang ', 'Deng ', 'Huo ', 'Lei ', 'Huan ', 'Zhuo ', 'Lian ', 'Yi ', 'Cha ', 'Biao ', 'La ', 'Chan ', 'Xiang ', 'Chang ', 'Chang ', 'Jiu ', 'Ao ', 'Die ', 'Qu ', 'Liao ', 'Mi ', 'Chang ', 'Men ', 'Ma ', 'Shuan ', 'Shan ', 'Huo ', 'Men ', 'Yan ', 'Bi ', 'Han ', 'Bi ', 'San ', 'Kai ', 'Kang ', 'Beng ', 'Hong ', 'Run ', 'San ', 'Xian ', 'Xian ', 'Jian ', 'Min ', 'Xia ', 'Yuru ', 'Dou ', 'Zha ', 'Nao ', 'Jian ', 'Peng ', 'Xia ', 'Ling ', 'Bian ', 'Bi ', 'Run ', 'He ', 'Guan ', 'Ge ', 'Ge ', 'Fa ', 'Chu ', 'Hong ', 'Gui ', 'Min ', 'Se ', 'Kun ', 'Lang ', 'Lu ', 'Ting ', 'Sha ', 'Ju ', 'Yue ', 'Yue ', 'Chan ', 'Qu ', 'Lin ', 'Chang ', 'Shai ', 'Kun ', 'Yan ', 'Min ', 'Yan ', 'E ', 'Hun ', 'Yu ', 'Wen ', 'Xiang ', 'Bao ', 'Xiang ', 'Qu ', 'Yao ', 'Wen ', 'Ban ', 'An ', 'Wei ', 'Yin ', 'Kuo ', 'Que ', 'Lan ', 'Du ', '[?] ', 'Phwung ', 'Tian ', 'Nie ', 'Ta ', 'Kai ', 'He ', 'Que ', 'Chuang ', 'Guan ', 'Dou ', 'Qi ', 'Kui ', 'Tang ', 'Guan ', 'Piao ', 'Kan ', 'Xi ', 'Hui ', 'Chan ', 'Pi ', 'Dang ', 'Huan ', 'Ta ', 'Wen ', '[?] ', 'Men ', 'Shuan ', 'Shan ', 'Yan ', 'Han ', 'Bi ', 'Wen ', 'Chuang ', 'Run ', 'Wei ', 'Xian ', 'Hong ', 'Jian ', 'Min ', 'Kang ', 'Men ', 'Zha ', 'Nao ', 'Gui ', 'Wen ', 'Ta ', 'Min ', 'Lu ', 'Kai '];
<?php return ['Fa ', 'Ge ', 'He ', 'Kun ', 'Jiu ', 'Yue ', 'Lang ', 'Du ', 'Yu ', 'Yan ', 'Chang ', 'Xi ', 'Wen ', 'Hun ', 'Yan ', 'E ', 'Chan ', 'Lan ', 'Qu ', 'Hui ', 'Kuo ', 'Que ', 'Ge ', 'Tian ', 'Ta ', 'Que ', 'Kan ', 'Huan ', 'Fu ', 'Fu ', 'Le ', 'Dui ', 'Xin ', 'Qian ', 'Wu ', 'Yi ', 'Tuo ', 'Yin ', 'Yang ', 'Dou ', 'E ', 'Sheng ', 'Ban ', 'Pei ', 'Keng ', 'Yun ', 'Ruan ', 'Zhi ', 'Pi ', 'Jing ', 'Fang ', 'Yang ', 'Yin ', 'Zhen ', 'Jie ', 'Cheng ', 'E ', 'Qu ', 'Di ', 'Zu ', 'Zuo ', 'Dian ', 'Ling ', 'A ', 'Tuo ', 'Tuo ', 'Po ', 'Bing ', 'Fu ', 'Ji ', 'Lu ', 'Long ', 'Chen ', 'Xing ', 'Duo ', 'Lou ', 'Mo ', 'Jiang ', 'Shu ', 'Duo ', 'Xian ', 'Er ', 'Gui ', 'Yu ', 'Gai ', 'Shan ', 'Xun ', 'Qiao ', 'Xing ', 'Chun ', 'Fu ', 'Bi ', 'Xia ', 'Shan ', 'Sheng ', 'Zhi ', 'Pu ', 'Dou ', 'Yuan ', 'Zhen ', 'Chu ', 'Xian ', 'Tou ', 'Nie ', 'Yun ', 'Xian ', 'Pei ', 'Pei ', 'Zou ', 'Yi ', 'Dui ', 'Lun ', 'Yin ', 'Ju ', 'Chui ', 'Chen ', 'Pi ', 'Ling ', 'Tao ', 'Xian ', 'Lu ', 'Sheng ', 'Xian ', 'Yin ', 'Zhu ', 'Yang ', 'Reng ', 'Shan ', 'Chong ', 'Yan ', 'Yin ', 'Yu ', 'Ti ', 'Yu ', 'Long ', 'Wei ', 'Wei ', 'Nie ', 'Dui ', 'Sui ', 'An ', 'Huang ', 'Jie ', 'Sui ', 'Yin ', 'Gai ', 'Yan ', 'Hui ', 'Ge ', 'Yun ', 'Wu ', 'Wei ', 'Ai ', 'Xi ', 'Tang ', 'Ji ', 'Zhang ', 'Dao ', 'Ao ', 'Xi ', 'Yin ', '[?] ', 'Rao ', 'Lin ', 'Tui ', 'Deng ', 'Pi ', 'Sui ', 'Sui ', 'Yu ', 'Xian ', 'Fen ', 'Ni ', 'Er ', 'Ji ', 'Dao ', 'Xi ', 'Yin ', 'E ', 'Hui ', 'Long ', 'Xi ', 'Li ', 'Li ', 'Li ', 'Zhui ', 'He ', 'Zhi ', 'Zhun ', 'Jun ', 'Nan ', 'Yi ', 'Que ', 'Yan ', 'Qian ', 'Ya ', 'Xiong ', 'Ya ', 'Ji ', 'Gu ', 'Huan ', 'Zhi ', 'Gou ', 'Jun ', 'Ci ', 'Yong ', 'Ju ', 'Chu ', 'Hu ', 'Za ', 'Luo ', 'Yu ', 'Chou ', 'Diao ', 'Sui ', 'Han ', 'Huo ', 'Shuang ', 'Guan ', 'Chu ', 'Za ', 'Yong ', 'Ji ', 'Xi ', 'Chou ', 'Liu ', 'Li ', 'Nan ', 'Xue ', 'Za ', 'Ji ', 'Ji ', 'Yu ', 'Yu ', 'Xue ', 'Na ', 'Fou ', 'Se ', 'Mu ', 'Wen ', 'Fen ', 'Pang ', 'Yun ', 'Li ', 'Li ', 'Ang ', 'Ling ', 'Lei ', 'An ', 'Bao ', 'Meng ', 'Dian ', 'Dang ', 'Xing ', 'Wu ', 'Zhao '];
<?php return ['Xu ', 'Ji ', 'Mu ', 'Chen ', 'Xiao ', 'Zha ', 'Ting ', 'Zhen ', 'Pei ', 'Mei ', 'Ling ', 'Qi ', 'Chou ', 'Huo ', 'Sha ', 'Fei ', 'Weng ', 'Zhan ', 'Yin ', 'Ni ', 'Chou ', 'Tun ', 'Lin ', '[?] ', 'Dong ', 'Ying ', 'Wu ', 'Ling ', 'Shuang ', 'Ling ', 'Xia ', 'Hong ', 'Yin ', 'Mo ', 'Mai ', 'Yun ', 'Liu ', 'Meng ', 'Bin ', 'Wu ', 'Wei ', 'Huo ', 'Yin ', 'Xi ', 'Yi ', 'Ai ', 'Dan ', 'Deng ', 'Xian ', 'Yu ', 'Lu ', 'Long ', 'Dai ', 'Ji ', 'Pang ', 'Yang ', 'Ba ', 'Pi ', 'Wei ', '[?] ', 'Xi ', 'Ji ', 'Mai ', 'Meng ', 'Meng ', 'Lei ', 'Li ', 'Huo ', 'Ai ', 'Fei ', 'Dai ', 'Long ', 'Ling ', 'Ai ', 'Feng ', 'Li ', 'Bao ', '[?] ', 'He ', 'He ', 'Bing ', 'Qing ', 'Qing ', 'Jing ', 'Tian ', 'Zhen ', 'Jing ', 'Cheng ', 'Qing ', 'Jing ', 'Jing ', 'Dian ', 'Jing ', 'Tian ', 'Fei ', 'Fei ', 'Kao ', 'Mi ', 'Mian ', 'Mian ', 'Pao ', 'Ye ', 'Tian ', 'Hui ', 'Ye ', 'Ge ', 'Ding ', 'Cha ', 'Jian ', 'Ren ', 'Di ', 'Du ', 'Wu ', 'Ren ', 'Qin ', 'Jin ', 'Xue ', 'Niu ', 'Ba ', 'Yin ', 'Sa ', 'Na ', 'Mo ', 'Zu ', 'Da ', 'Ban ', 'Yi ', 'Yao ', 'Tao ', 'Tuo ', 'Jia ', 'Hong ', 'Pao ', 'Yang ', 'Tomo ', 'Yin ', 'Jia ', 'Tao ', 'Ji ', 'Xie ', 'An ', 'An ', 'Hen ', 'Gong ', 'Kohaze ', 'Da ', 'Qiao ', 'Ting ', 'Wan ', 'Ying ', 'Sui ', 'Tiao ', 'Qiao ', 'Xuan ', 'Kong ', 'Beng ', 'Ta ', 'Zhang ', 'Bing ', 'Kuo ', 'Ju ', 'La ', 'Xie ', 'Rou ', 'Bang ', 'Yi ', 'Qiu ', 'Qiu ', 'He ', 'Xiao ', 'Mu ', 'Ju ', 'Jian ', 'Bian ', 'Di ', 'Jian ', 'On ', 'Tao ', 'Gou ', 'Ta ', 'Bei ', 'Xie ', 'Pan ', 'Ge ', 'Bi ', 'Kuo ', 'Tang ', 'Lou ', 'Gui ', 'Qiao ', 'Xue ', 'Ji ', 'Jian ', 'Jiang ', 'Chan ', 'Da ', 'Huo ', 'Xian ', 'Qian ', 'Du ', 'Wa ', 'Jian ', 'Lan ', 'Wei ', 'Ren ', 'Fu ', 'Mei ', 'Juan ', 'Ge ', 'Wei ', 'Qiao ', 'Han ', 'Chang ', '[?] ', 'Rou ', 'Xun ', 'She ', 'Wei ', 'Ge ', 'Bei ', 'Tao ', 'Gou ', 'Yun ', '[?] ', 'Bi ', 'Wei ', 'Hui ', 'Du ', 'Wa ', 'Du ', 'Wei ', 'Ren ', 'Fu ', 'Han ', 'Wei ', 'Yun ', 'Tao ', 'Jiu ', 'Jiu ', 'Xian ', 'Xie ', 'Xian ', 'Ji ', 'Yin ', 'Za ', 'Yun ', 'Shao ', 'Le ', 'Peng ', 'Heng ', 'Ying ', 'Yun ', 'Peng ', 'Yin ', 'Yin ', 'Xiang '];
<?php return ['Hu ', 'Ye ', 'Ding ', 'Qing ', 'Pan ', 'Xiang ', 'Shun ', 'Han ', 'Xu ', 'Yi ', 'Xu ', 'Gu ', 'Song ', 'Kui ', 'Qi ', 'Hang ', 'Yu ', 'Wan ', 'Ban ', 'Dun ', 'Di ', 'Dan ', 'Pan ', 'Po ', 'Ling ', 'Ce ', 'Jing ', 'Lei ', 'He ', 'Qiao ', 'E ', 'E ', 'Wei ', 'Jie ', 'Gua ', 'Shen ', 'Yi ', 'Shen ', 'Hai ', 'Dui ', 'Pian ', 'Ping ', 'Lei ', 'Fu ', 'Jia ', 'Tou ', 'Hui ', 'Kui ', 'Jia ', 'Le ', 'Tian ', 'Cheng ', 'Ying ', 'Jun ', 'Hu ', 'Han ', 'Jing ', 'Tui ', 'Tui ', 'Pin ', 'Lai ', 'Tui ', 'Zi ', 'Zi ', 'Chui ', 'Ding ', 'Lai ', 'Yan ', 'Han ', 'Jian ', 'Ke ', 'Cui ', 'Jiong ', 'Qin ', 'Yi ', 'Sai ', 'Ti ', 'E ', 'E ', 'Yan ', 'Hun ', 'Kan ', 'Yong ', 'Zhuan ', 'Yan ', 'Xian ', 'Xin ', 'Yi ', 'Yuan ', 'Sang ', 'Dian ', 'Dian ', 'Jiang ', 'Ku ', 'Lei ', 'Liao ', 'Piao ', 'Yi ', 'Man ', 'Qi ', 'Rao ', 'Hao ', 'Qiao ', 'Gu ', 'Xun ', 'Qian ', 'Hui ', 'Zhan ', 'Ru ', 'Hong ', 'Bin ', 'Xian ', 'Pin ', 'Lu ', 'Lan ', 'Nie ', 'Quan ', 'Ye ', 'Ding ', 'Qing ', 'Han ', 'Xiang ', 'Shun ', 'Xu ', 'Xu ', 'Wan ', 'Gu ', 'Dun ', 'Qi ', 'Ban ', 'Song ', 'Hang ', 'Yu ', 'Lu ', 'Ling ', 'Po ', 'Jing ', 'Jie ', 'Jia ', 'Tian ', 'Han ', 'Ying ', 'Jiong ', 'Hai ', 'Yi ', 'Pin ', 'Hui ', 'Tui ', 'Han ', 'Ying ', 'Ying ', 'Ke ', 'Ti ', 'Yong ', 'E ', 'Zhuan ', 'Yan ', 'E ', 'Nie ', 'Man ', 'Dian ', 'Sang ', 'Hao ', 'Lei ', 'Zhan ', 'Ru ', 'Pin ', 'Quan ', 'Feng ', 'Biao ', 'Oroshi ', 'Fu ', 'Xia ', 'Zhan ', 'Biao ', 'Sa ', 'Ba ', 'Tai ', 'Lie ', 'Gua ', 'Xuan ', 'Shao ', 'Ju ', 'Bi ', 'Si ', 'Wei ', 'Yang ', 'Yao ', 'Sou ', 'Kai ', 'Sao ', 'Fan ', 'Liu ', 'Xi ', 'Liao ', 'Piao ', 'Piao ', 'Liu ', 'Biao ', 'Biao ', 'Biao ', 'Liao ', '[?] ', 'Se ', 'Feng ', 'Biao ', 'Feng ', 'Yang ', 'Zhan ', 'Biao ', 'Sa ', 'Ju ', 'Si ', 'Sou ', 'Yao ', 'Liu ', 'Piao ', 'Biao ', 'Biao ', 'Fei ', 'Fan ', 'Fei ', 'Fei ', 'Shi ', 'Shi ', 'Can ', 'Ji ', 'Ding ', 'Si ', 'Tuo ', 'Zhan ', 'Sun ', 'Xiang ', 'Tun ', 'Ren ', 'Yu ', 'Juan ', 'Chi ', 'Yin ', 'Fan ', 'Fan ', 'Sun ', 'Yin ', 'Zhu ', 'Yi ', 'Zhai ', 'Bi ', 'Jie ', 'Tao ', 'Liu ', 'Ci ', 'Tie ', 'Si ', 'Bao ', 'Shi ', 'Duo '];
<?php return ['Hai ', 'Ren ', 'Tian ', 'Jiao ', 'Jia ', 'Bing ', 'Yao ', 'Tong ', 'Ci ', 'Xiang ', 'Yang ', 'Yang ', 'Er ', 'Yan ', 'Le ', 'Yi ', 'Can ', 'Bo ', 'Nei ', 'E ', 'Bu ', 'Jun ', 'Dou ', 'Su ', 'Yu ', 'Shi ', 'Yao ', 'Hun ', 'Guo ', 'Shi ', 'Jian ', 'Zhui ', 'Bing ', 'Xian ', 'Bu ', 'Ye ', 'Tan ', 'Fei ', 'Zhang ', 'Wei ', 'Guan ', 'E ', 'Nuan ', 'Hun ', 'Hu ', 'Huang ', 'Tie ', 'Hui ', 'Jian ', 'Hou ', 'He ', 'Xing ', 'Fen ', 'Wei ', 'Gu ', 'Cha ', 'Song ', 'Tang ', 'Bo ', 'Gao ', 'Xi ', 'Kui ', 'Liu ', 'Sou ', 'Tao ', 'Ye ', 'Yun ', 'Mo ', 'Tang ', 'Man ', 'Bi ', 'Yu ', 'Xiu ', 'Jin ', 'San ', 'Kui ', 'Zhuan ', 'Shan ', 'Chi ', 'Dan ', 'Yi ', 'Ji ', 'Rao ', 'Cheng ', 'Yong ', 'Tao ', 'Hui ', 'Xiang ', 'Zhan ', 'Fen ', 'Hai ', 'Meng ', 'Yan ', 'Mo ', 'Chan ', 'Xiang ', 'Luo ', 'Zuan ', 'Nang ', 'Shi ', 'Ding ', 'Ji ', 'Tuo ', 'Xing ', 'Tun ', 'Xi ', 'Ren ', 'Yu ', 'Chi ', 'Fan ', 'Yin ', 'Jian ', 'Shi ', 'Bao ', 'Si ', 'Duo ', 'Yi ', 'Er ', 'Rao ', 'Xiang ', 'Jia ', 'Le ', 'Jiao ', 'Yi ', 'Bing ', 'Bo ', 'Dou ', 'E ', 'Yu ', 'Nei ', 'Jun ', 'Guo ', 'Hun ', 'Xian ', 'Guan ', 'Cha ', 'Kui ', 'Gu ', 'Sou ', 'Chan ', 'Ye ', 'Mo ', 'Bo ', 'Liu ', 'Xiu ', 'Jin ', 'Man ', 'San ', 'Zhuan ', 'Nang ', 'Shou ', 'Kui ', 'Guo ', 'Xiang ', 'Fen ', 'Ba ', 'Ni ', 'Bi ', 'Bo ', 'Tu ', 'Han ', 'Fei ', 'Jian ', 'An ', 'Ai ', 'Fu ', 'Xian ', 'Wen ', 'Xin ', 'Fen ', 'Bin ', 'Xing ', 'Ma ', 'Yu ', 'Feng ', 'Han ', 'Di ', 'Tuo ', 'Tuo ', 'Chi ', 'Xun ', 'Zhu ', 'Zhi ', 'Pei ', 'Xin ', 'Ri ', 'Sa ', 'Yin ', 'Wen ', 'Zhi ', 'Dan ', 'Lu ', 'You ', 'Bo ', 'Bao ', 'Kuai ', 'Tuo ', 'Yi ', 'Qu ', '[?] ', 'Qu ', 'Jiong ', 'Bo ', 'Zhao ', 'Yuan ', 'Peng ', 'Zhou ', 'Ju ', 'Zhu ', 'Nu ', 'Ju ', 'Pi ', 'Zang ', 'Jia ', 'Ling ', 'Zhen ', 'Tai ', 'Fu ', 'Yang ', 'Shi ', 'Bi ', 'Tuo ', 'Tuo ', 'Si ', 'Liu ', 'Ma ', 'Pian ', 'Tao ', 'Zhi ', 'Rong ', 'Teng ', 'Dong ', 'Xun ', 'Quan ', 'Shen ', 'Jiong ', 'Er ', 'Hai ', 'Bo ', 'Zhu ', 'Yin ', 'Luo ', 'Shuu ', 'Dan ', 'Xie ', 'Liu ', 'Ju ', 'Song ', 'Qin ', 'Mang ', 'Liang ', 'Han ', 'Tu ', 'Xuan ', 'Tui ', 'Jun '];
<?php return ['E ', 'Cheng ', 'Xin ', 'Ai ', 'Lu ', 'Zhui ', 'Zhou ', 'She ', 'Pian ', 'Kun ', 'Tao ', 'Lai ', 'Zong ', 'Ke ', 'Qi ', 'Qi ', 'Yan ', 'Fei ', 'Sao ', 'Yan ', 'Jie ', 'Yao ', 'Wu ', 'Pian ', 'Cong ', 'Pian ', 'Qian ', 'Fei ', 'Huang ', 'Jian ', 'Huo ', 'Yu ', 'Ti ', 'Quan ', 'Xia ', 'Zong ', 'Kui ', 'Rou ', 'Si ', 'Gua ', 'Tuo ', 'Kui ', 'Sou ', 'Qian ', 'Cheng ', 'Zhi ', 'Liu ', 'Pang ', 'Teng ', 'Xi ', 'Cao ', 'Du ', 'Yan ', 'Yuan ', 'Zou ', 'Sao ', 'Shan ', 'Li ', 'Zhi ', 'Shuang ', 'Lu ', 'Xi ', 'Luo ', 'Zhang ', 'Mo ', 'Ao ', 'Can ', 'Piao ', 'Cong ', 'Qu ', 'Bi ', 'Zhi ', 'Yu ', 'Xu ', 'Hua ', 'Bo ', 'Su ', 'Xiao ', 'Lin ', 'Chan ', 'Dun ', 'Liu ', 'Tuo ', 'Zeng ', 'Tan ', 'Jiao ', 'Tie ', 'Yan ', 'Luo ', 'Zhan ', 'Jing ', 'Yi ', 'Ye ', 'Tuo ', 'Bin ', 'Zou ', 'Yan ', 'Peng ', 'Lu ', 'Teng ', 'Xiang ', 'Ji ', 'Shuang ', 'Ju ', 'Xi ', 'Huan ', 'Li ', 'Biao ', 'Ma ', 'Yu ', 'Tuo ', 'Xun ', 'Chi ', 'Qu ', 'Ri ', 'Bo ', 'Lu ', 'Zang ', 'Shi ', 'Si ', 'Fu ', 'Ju ', 'Zou ', 'Zhu ', 'Tuo ', 'Nu ', 'Jia ', 'Yi ', 'Tai ', 'Xiao ', 'Ma ', 'Yin ', 'Jiao ', 'Hua ', 'Luo ', 'Hai ', 'Pian ', 'Biao ', 'Li ', 'Cheng ', 'Yan ', 'Xin ', 'Qin ', 'Jun ', 'Qi ', 'Qi ', 'Ke ', 'Zhui ', 'Zong ', 'Su ', 'Can ', 'Pian ', 'Zhi ', 'Kui ', 'Sao ', 'Wu ', 'Ao ', 'Liu ', 'Qian ', 'Shan ', 'Piao ', 'Luo ', 'Cong ', 'Chan ', 'Zou ', 'Ji ', 'Shuang ', 'Xiang ', 'Gu ', 'Wei ', 'Wei ', 'Wei ', 'Yu ', 'Gan ', 'Yi ', 'Ang ', 'Tou ', 'Xie ', 'Bao ', 'Bi ', 'Chi ', 'Ti ', 'Di ', 'Ku ', 'Hai ', 'Qiao ', 'Gou ', 'Kua ', 'Ge ', 'Tui ', 'Geng ', 'Pian ', 'Bi ', 'Ke ', 'Ka ', 'Yu ', 'Sui ', 'Lou ', 'Bo ', 'Xiao ', 'Pang ', 'Bo ', 'Ci ', 'Kuan ', 'Bin ', 'Mo ', 'Liao ', 'Lou ', 'Nao ', 'Du ', 'Zang ', 'Sui ', 'Ti ', 'Bin ', 'Kuan ', 'Lu ', 'Gao ', 'Gao ', 'Qiao ', 'Kao ', 'Qiao ', 'Lao ', 'Zao ', 'Biao ', 'Kun ', 'Kun ', 'Ti ', 'Fang ', 'Xiu ', 'Ran ', 'Mao ', 'Dan ', 'Kun ', 'Bin ', 'Fa ', 'Tiao ', 'Peng ', 'Zi ', 'Fa ', 'Ran ', 'Ti ', 'Pao ', 'Pi ', 'Mao ', 'Fu ', 'Er ', 'Rong ', 'Qu ', 'Gong ', 'Xiu ', 'Gua ', 'Ji ', 'Peng ', 'Zhua ', 'Shao ', 'Sha '];
<?php return ['Ti ', 'Li ', 'Bin ', 'Zong ', 'Ti ', 'Peng ', 'Song ', 'Zheng ', 'Quan ', 'Zong ', 'Shun ', 'Jian ', 'Duo ', 'Hu ', 'La ', 'Jiu ', 'Qi ', 'Lian ', 'Zhen ', 'Bin ', 'Peng ', 'Mo ', 'San ', 'Man ', 'Man ', 'Seng ', 'Xu ', 'Lie ', 'Qian ', 'Qian ', 'Nong ', 'Huan ', 'Kuai ', 'Ning ', 'Bin ', 'Lie ', 'Rang ', 'Dou ', 'Dou ', 'Nao ', 'Hong ', 'Xi ', 'Dou ', 'Han ', 'Dou ', 'Dou ', 'Jiu ', 'Chang ', 'Yu ', 'Yu ', 'Li ', 'Juan ', 'Fu ', 'Qian ', 'Gui ', 'Zong ', 'Liu ', 'Gui ', 'Shang ', 'Yu ', 'Gui ', 'Mei ', 'Ji ', 'Qi ', 'Jie ', 'Kui ', 'Hun ', 'Ba ', 'Po ', 'Mei ', 'Xu ', 'Yan ', 'Xiao ', 'Liang ', 'Yu ', 'Tui ', 'Qi ', 'Wang ', 'Liang ', 'Wei ', 'Jian ', 'Chi ', 'Piao ', 'Bi ', 'Mo ', 'Ji ', 'Xu ', 'Chou ', 'Yan ', 'Zhan ', 'Yu ', 'Dao ', 'Ren ', 'Ji ', 'Eri ', 'Gong ', 'Tuo ', 'Diao ', 'Ji ', 'Xu ', 'E ', 'E ', 'Sha ', 'Hang ', 'Tun ', 'Mo ', 'Jie ', 'Shen ', 'Fan ', 'Yuan ', 'Bi ', 'Lu ', 'Wen ', 'Hu ', 'Lu ', 'Za ', 'Fang ', 'Fen ', 'Na ', 'You ', 'Namazu ', 'Todo ', 'He ', 'Xia ', 'Qu ', 'Han ', 'Pi ', 'Ling ', 'Tuo ', 'Bo ', 'Qiu ', 'Ping ', 'Fu ', 'Bi ', 'Ji ', 'Wei ', 'Ju ', 'Diao ', 'Bo ', 'You ', 'Gun ', 'Pi ', 'Nian ', 'Xing ', 'Tai ', 'Bao ', 'Fu ', 'Zha ', 'Ju ', 'Gu ', 'Kajika ', 'Tong ', '[?] ', 'Ta ', 'Jie ', 'Shu ', 'Hou ', 'Xiang ', 'Er ', 'An ', 'Wei ', 'Tiao ', 'Zhu ', 'Yin ', 'Lie ', 'Luo ', 'Tong ', 'Yi ', 'Qi ', 'Bing ', 'Wei ', 'Jiao ', 'Bu ', 'Gui ', 'Xian ', 'Ge ', 'Hui ', 'Bora ', 'Mate ', 'Kao ', 'Gori ', 'Duo ', 'Jun ', 'Ti ', 'Man ', 'Xiao ', 'Za ', 'Sha ', 'Qin ', 'Yu ', 'Nei ', 'Zhe ', 'Gun ', 'Geng ', 'Su ', 'Wu ', 'Qiu ', 'Ting ', 'Fu ', 'Wan ', 'You ', 'Li ', 'Sha ', 'Sha ', 'Gao ', 'Meng ', 'Ugui ', 'Asari ', 'Subashiri ', 'Kazunoko ', 'Yong ', 'Ni ', 'Zi ', 'Qi ', 'Qing ', 'Xiang ', 'Nei ', 'Chun ', 'Ji ', 'Diao ', 'Qie ', 'Gu ', 'Zhou ', 'Dong ', 'Lai ', 'Fei ', 'Ni ', 'Yi ', 'Kun ', 'Lu ', 'Jiu ', 'Chang ', 'Jing ', 'Lun ', 'Ling ', 'Zou ', 'Li ', 'Meng ', 'Zong ', 'Zhi ', 'Nian ', 'Shachi ', 'Dojou ', 'Sukesou ', 'Shi ', 'Shen ', 'Hun ', 'Shi ', 'Hou ', 'Xing ', 'Zhu ', 'La ', 'Zong ', 'Ji ', 'Bian ', 'Bian '];
<?php return ['Huan ', 'Quan ', 'Ze ', 'Wei ', 'Wei ', 'Yu ', 'Qun ', 'Rou ', 'Die ', 'Huang ', 'Lian ', 'Yan ', 'Qiu ', 'Qiu ', 'Jian ', 'Bi ', 'E ', 'Yang ', 'Fu ', 'Sai ', 'Jian ', 'Xia ', 'Tuo ', 'Hu ', 'Muroaji ', 'Ruo ', 'Haraka ', 'Wen ', 'Jian ', 'Hao ', 'Wu ', 'Fang ', 'Sao ', 'Liu ', 'Ma ', 'Shi ', 'Shi ', 'Yin ', 'Z ', 'Teng ', 'Ta ', 'Yao ', 'Ge ', 'Rong ', 'Qian ', 'Qi ', 'Wen ', 'Ruo ', 'Hatahata ', 'Lian ', 'Ao ', 'Le ', 'Hui ', 'Min ', 'Ji ', 'Tiao ', 'Qu ', 'Jian ', 'Sao ', 'Man ', 'Xi ', 'Qiu ', 'Biao ', 'Ji ', 'Ji ', 'Zhu ', 'Jiang ', 'Qiu ', 'Zhuan ', 'Yong ', 'Zhang ', 'Kang ', 'Xue ', 'Bie ', 'Jue ', 'Qu ', 'Xiang ', 'Bo ', 'Jiao ', 'Xun ', 'Su ', 'Huang ', 'Zun ', 'Shan ', 'Shan ', 'Fan ', 'Jue ', 'Lin ', 'Xun ', 'Miao ', 'Xi ', 'Eso ', 'Kyou ', 'Fen ', 'Guan ', 'Hou ', 'Kuai ', 'Zei ', 'Sao ', 'Zhan ', 'Gan ', 'Gui ', 'Sheng ', 'Li ', 'Chang ', 'Hatahata ', 'Shiira ', 'Mutsu ', 'Ru ', 'Ji ', 'Xu ', 'Huo ', 'Shiira ', 'Li ', 'Lie ', 'Li ', 'Mie ', 'Zhen ', 'Xiang ', 'E ', 'Lu ', 'Guan ', 'Li ', 'Xian ', 'Yu ', 'Dao ', 'Ji ', 'You ', 'Tun ', 'Lu ', 'Fang ', 'Ba ', 'He ', 'Bo ', 'Ping ', 'Nian ', 'Lu ', 'You ', 'Zha ', 'Fu ', 'Bo ', 'Bao ', 'Hou ', 'Pi ', 'Tai ', 'Gui ', 'Jie ', 'Kao ', 'Wei ', 'Er ', 'Tong ', 'Ze ', 'Hou ', 'Kuai ', 'Ji ', 'Jiao ', 'Xian ', 'Za ', 'Xiang ', 'Xun ', 'Geng ', 'Li ', 'Lian ', 'Jian ', 'Li ', 'Shi ', 'Tiao ', 'Gun ', 'Sha ', 'Wan ', 'Jun ', 'Ji ', 'Yong ', 'Qing ', 'Ling ', 'Qi ', 'Zou ', 'Fei ', 'Kun ', 'Chang ', 'Gu ', 'Ni ', 'Nian ', 'Diao ', 'Jing ', 'Shen ', 'Shi ', 'Zi ', 'Fen ', 'Die ', 'Bi ', 'Chang ', 'Shi ', 'Wen ', 'Wei ', 'Sai ', 'E ', 'Qiu ', 'Fu ', 'Huang ', 'Quan ', 'Jiang ', 'Bian ', 'Sao ', 'Ao ', 'Qi ', 'Ta ', 'Yin ', 'Yao ', 'Fang ', 'Jian ', 'Le ', 'Biao ', 'Xue ', 'Bie ', 'Man ', 'Min ', 'Yong ', 'Wei ', 'Xi ', 'Jue ', 'Shan ', 'Lin ', 'Zun ', 'Huo ', 'Gan ', 'Li ', 'Zhan ', 'Guan ', 'Niao ', 'Yi ', 'Fu ', 'Li ', 'Jiu ', 'Bu ', 'Yan ', 'Fu ', 'Diao ', 'Ji ', 'Feng ', 'Nio ', 'Gan ', 'Shi ', 'Feng ', 'Ming ', 'Bao ', 'Yuan ', 'Zhi ', 'Hu ', 'Qin ', 'Fu ', 'Fen ', 'Wen ', 'Jian ', 'Shi ', 'Yu '];
<?php return ['Fou ', 'Yiao ', 'Jue ', 'Jue ', 'Pi ', 'Huan ', 'Zhen ', 'Bao ', 'Yan ', 'Ya ', 'Zheng ', 'Fang ', 'Feng ', 'Wen ', 'Ou ', 'Te ', 'Jia ', 'Nu ', 'Ling ', 'Mie ', 'Fu ', 'Tuo ', 'Wen ', 'Li ', 'Bian ', 'Zhi ', 'Ge ', 'Yuan ', 'Zi ', 'Qu ', 'Xiao ', 'Zhi ', 'Dan ', 'Ju ', 'You ', 'Gu ', 'Zhong ', 'Yu ', 'Yang ', 'Rong ', 'Ya ', 'Tie ', 'Yu ', 'Shigi ', 'Ying ', 'Zhui ', 'Wu ', 'Er ', 'Gua ', 'Ai ', 'Zhi ', 'Yan ', 'Heng ', 'Jiao ', 'Ji ', 'Lie ', 'Zhu ', 'Ren ', 'Yi ', 'Hong ', 'Luo ', 'Ru ', 'Mou ', 'Ge ', 'Ren ', 'Jiao ', 'Xiu ', 'Zhou ', 'Zhi ', 'Luo ', 'Chidori ', 'Toki ', 'Ten ', 'Luan ', 'Jia ', 'Ji ', 'Yu ', 'Huan ', 'Tuo ', 'Bu ', 'Wu ', 'Juan ', 'Yu ', 'Bo ', 'Xun ', 'Xun ', 'Bi ', 'Xi ', 'Jun ', 'Ju ', 'Tu ', 'Jing ', 'Ti ', 'E ', 'E ', 'Kuang ', 'Hu ', 'Wu ', 'Shen ', 'Lai ', 'Ikaruga ', 'Kakesu ', 'Lu ', 'Ping ', 'Shu ', 'Fu ', 'An ', 'Zhao ', 'Peng ', 'Qin ', 'Qian ', 'Bei ', 'Diao ', 'Lu ', 'Que ', 'Jian ', 'Ju ', 'Tu ', 'Ya ', 'Yuan ', 'Qi ', 'Li ', 'Ye ', 'Zhui ', 'Kong ', 'Zhui ', 'Kun ', 'Sheng ', 'Qi ', 'Jing ', 'Yi ', 'Yi ', 'Jing ', 'Zi ', 'Lai ', 'Dong ', 'Qi ', 'Chun ', 'Geng ', 'Ju ', 'Qu ', 'Isuka ', 'Kikuitadaki ', 'Ji ', 'Shu ', '[?] ', 'Chi ', 'Miao ', 'Rou ', 'An ', 'Qiu ', 'Ti ', 'Hu ', 'Ti ', 'E ', 'Jie ', 'Mao ', 'Fu ', 'Chun ', 'Tu ', 'Yan ', 'He ', 'Yuan ', 'Pian ', 'Yun ', 'Mei ', 'Hu ', 'Ying ', 'Dun ', 'Mu ', 'Ju ', 'Tsugumi ', 'Cang ', 'Fang ', 'Gu ', 'Ying ', 'Yuan ', 'Xuan ', 'Weng ', 'Shi ', 'He ', 'Chu ', 'Tang ', 'Xia ', 'Ruo ', 'Liu ', 'Ji ', 'Gu ', 'Jian ', 'Zhun ', 'Han ', 'Zi ', 'Zi ', 'Ni ', 'Yao ', 'Yan ', 'Ji ', 'Li ', 'Tian ', 'Kou ', 'Ti ', 'Ti ', 'Ni ', 'Tu ', 'Ma ', 'Jiao ', 'Gao ', 'Tian ', 'Chen ', 'Li ', 'Zhuan ', 'Zhe ', 'Ao ', 'Yao ', 'Yi ', 'Ou ', 'Chi ', 'Zhi ', 'Liao ', 'Rong ', 'Lou ', 'Bi ', 'Shuang ', 'Zhuo ', 'Yu ', 'Wu ', 'Jue ', 'Yin ', 'Quan ', 'Si ', 'Jiao ', 'Yi ', 'Hua ', 'Bi ', 'Ying ', 'Su ', 'Huang ', 'Fan ', 'Jiao ', 'Liao ', 'Yan ', 'Kao ', 'Jiu ', 'Xian ', 'Xian ', 'Tu ', 'Mai ', 'Zun ', 'Yu ', 'Ying ', 'Lu ', 'Tuan ', 'Xian ', 'Xue ', 'Yi ', 'Pi '];
<?php return ['Shu ', 'Luo ', 'Qi ', 'Yi ', 'Ji ', 'Zhe ', 'Yu ', 'Zhan ', 'Ye ', 'Yang ', 'Pi ', 'Ning ', 'Huo ', 'Mi ', 'Ying ', 'Meng ', 'Di ', 'Yue ', 'Yu ', 'Lei ', 'Bao ', 'Lu ', 'He ', 'Long ', 'Shuang ', 'Yue ', 'Ying ', 'Guan ', 'Qu ', 'Li ', 'Luan ', 'Niao ', 'Jiu ', 'Ji ', 'Yuan ', 'Ming ', 'Shi ', 'Ou ', 'Ya ', 'Cang ', 'Bao ', 'Zhen ', 'Gu ', 'Dong ', 'Lu ', 'Ya ', 'Xiao ', 'Yang ', 'Ling ', 'Zhi ', 'Qu ', 'Yuan ', 'Xue ', 'Tuo ', 'Si ', 'Zhi ', 'Er ', 'Gua ', 'Xiu ', 'Heng ', 'Zhou ', 'Ge ', 'Luan ', 'Hong ', 'Wu ', 'Bo ', 'Li ', 'Juan ', 'Hu ', 'E ', 'Yu ', 'Xian ', 'Ti ', 'Wu ', 'Que ', 'Miao ', 'An ', 'Kun ', 'Bei ', 'Peng ', 'Qian ', 'Chun ', 'Geng ', 'Yuan ', 'Su ', 'Hu ', 'He ', 'E ', 'Gu ', 'Qiu ', 'Zi ', 'Mei ', 'Mu ', 'Ni ', 'Yao ', 'Weng ', 'Liu ', 'Ji ', 'Ni ', 'Jian ', 'He ', 'Yi ', 'Ying ', 'Zhe ', 'Liao ', 'Liao ', 'Jiao ', 'Jiu ', 'Yu ', 'Lu ', 'Xuan ', 'Zhan ', 'Ying ', 'Huo ', 'Meng ', 'Guan ', 'Shuang ', 'Lu ', 'Jin ', 'Ling ', 'Jian ', 'Xian ', 'Cuo ', 'Jian ', 'Jian ', 'Yan ', 'Cuo ', 'Lu ', 'You ', 'Cu ', 'Ji ', 'Biao ', 'Cu ', 'Biao ', 'Zhu ', 'Jun ', 'Zhu ', 'Jian ', 'Mi ', 'Mi ', 'Wu ', 'Liu ', 'Chen ', 'Jun ', 'Lin ', 'Ni ', 'Qi ', 'Lu ', 'Jiu ', 'Jun ', 'Jing ', 'Li ', 'Xiang ', 'Yan ', 'Jia ', 'Mi ', 'Li ', 'She ', 'Zhang ', 'Lin ', 'Jing ', 'Ji ', 'Ling ', 'Yan ', 'Cu ', 'Mai ', 'Mai ', 'Ge ', 'Chao ', 'Fu ', 'Mian ', 'Mian ', 'Fu ', 'Pao ', 'Qu ', 'Qu ', 'Mou ', 'Fu ', 'Xian ', 'Lai ', 'Qu ', 'Mian ', '[?] ', 'Feng ', 'Fu ', 'Qu ', 'Mian ', 'Ma ', 'Mo ', 'Mo ', 'Hui ', 'Ma ', 'Zou ', 'Nen ', 'Fen ', 'Huang ', 'Huang ', 'Jin ', 'Guang ', 'Tian ', 'Tou ', 'Heng ', 'Xi ', 'Kuang ', 'Heng ', 'Shu ', 'Li ', 'Nian ', 'Chi ', 'Hei ', 'Hei ', 'Yi ', 'Qian ', 'Dan ', 'Xi ', 'Tuan ', 'Mo ', 'Mo ', 'Qian ', 'Dai ', 'Chu ', 'You ', 'Dian ', 'Yi ', 'Xia ', 'Yan ', 'Qu ', 'Mei ', 'Yan ', 'Jing ', 'Yu ', 'Li ', 'Dang ', 'Du ', 'Can ', 'Yin ', 'An ', 'Yan ', 'Tan ', 'An ', 'Zhen ', 'Dai ', 'Can ', 'Yi ', 'Mei ', 'Dan ', 'Yan ', 'Du ', 'Lu ', 'Zhi ', 'Fen ', 'Fu ', 'Fu ', 'Min ', 'Min ', 'Yuan '];
<?php return ['Cu ', 'Qu ', 'Chao ', 'Wa ', 'Zhu ', 'Zhi ', 'Mang ', 'Ao ', 'Bie ', 'Tuo ', 'Bi ', 'Yuan ', 'Chao ', 'Tuo ', 'Ding ', 'Mi ', 'Nai ', 'Ding ', 'Zi ', 'Gu ', 'Gu ', 'Dong ', 'Fen ', 'Tao ', 'Yuan ', 'Pi ', 'Chang ', 'Gao ', 'Qi ', 'Yuan ', 'Tang ', 'Teng ', 'Shu ', 'Shu ', 'Fen ', 'Fei ', 'Wen ', 'Ba ', 'Diao ', 'Tuo ', 'Tong ', 'Qu ', 'Sheng ', 'Shi ', 'You ', 'Shi ', 'Ting ', 'Wu ', 'Nian ', 'Jing ', 'Hun ', 'Ju ', 'Yan ', 'Tu ', 'Ti ', 'Xi ', 'Xian ', 'Yan ', 'Lei ', 'Bi ', 'Yao ', 'Qiu ', 'Han ', 'Wu ', 'Wu ', 'Hou ', 'Xi ', 'Ge ', 'Zha ', 'Xiu ', 'Weng ', 'Zha ', 'Nong ', 'Nang ', 'Qi ', 'Zhai ', 'Ji ', 'Zi ', 'Ji ', 'Ji ', 'Qi ', 'Ji ', 'Chi ', 'Chen ', 'Chen ', 'He ', 'Ya ', 'Ken ', 'Xie ', 'Pao ', 'Cuo ', 'Shi ', 'Zi ', 'Chi ', 'Nian ', 'Ju ', 'Tiao ', 'Ling ', 'Ling ', 'Chu ', 'Quan ', 'Xie ', 'Ken ', 'Nie ', 'Jiu ', 'Yao ', 'Chuo ', 'Kun ', 'Yu ', 'Chu ', 'Yi ', 'Ni ', 'Cuo ', 'Zou ', 'Qu ', 'Nen ', 'Xian ', 'Ou ', 'E ', 'Wo ', 'Yi ', 'Chuo ', 'Zou ', 'Dian ', 'Chu ', 'Jin ', 'Ya ', 'Chi ', 'Chen ', 'He ', 'Ken ', 'Ju ', 'Ling ', 'Pao ', 'Tiao ', 'Zi ', 'Ken ', 'Yu ', 'Chuo ', 'Qu ', 'Wo ', 'Long ', 'Pang ', 'Gong ', 'Pang ', 'Yan ', 'Long ', 'Long ', 'Gong ', 'Kan ', 'Ta ', 'Ling ', 'Ta ', 'Long ', 'Gong ', 'Kan ', 'Gui ', 'Qiu ', 'Bie ', 'Gui ', 'Yue ', 'Chui ', 'He ', 'Jue ', 'Xie ', 'Yu ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['it', 'ix', 'i', 'ip', 'iet', 'iex', 'ie', 'iep', 'at', 'ax', 'a', 'ap', 'uox', 'uo', 'uop', 'ot', 'ox', 'o', 'op', 'ex', 'e', 'wu', 'bit', 'bix', 'bi', 'bip', 'biet', 'biex', 'bie', 'biep', 'bat', 'bax', 'ba', 'bap', 'buox', 'buo', 'buop', 'bot', 'box', 'bo', 'bop', 'bex', 'be', 'bep', 'but', 'bux', 'bu', 'bup', 'burx', 'bur', 'byt', 'byx', 'by', 'byp', 'byrx', 'byr', 'pit', 'pix', 'pi', 'pip', 'piex', 'pie', 'piep', 'pat', 'pax', 'pa', 'pap', 'puox', 'puo', 'puop', 'pot', 'pox', 'po', 'pop', 'put', 'pux', 'pu', 'pup', 'purx', 'pur', 'pyt', 'pyx', 'py', 'pyp', 'pyrx', 'pyr', 'bbit', 'bbix', 'bbi', 'bbip', 'bbiet', 'bbiex', 'bbie', 'bbiep', 'bbat', 'bbax', 'bba', 'bbap', 'bbuox', 'bbuo', 'bbuop', 'bbot', 'bbox', 'bbo', 'bbop', 'bbex', 'bbe', 'bbep', 'bbut', 'bbux', 'bbu', 'bbup', 'bburx', 'bbur', 'bbyt', 'bbyx', 'bby', 'bbyp', 'nbit', 'nbix', 'nbi', 'nbip', 'nbiex', 'nbie', 'nbiep', 'nbat', 'nbax', 'nba', 'nbap', 'nbot', 'nbox', 'nbo', 'nbop', 'nbut', 'nbux', 'nbu', 'nbup', 'nburx', 'nbur', 'nbyt', 'nbyx', 'nby', 'nbyp', 'nbyrx', 'nbyr', 'hmit', 'hmix', 'hmi', 'hmip', 'hmiex', 'hmie', 'hmiep', 'hmat', 'hmax', 'hma', 'hmap', 'hmuox', 'hmuo', 'hmuop', 'hmot', 'hmox', 'hmo', 'hmop', 'hmut', 'hmux', 'hmu', 'hmup', 'hmurx', 'hmur', 'hmyx', 'hmy', 'hmyp', 'hmyrx', 'hmyr', 'mit', 'mix', 'mi', 'mip', 'miex', 'mie', 'miep', 'mat', 'max', 'ma', 'map', 'muot', 'muox', 'muo', 'muop', 'mot', 'mox', 'mo', 'mop', 'mex', 'me', 'mut', 'mux', 'mu', 'mup', 'murx', 'mur', 'myt', 'myx', 'my', 'myp', 'fit', 'fix', 'fi', 'fip', 'fat', 'fax', 'fa', 'fap', 'fox', 'fo', 'fop', 'fut', 'fux', 'fu', 'fup', 'furx', 'fur', 'fyt', 'fyx', 'fy', 'fyp', 'vit', 'vix', 'vi', 'vip', 'viet', 'viex', 'vie', 'viep', 'vat', 'vax', 'va', 'vap', 'vot', 'vox', 'vo', 'vop', 'vex', 'vep', 'vut', 'vux', 'vu', 'vup', 'vurx', 'vur', 'vyt', 'vyx', 'vy', 'vyp', 'vyrx', 'vyr'];
<?php return ['dit', 'dix', 'di', 'dip', 'diex', 'die', 'diep', 'dat', 'dax', 'da', 'dap', 'duox', 'duo', 'dot', 'dox', 'do', 'dop', 'dex', 'de', 'dep', 'dut', 'dux', 'du', 'dup', 'durx', 'dur', 'tit', 'tix', 'ti', 'tip', 'tiex', 'tie', 'tiep', 'tat', 'tax', 'ta', 'tap', 'tuot', 'tuox', 'tuo', 'tuop', 'tot', 'tox', 'to', 'top', 'tex', 'te', 'tep', 'tut', 'tux', 'tu', 'tup', 'turx', 'tur', 'ddit', 'ddix', 'ddi', 'ddip', 'ddiex', 'ddie', 'ddiep', 'ddat', 'ddax', 'dda', 'ddap', 'dduox', 'dduo', 'dduop', 'ddot', 'ddox', 'ddo', 'ddop', 'ddex', 'dde', 'ddep', 'ddut', 'ddux', 'ddu', 'ddup', 'ddurx', 'ddur', 'ndit', 'ndix', 'ndi', 'ndip', 'ndiex', 'ndie', 'ndat', 'ndax', 'nda', 'ndap', 'ndot', 'ndox', 'ndo', 'ndop', 'ndex', 'nde', 'ndep', 'ndut', 'ndux', 'ndu', 'ndup', 'ndurx', 'ndur', 'hnit', 'hnix', 'hni', 'hnip', 'hniet', 'hniex', 'hnie', 'hniep', 'hnat', 'hnax', 'hna', 'hnap', 'hnuox', 'hnuo', 'hnot', 'hnox', 'hnop', 'hnex', 'hne', 'hnep', 'hnut', 'nit', 'nix', 'ni', 'nip', 'niex', 'nie', 'niep', 'nax', 'na', 'nap', 'nuox', 'nuo', 'nuop', 'not', 'nox', 'no', 'nop', 'nex', 'ne', 'nep', 'nut', 'nux', 'nu', 'nup', 'nurx', 'nur', 'hlit', 'hlix', 'hli', 'hlip', 'hliex', 'hlie', 'hliep', 'hlat', 'hlax', 'hla', 'hlap', 'hluox', 'hluo', 'hluop', 'hlox', 'hlo', 'hlop', 'hlex', 'hle', 'hlep', 'hlut', 'hlux', 'hlu', 'hlup', 'hlurx', 'hlur', 'hlyt', 'hlyx', 'hly', 'hlyp', 'hlyrx', 'hlyr', 'lit', 'lix', 'li', 'lip', 'liet', 'liex', 'lie', 'liep', 'lat', 'lax', 'la', 'lap', 'luot', 'luox', 'luo', 'luop', 'lot', 'lox', 'lo', 'lop', 'lex', 'le', 'lep', 'lut', 'lux', 'lu', 'lup', 'lurx', 'lur', 'lyt', 'lyx', 'ly', 'lyp', 'lyrx', 'lyr', 'git', 'gix', 'gi', 'gip', 'giet', 'giex', 'gie', 'giep', 'gat', 'gax', 'ga', 'gap', 'guot', 'guox', 'guo', 'guop', 'got', 'gox', 'go', 'gop', 'get', 'gex', 'ge', 'gep', 'gut', 'gux', 'gu', 'gup', 'gurx', 'gur', 'kit', 'kix', 'ki', 'kip', 'kiex', 'kie', 'kiep', 'kat'];
<?php return ['kax', 'ka', 'kap', 'kuox', 'kuo', 'kuop', 'kot', 'kox', 'ko', 'kop', 'ket', 'kex', 'ke', 'kep', 'kut', 'kux', 'ku', 'kup', 'kurx', 'kur', 'ggit', 'ggix', 'ggi', 'ggiex', 'ggie', 'ggiep', 'ggat', 'ggax', 'gga', 'ggap', 'gguot', 'gguox', 'gguo', 'gguop', 'ggot', 'ggox', 'ggo', 'ggop', 'gget', 'ggex', 'gge', 'ggep', 'ggut', 'ggux', 'ggu', 'ggup', 'ggurx', 'ggur', 'mgiex', 'mgie', 'mgat', 'mgax', 'mga', 'mgap', 'mguox', 'mguo', 'mguop', 'mgot', 'mgox', 'mgo', 'mgop', 'mgex', 'mge', 'mgep', 'mgut', 'mgux', 'mgu', 'mgup', 'mgurx', 'mgur', 'hxit', 'hxix', 'hxi', 'hxip', 'hxiet', 'hxiex', 'hxie', 'hxiep', 'hxat', 'hxax', 'hxa', 'hxap', 'hxuot', 'hxuox', 'hxuo', 'hxuop', 'hxot', 'hxox', 'hxo', 'hxop', 'hxex', 'hxe', 'hxep', 'ngiex', 'ngie', 'ngiep', 'ngat', 'ngax', 'nga', 'ngap', 'nguot', 'nguox', 'nguo', 'ngot', 'ngox', 'ngo', 'ngop', 'ngex', 'nge', 'ngep', 'hit', 'hiex', 'hie', 'hat', 'hax', 'ha', 'hap', 'huot', 'huox', 'huo', 'huop', 'hot', 'hox', 'ho', 'hop', 'hex', 'he', 'hep', 'wat', 'wax', 'wa', 'wap', 'wuox', 'wuo', 'wuop', 'wox', 'wo', 'wop', 'wex', 'we', 'wep', 'zit', 'zix', 'zi', 'zip', 'ziex', 'zie', 'ziep', 'zat', 'zax', 'za', 'zap', 'zuox', 'zuo', 'zuop', 'zot', 'zox', 'zo', 'zop', 'zex', 'ze', 'zep', 'zut', 'zux', 'zu', 'zup', 'zurx', 'zur', 'zyt', 'zyx', 'zy', 'zyp', 'zyrx', 'zyr', 'cit', 'cix', 'ci', 'cip', 'ciet', 'ciex', 'cie', 'ciep', 'cat', 'cax', 'ca', 'cap', 'cuox', 'cuo', 'cuop', 'cot', 'cox', 'co', 'cop', 'cex', 'ce', 'cep', 'cut', 'cux', 'cu', 'cup', 'curx', 'cur', 'cyt', 'cyx', 'cy', 'cyp', 'cyrx', 'cyr', 'zzit', 'zzix', 'zzi', 'zzip', 'zziet', 'zziex', 'zzie', 'zziep', 'zzat', 'zzax', 'zza', 'zzap', 'zzox', 'zzo', 'zzop', 'zzex', 'zze', 'zzep', 'zzux', 'zzu', 'zzup', 'zzurx', 'zzur', 'zzyt', 'zzyx', 'zzy', 'zzyp', 'zzyrx', 'zzyr', 'nzit', 'nzix', 'nzi', 'nzip', 'nziex', 'nzie', 'nziep', 'nzat', 'nzax', 'nza', 'nzap', 'nzuox', 'nzuo', 'nzox', 'nzop', 'nzex', 'nze', 'nzux', 'nzu'];
<?php return ['nzup', 'nzurx', 'nzur', 'nzyt', 'nzyx', 'nzy', 'nzyp', 'nzyrx', 'nzyr', 'sit', 'six', 'si', 'sip', 'siex', 'sie', 'siep', 'sat', 'sax', 'sa', 'sap', 'suox', 'suo', 'suop', 'sot', 'sox', 'so', 'sop', 'sex', 'se', 'sep', 'sut', 'sux', 'su', 'sup', 'surx', 'sur', 'syt', 'syx', 'sy', 'syp', 'syrx', 'syr', 'ssit', 'ssix', 'ssi', 'ssip', 'ssiex', 'ssie', 'ssiep', 'ssat', 'ssax', 'ssa', 'ssap', 'ssot', 'ssox', 'sso', 'ssop', 'ssex', 'sse', 'ssep', 'ssut', 'ssux', 'ssu', 'ssup', 'ssyt', 'ssyx', 'ssy', 'ssyp', 'ssyrx', 'ssyr', 'zhat', 'zhax', 'zha', 'zhap', 'zhuox', 'zhuo', 'zhuop', 'zhot', 'zhox', 'zho', 'zhop', 'zhet', 'zhex', 'zhe', 'zhep', 'zhut', 'zhux', 'zhu', 'zhup', 'zhurx', 'zhur', 'zhyt', 'zhyx', 'zhy', 'zhyp', 'zhyrx', 'zhyr', 'chat', 'chax', 'cha', 'chap', 'chuot', 'chuox', 'chuo', 'chuop', 'chot', 'chox', 'cho', 'chop', 'chet', 'chex', 'che', 'chep', 'chux', 'chu', 'chup', 'churx', 'chur', 'chyt', 'chyx', 'chy', 'chyp', 'chyrx', 'chyr', 'rrax', 'rra', 'rruox', 'rruo', 'rrot', 'rrox', 'rro', 'rrop', 'rret', 'rrex', 'rre', 'rrep', 'rrut', 'rrux', 'rru', 'rrup', 'rrurx', 'rrur', 'rryt', 'rryx', 'rry', 'rryp', 'rryrx', 'rryr', 'nrat', 'nrax', 'nra', 'nrap', 'nrox', 'nro', 'nrop', 'nret', 'nrex', 'nre', 'nrep', 'nrut', 'nrux', 'nru', 'nrup', 'nrurx', 'nrur', 'nryt', 'nryx', 'nry', 'nryp', 'nryrx', 'nryr', 'shat', 'shax', 'sha', 'shap', 'shuox', 'shuo', 'shuop', 'shot', 'shox', 'sho', 'shop', 'shet', 'shex', 'she', 'shep', 'shut', 'shux', 'shu', 'shup', 'shurx', 'shur', 'shyt', 'shyx', 'shy', 'shyp', 'shyrx', 'shyr', 'rat', 'rax', 'ra', 'rap', 'ruox', 'ruo', 'ruop', 'rot', 'rox', 'ro', 'rop', 'rex', 're', 'rep', 'rut', 'rux', 'ru', 'rup', 'rurx', 'rur', 'ryt', 'ryx', 'ry', 'ryp', 'ryrx', 'ryr', 'jit', 'jix', 'ji', 'jip', 'jiet', 'jiex', 'jie', 'jiep', 'juot', 'juox', 'juo', 'juop', 'jot', 'jox', 'jo', 'jop', 'jut', 'jux', 'ju', 'jup', 'jurx', 'jur', 'jyt', 'jyx', 'jy', 'jyp', 'jyrx', 'jyr', 'qit', 'qix', 'qi', 'qip'];
<?php return ['qiet', 'qiex', 'qie', 'qiep', 'quot', 'quox', 'quo', 'quop', 'qot', 'qox', 'qo', 'qop', 'qut', 'qux', 'qu', 'qup', 'qurx', 'qur', 'qyt', 'qyx', 'qy', 'qyp', 'qyrx', 'qyr', 'jjit', 'jjix', 'jji', 'jjip', 'jjiet', 'jjiex', 'jjie', 'jjiep', 'jjuox', 'jjuo', 'jjuop', 'jjot', 'jjox', 'jjo', 'jjop', 'jjut', 'jjux', 'jju', 'jjup', 'jjurx', 'jjur', 'jjyt', 'jjyx', 'jjy', 'jjyp', 'njit', 'njix', 'nji', 'njip', 'njiet', 'njiex', 'njie', 'njiep', 'njuox', 'njuo', 'njot', 'njox', 'njo', 'njop', 'njux', 'nju', 'njup', 'njurx', 'njur', 'njyt', 'njyx', 'njy', 'njyp', 'njyrx', 'njyr', 'nyit', 'nyix', 'nyi', 'nyip', 'nyiet', 'nyiex', 'nyie', 'nyiep', 'nyuox', 'nyuo', 'nyuop', 'nyot', 'nyox', 'nyo', 'nyop', 'nyut', 'nyux', 'nyu', 'nyup', 'xit', 'xix', 'xi', 'xip', 'xiet', 'xiex', 'xie', 'xiep', 'xuox', 'xuo', 'xot', 'xox', 'xo', 'xop', 'xyt', 'xyx', 'xy', 'xyp', 'xyrx', 'xyr', 'yit', 'yix', 'yi', 'yip', 'yiet', 'yiex', 'yie', 'yiep', 'yuot', 'yuox', 'yuo', 'yuop', 'yot', 'yox', 'yo', 'yop', 'yut', 'yux', 'yu', 'yup', 'yurx', 'yur', 'yyt', 'yyx', 'yy', 'yyp', 'yyrx', 'yyr', '[?]', '[?]', '[?]', 'Qot', 'Li', 'Kit', 'Nyip', 'Cyp', 'Ssi', 'Ggop', 'Gep', 'Mi', 'Hxit', 'Lyr', 'Bbut', 'Mop', 'Yo', 'Put', 'Hxuo', 'Tat', 'Ga', '[?]', '[?]', 'Ddur', 'Bur', 'Gguo', 'Nyop', 'Tu', 'Op', 'Jjut', 'Zot', 'Pyt', 'Hmo', 'Yit', 'Vur', 'Shy', 'Vep', 'Za', 'Jo', '[?]', 'Jjy', 'Got', 'Jjie', 'Wo', 'Du', 'Shur', 'Lie', 'Cy', 'Cuop', 'Cip', 'Hxop', 'Shat', '[?]', 'Shop', 'Che', 'Zziet', '[?]', 'Ke', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['ga', 'gag', 'gagg', 'gags', 'gan', 'ganj', 'ganh', 'gad', 'gal', 'galg', 'galm', 'galb', 'gals', 'galt', 'galp', 'galh', 'gam', 'gab', 'gabs', 'gas', 'gass', 'gang', 'gaj', 'gac', 'gak', 'gat', 'gap', 'gah', 'gae', 'gaeg', 'gaegg', 'gaegs', 'gaen', 'gaenj', 'gaenh', 'gaed', 'gael', 'gaelg', 'gaelm', 'gaelb', 'gaels', 'gaelt', 'gaelp', 'gaelh', 'gaem', 'gaeb', 'gaebs', 'gaes', 'gaess', 'gaeng', 'gaej', 'gaec', 'gaek', 'gaet', 'gaep', 'gaeh', 'gya', 'gyag', 'gyagg', 'gyags', 'gyan', 'gyanj', 'gyanh', 'gyad', 'gyal', 'gyalg', 'gyalm', 'gyalb', 'gyals', 'gyalt', 'gyalp', 'gyalh', 'gyam', 'gyab', 'gyabs', 'gyas', 'gyass', 'gyang', 'gyaj', 'gyac', 'gyak', 'gyat', 'gyap', 'gyah', 'gyae', 'gyaeg', 'gyaegg', 'gyaegs', 'gyaen', 'gyaenj', 'gyaenh', 'gyaed', 'gyael', 'gyaelg', 'gyaelm', 'gyaelb', 'gyaels', 'gyaelt', 'gyaelp', 'gyaelh', 'gyaem', 'gyaeb', 'gyaebs', 'gyaes', 'gyaess', 'gyaeng', 'gyaej', 'gyaec', 'gyaek', 'gyaet', 'gyaep', 'gyaeh', 'geo', 'geog', 'geogg', 'geogs', 'geon', 'geonj', 'geonh', 'geod', 'geol', 'geolg', 'geolm', 'geolb', 'geols', 'geolt', 'geolp', 'geolh', 'geom', 'geob', 'geobs', 'geos', 'geoss', 'geong', 'geoj', 'geoc', 'geok', 'geot', 'geop', 'geoh', 'ge', 'geg', 'gegg', 'gegs', 'gen', 'genj', 'genh', 'ged', 'gel', 'gelg', 'gelm', 'gelb', 'gels', 'gelt', 'gelp', 'gelh', 'gem', 'geb', 'gebs', 'ges', 'gess', 'geng', 'gej', 'gec', 'gek', 'get', 'gep', 'geh', 'gyeo', 'gyeog', 'gyeogg', 'gyeogs', 'gyeon', 'gyeonj', 'gyeonh', 'gyeod', 'gyeol', 'gyeolg', 'gyeolm', 'gyeolb', 'gyeols', 'gyeolt', 'gyeolp', 'gyeolh', 'gyeom', 'gyeob', 'gyeobs', 'gyeos', 'gyeoss', 'gyeong', 'gyeoj', 'gyeoc', 'gyeok', 'gyeot', 'gyeop', 'gyeoh', 'gye', 'gyeg', 'gyegg', 'gyegs', 'gyen', 'gyenj', 'gyenh', 'gyed', 'gyel', 'gyelg', 'gyelm', 'gyelb', 'gyels', 'gyelt', 'gyelp', 'gyelh', 'gyem', 'gyeb', 'gyebs', 'gyes', 'gyess', 'gyeng', 'gyej', 'gyec', 'gyek', 'gyet', 'gyep', 'gyeh', 'go', 'gog', 'gogg', 'gogs', 'gon', 'gonj', 'gonh', 'god', 'gol', 'golg', 'golm', 'golb', 'gols', 'golt', 'golp', 'golh', 'gom', 'gob', 'gobs', 'gos', 'goss', 'gong', 'goj', 'goc', 'gok', 'got', 'gop', 'goh', 'gwa', 'gwag', 'gwagg', 'gwags'];
<?php return ['gwan', 'gwanj', 'gwanh', 'gwad', 'gwal', 'gwalg', 'gwalm', 'gwalb', 'gwals', 'gwalt', 'gwalp', 'gwalh', 'gwam', 'gwab', 'gwabs', 'gwas', 'gwass', 'gwang', 'gwaj', 'gwac', 'gwak', 'gwat', 'gwap', 'gwah', 'gwae', 'gwaeg', 'gwaegg', 'gwaegs', 'gwaen', 'gwaenj', 'gwaenh', 'gwaed', 'gwael', 'gwaelg', 'gwaelm', 'gwaelb', 'gwaels', 'gwaelt', 'gwaelp', 'gwaelh', 'gwaem', 'gwaeb', 'gwaebs', 'gwaes', 'gwaess', 'gwaeng', 'gwaej', 'gwaec', 'gwaek', 'gwaet', 'gwaep', 'gwaeh', 'goe', 'goeg', 'goegg', 'goegs', 'goen', 'goenj', 'goenh', 'goed', 'goel', 'goelg', 'goelm', 'goelb', 'goels', 'goelt', 'goelp', 'goelh', 'goem', 'goeb', 'goebs', 'goes', 'goess', 'goeng', 'goej', 'goec', 'goek', 'goet', 'goep', 'goeh', 'gyo', 'gyog', 'gyogg', 'gyogs', 'gyon', 'gyonj', 'gyonh', 'gyod', 'gyol', 'gyolg', 'gyolm', 'gyolb', 'gyols', 'gyolt', 'gyolp', 'gyolh', 'gyom', 'gyob', 'gyobs', 'gyos', 'gyoss', 'gyong', 'gyoj', 'gyoc', 'gyok', 'gyot', 'gyop', 'gyoh', 'gu', 'gug', 'gugg', 'gugs', 'gun', 'gunj', 'gunh', 'gud', 'gul', 'gulg', 'gulm', 'gulb', 'guls', 'gult', 'gulp', 'gulh', 'gum', 'gub', 'gubs', 'gus', 'guss', 'gung', 'guj', 'guc', 'guk', 'gut', 'gup', 'guh', 'gweo', 'gweog', 'gweogg', 'gweogs', 'gweon', 'gweonj', 'gweonh', 'gweod', 'gweol', 'gweolg', 'gweolm', 'gweolb', 'gweols', 'gweolt', 'gweolp', 'gweolh', 'gweom', 'gweob', 'gweobs', 'gweos', 'gweoss', 'gweong', 'gweoj', 'gweoc', 'gweok', 'gweot', 'gweop', 'gweoh', 'gwe', 'gweg', 'gwegg', 'gwegs', 'gwen', 'gwenj', 'gwenh', 'gwed', 'gwel', 'gwelg', 'gwelm', 'gwelb', 'gwels', 'gwelt', 'gwelp', 'gwelh', 'gwem', 'gweb', 'gwebs', 'gwes', 'gwess', 'gweng', 'gwej', 'gwec', 'gwek', 'gwet', 'gwep', 'gweh', 'gwi', 'gwig', 'gwigg', 'gwigs', 'gwin', 'gwinj', 'gwinh', 'gwid', 'gwil', 'gwilg', 'gwilm', 'gwilb', 'gwils', 'gwilt', 'gwilp', 'gwilh', 'gwim', 'gwib', 'gwibs', 'gwis', 'gwiss', 'gwing', 'gwij', 'gwic', 'gwik', 'gwit', 'gwip', 'gwih', 'gyu', 'gyug', 'gyugg', 'gyugs', 'gyun', 'gyunj', 'gyunh', 'gyud', 'gyul', 'gyulg', 'gyulm', 'gyulb', 'gyuls', 'gyult', 'gyulp', 'gyulh', 'gyum', 'gyub', 'gyubs', 'gyus', 'gyuss', 'gyung', 'gyuj', 'gyuc', 'gyuk', 'gyut', 'gyup', 'gyuh', 'geu', 'geug', 'geugg', 'geugs', 'geun', 'geunj', 'geunh', 'geud'];
<?php return ['geul', 'geulg', 'geulm', 'geulb', 'geuls', 'geult', 'geulp', 'geulh', 'geum', 'geub', 'geubs', 'geus', 'geuss', 'geung', 'geuj', 'geuc', 'geuk', 'geut', 'geup', 'geuh', 'gyi', 'gyig', 'gyigg', 'gyigs', 'gyin', 'gyinj', 'gyinh', 'gyid', 'gyil', 'gyilg', 'gyilm', 'gyilb', 'gyils', 'gyilt', 'gyilp', 'gyilh', 'gyim', 'gyib', 'gyibs', 'gyis', 'gyiss', 'gying', 'gyij', 'gyic', 'gyik', 'gyit', 'gyip', 'gyih', 'gi', 'gig', 'gigg', 'gigs', 'gin', 'ginj', 'ginh', 'gid', 'gil', 'gilg', 'gilm', 'gilb', 'gils', 'gilt', 'gilp', 'gilh', 'gim', 'gib', 'gibs', 'gis', 'giss', 'ging', 'gij', 'gic', 'gik', 'git', 'gip', 'gih', 'gga', 'ggag', 'ggagg', 'ggags', 'ggan', 'gganj', 'gganh', 'ggad', 'ggal', 'ggalg', 'ggalm', 'ggalb', 'ggals', 'ggalt', 'ggalp', 'ggalh', 'ggam', 'ggab', 'ggabs', 'ggas', 'ggass', 'ggang', 'ggaj', 'ggac', 'ggak', 'ggat', 'ggap', 'ggah', 'ggae', 'ggaeg', 'ggaegg', 'ggaegs', 'ggaen', 'ggaenj', 'ggaenh', 'ggaed', 'ggael', 'ggaelg', 'ggaelm', 'ggaelb', 'ggaels', 'ggaelt', 'ggaelp', 'ggaelh', 'ggaem', 'ggaeb', 'ggaebs', 'ggaes', 'ggaess', 'ggaeng', 'ggaej', 'ggaec', 'ggaek', 'ggaet', 'ggaep', 'ggaeh', 'ggya', 'ggyag', 'ggyagg', 'ggyags', 'ggyan', 'ggyanj', 'ggyanh', 'ggyad', 'ggyal', 'ggyalg', 'ggyalm', 'ggyalb', 'ggyals', 'ggyalt', 'ggyalp', 'ggyalh', 'ggyam', 'ggyab', 'ggyabs', 'ggyas', 'ggyass', 'ggyang', 'ggyaj', 'ggyac', 'ggyak', 'ggyat', 'ggyap', 'ggyah', 'ggyae', 'ggyaeg', 'ggyaegg', 'ggyaegs', 'ggyaen', 'ggyaenj', 'ggyaenh', 'ggyaed', 'ggyael', 'ggyaelg', 'ggyaelm', 'ggyaelb', 'ggyaels', 'ggyaelt', 'ggyaelp', 'ggyaelh', 'ggyaem', 'ggyaeb', 'ggyaebs', 'ggyaes', 'ggyaess', 'ggyaeng', 'ggyaej', 'ggyaec', 'ggyaek', 'ggyaet', 'ggyaep', 'ggyaeh', 'ggeo', 'ggeog', 'ggeogg', 'ggeogs', 'ggeon', 'ggeonj', 'ggeonh', 'ggeod', 'ggeol', 'ggeolg', 'ggeolm', 'ggeolb', 'ggeols', 'ggeolt', 'ggeolp', 'ggeolh', 'ggeom', 'ggeob', 'ggeobs', 'ggeos', 'ggeoss', 'ggeong', 'ggeoj', 'ggeoc', 'ggeok', 'ggeot', 'ggeop', 'ggeoh', 'gge', 'ggeg', 'ggegg', 'ggegs', 'ggen', 'ggenj', 'ggenh', 'gged', 'ggel', 'ggelg', 'ggelm', 'ggelb', 'ggels', 'ggelt', 'ggelp', 'ggelh', 'ggem', 'ggeb', 'ggebs', 'gges', 'ggess', 'ggeng', 'ggej', 'ggec', 'ggek', 'gget', 'ggep', 'ggeh', 'ggyeo', 'ggyeog', 'ggyeogg', 'ggyeogs', 'ggyeon', 'ggyeonj', 'ggyeonh', 'ggyeod', 'ggyeol', 'ggyeolg', 'ggyeolm', 'ggyeolb'];
<?php return ['ggyeols', 'ggyeolt', 'ggyeolp', 'ggyeolh', 'ggyeom', 'ggyeob', 'ggyeobs', 'ggyeos', 'ggyeoss', 'ggyeong', 'ggyeoj', 'ggyeoc', 'ggyeok', 'ggyeot', 'ggyeop', 'ggyeoh', 'ggye', 'ggyeg', 'ggyegg', 'ggyegs', 'ggyen', 'ggyenj', 'ggyenh', 'ggyed', 'ggyel', 'ggyelg', 'ggyelm', 'ggyelb', 'ggyels', 'ggyelt', 'ggyelp', 'ggyelh', 'ggyem', 'ggyeb', 'ggyebs', 'ggyes', 'ggyess', 'ggyeng', 'ggyej', 'ggyec', 'ggyek', 'ggyet', 'ggyep', 'ggyeh', 'ggo', 'ggog', 'ggogg', 'ggogs', 'ggon', 'ggonj', 'ggonh', 'ggod', 'ggol', 'ggolg', 'ggolm', 'ggolb', 'ggols', 'ggolt', 'ggolp', 'ggolh', 'ggom', 'ggob', 'ggobs', 'ggos', 'ggoss', 'ggong', 'ggoj', 'ggoc', 'ggok', 'ggot', 'ggop', 'ggoh', 'ggwa', 'ggwag', 'ggwagg', 'ggwags', 'ggwan', 'ggwanj', 'ggwanh', 'ggwad', 'ggwal', 'ggwalg', 'ggwalm', 'ggwalb', 'ggwals', 'ggwalt', 'ggwalp', 'ggwalh', 'ggwam', 'ggwab', 'ggwabs', 'ggwas', 'ggwass', 'ggwang', 'ggwaj', 'ggwac', 'ggwak', 'ggwat', 'ggwap', 'ggwah', 'ggwae', 'ggwaeg', 'ggwaegg', 'ggwaegs', 'ggwaen', 'ggwaenj', 'ggwaenh', 'ggwaed', 'ggwael', 'ggwaelg', 'ggwaelm', 'ggwaelb', 'ggwaels', 'ggwaelt', 'ggwaelp', 'ggwaelh', 'ggwaem', 'ggwaeb', 'ggwaebs', 'ggwaes', 'ggwaess', 'ggwaeng', 'ggwaej', 'ggwaec', 'ggwaek', 'ggwaet', 'ggwaep', 'ggwaeh', 'ggoe', 'ggoeg', 'ggoegg', 'ggoegs', 'ggoen', 'ggoenj', 'ggoenh', 'ggoed', 'ggoel', 'ggoelg', 'ggoelm', 'ggoelb', 'ggoels', 'ggoelt', 'ggoelp', 'ggoelh', 'ggoem', 'ggoeb', 'ggoebs', 'ggoes', 'ggoess', 'ggoeng', 'ggoej', 'ggoec', 'ggoek', 'ggoet', 'ggoep', 'ggoeh', 'ggyo', 'ggyog', 'ggyogg', 'ggyogs', 'ggyon', 'ggyonj', 'ggyonh', 'ggyod', 'ggyol', 'ggyolg', 'ggyolm', 'ggyolb', 'ggyols', 'ggyolt', 'ggyolp', 'ggyolh', 'ggyom', 'ggyob', 'ggyobs', 'ggyos', 'ggyoss', 'ggyong', 'ggyoj', 'ggyoc', 'ggyok', 'ggyot', 'ggyop', 'ggyoh', 'ggu', 'ggug', 'ggugg', 'ggugs', 'ggun', 'ggunj', 'ggunh', 'ggud', 'ggul', 'ggulg', 'ggulm', 'ggulb', 'gguls', 'ggult', 'ggulp', 'ggulh', 'ggum', 'ggub', 'ggubs', 'ggus', 'gguss', 'ggung', 'gguj', 'gguc', 'gguk', 'ggut', 'ggup', 'gguh', 'ggweo', 'ggweog', 'ggweogg', 'ggweogs', 'ggweon', 'ggweonj', 'ggweonh', 'ggweod', 'ggweol', 'ggweolg', 'ggweolm', 'ggweolb', 'ggweols', 'ggweolt', 'ggweolp', 'ggweolh', 'ggweom', 'ggweob', 'ggweobs', 'ggweos', 'ggweoss', 'ggweong', 'ggweoj', 'ggweoc', 'ggweok', 'ggweot', 'ggweop', 'ggweoh', 'ggwe', 'ggweg', 'ggwegg', 'ggwegs', 'ggwen', 'ggwenj', 'ggwenh', 'ggwed', 'ggwel', 'ggwelg', 'ggwelm', 'ggwelb', 'ggwels', 'ggwelt', 'ggwelp', 'ggwelh'];
<?php return ['ggwem', 'ggweb', 'ggwebs', 'ggwes', 'ggwess', 'ggweng', 'ggwej', 'ggwec', 'ggwek', 'ggwet', 'ggwep', 'ggweh', 'ggwi', 'ggwig', 'ggwigg', 'ggwigs', 'ggwin', 'ggwinj', 'ggwinh', 'ggwid', 'ggwil', 'ggwilg', 'ggwilm', 'ggwilb', 'ggwils', 'ggwilt', 'ggwilp', 'ggwilh', 'ggwim', 'ggwib', 'ggwibs', 'ggwis', 'ggwiss', 'ggwing', 'ggwij', 'ggwic', 'ggwik', 'ggwit', 'ggwip', 'ggwih', 'ggyu', 'ggyug', 'ggyugg', 'ggyugs', 'ggyun', 'ggyunj', 'ggyunh', 'ggyud', 'ggyul', 'ggyulg', 'ggyulm', 'ggyulb', 'ggyuls', 'ggyult', 'ggyulp', 'ggyulh', 'ggyum', 'ggyub', 'ggyubs', 'ggyus', 'ggyuss', 'ggyung', 'ggyuj', 'ggyuc', 'ggyuk', 'ggyut', 'ggyup', 'ggyuh', 'ggeu', 'ggeug', 'ggeugg', 'ggeugs', 'ggeun', 'ggeunj', 'ggeunh', 'ggeud', 'ggeul', 'ggeulg', 'ggeulm', 'ggeulb', 'ggeuls', 'ggeult', 'ggeulp', 'ggeulh', 'ggeum', 'ggeub', 'ggeubs', 'ggeus', 'ggeuss', 'ggeung', 'ggeuj', 'ggeuc', 'ggeuk', 'ggeut', 'ggeup', 'ggeuh', 'ggyi', 'ggyig', 'ggyigg', 'ggyigs', 'ggyin', 'ggyinj', 'ggyinh', 'ggyid', 'ggyil', 'ggyilg', 'ggyilm', 'ggyilb', 'ggyils', 'ggyilt', 'ggyilp', 'ggyilh', 'ggyim', 'ggyib', 'ggyibs', 'ggyis', 'ggyiss', 'ggying', 'ggyij', 'ggyic', 'ggyik', 'ggyit', 'ggyip', 'ggyih', 'ggi', 'ggig', 'ggigg', 'ggigs', 'ggin', 'gginj', 'gginh', 'ggid', 'ggil', 'ggilg', 'ggilm', 'ggilb', 'ggils', 'ggilt', 'ggilp', 'ggilh', 'ggim', 'ggib', 'ggibs', 'ggis', 'ggiss', 'gging', 'ggij', 'ggic', 'ggik', 'ggit', 'ggip', 'ggih', 'na', 'nag', 'nagg', 'nags', 'nan', 'nanj', 'nanh', 'nad', 'nal', 'nalg', 'nalm', 'nalb', 'nals', 'nalt', 'nalp', 'nalh', 'nam', 'nab', 'nabs', 'nas', 'nass', 'nang', 'naj', 'nac', 'nak', 'nat', 'nap', 'nah', 'nae', 'naeg', 'naegg', 'naegs', 'naen', 'naenj', 'naenh', 'naed', 'nael', 'naelg', 'naelm', 'naelb', 'naels', 'naelt', 'naelp', 'naelh', 'naem', 'naeb', 'naebs', 'naes', 'naess', 'naeng', 'naej', 'naec', 'naek', 'naet', 'naep', 'naeh', 'nya', 'nyag', 'nyagg', 'nyags', 'nyan', 'nyanj', 'nyanh', 'nyad', 'nyal', 'nyalg', 'nyalm', 'nyalb', 'nyals', 'nyalt', 'nyalp', 'nyalh', 'nyam', 'nyab', 'nyabs', 'nyas', 'nyass', 'nyang', 'nyaj', 'nyac', 'nyak', 'nyat', 'nyap', 'nyah', 'nyae', 'nyaeg', 'nyaegg', 'nyaegs', 'nyaen', 'nyaenj', 'nyaenh', 'nyaed', 'nyael', 'nyaelg', 'nyaelm', 'nyaelb', 'nyaels', 'nyaelt', 'nyaelp', 'nyaelh', 'nyaem', 'nyaeb', 'nyaebs', 'nyaes'];
<?php return ['nyaess', 'nyaeng', 'nyaej', 'nyaec', 'nyaek', 'nyaet', 'nyaep', 'nyaeh', 'neo', 'neog', 'neogg', 'neogs', 'neon', 'neonj', 'neonh', 'neod', 'neol', 'neolg', 'neolm', 'neolb', 'neols', 'neolt', 'neolp', 'neolh', 'neom', 'neob', 'neobs', 'neos', 'neoss', 'neong', 'neoj', 'neoc', 'neok', 'neot', 'neop', 'neoh', 'ne', 'neg', 'negg', 'negs', 'nen', 'nenj', 'nenh', 'ned', 'nel', 'nelg', 'nelm', 'nelb', 'nels', 'nelt', 'nelp', 'nelh', 'nem', 'neb', 'nebs', 'nes', 'ness', 'neng', 'nej', 'nec', 'nek', 'net', 'nep', 'neh', 'nyeo', 'nyeog', 'nyeogg', 'nyeogs', 'nyeon', 'nyeonj', 'nyeonh', 'nyeod', 'nyeol', 'nyeolg', 'nyeolm', 'nyeolb', 'nyeols', 'nyeolt', 'nyeolp', 'nyeolh', 'nyeom', 'nyeob', 'nyeobs', 'nyeos', 'nyeoss', 'nyeong', 'nyeoj', 'nyeoc', 'nyeok', 'nyeot', 'nyeop', 'nyeoh', 'nye', 'nyeg', 'nyegg', 'nyegs', 'nyen', 'nyenj', 'nyenh', 'nyed', 'nyel', 'nyelg', 'nyelm', 'nyelb', 'nyels', 'nyelt', 'nyelp', 'nyelh', 'nyem', 'nyeb', 'nyebs', 'nyes', 'nyess', 'nyeng', 'nyej', 'nyec', 'nyek', 'nyet', 'nyep', 'nyeh', 'no', 'nog', 'nogg', 'nogs', 'non', 'nonj', 'nonh', 'nod', 'nol', 'nolg', 'nolm', 'nolb', 'nols', 'nolt', 'nolp', 'nolh', 'nom', 'nob', 'nobs', 'nos', 'noss', 'nong', 'noj', 'noc', 'nok', 'not', 'nop', 'noh', 'nwa', 'nwag', 'nwagg', 'nwags', 'nwan', 'nwanj', 'nwanh', 'nwad', 'nwal', 'nwalg', 'nwalm', 'nwalb', 'nwals', 'nwalt', 'nwalp', 'nwalh', 'nwam', 'nwab', 'nwabs', 'nwas', 'nwass', 'nwang', 'nwaj', 'nwac', 'nwak', 'nwat', 'nwap', 'nwah', 'nwae', 'nwaeg', 'nwaegg', 'nwaegs', 'nwaen', 'nwaenj', 'nwaenh', 'nwaed', 'nwael', 'nwaelg', 'nwaelm', 'nwaelb', 'nwaels', 'nwaelt', 'nwaelp', 'nwaelh', 'nwaem', 'nwaeb', 'nwaebs', 'nwaes', 'nwaess', 'nwaeng', 'nwaej', 'nwaec', 'nwaek', 'nwaet', 'nwaep', 'nwaeh', 'noe', 'noeg', 'noegg', 'noegs', 'noen', 'noenj', 'noenh', 'noed', 'noel', 'noelg', 'noelm', 'noelb', 'noels', 'noelt', 'noelp', 'noelh', 'noem', 'noeb', 'noebs', 'noes', 'noess', 'noeng', 'noej', 'noec', 'noek', 'noet', 'noep', 'noeh', 'nyo', 'nyog', 'nyogg', 'nyogs', 'nyon', 'nyonj', 'nyonh', 'nyod', 'nyol', 'nyolg', 'nyolm', 'nyolb', 'nyols', 'nyolt', 'nyolp', 'nyolh', 'nyom', 'nyob', 'nyobs', 'nyos', 'nyoss', 'nyong', 'nyoj', 'nyoc'];
<?php return ['nyok', 'nyot', 'nyop', 'nyoh', 'nu', 'nug', 'nugg', 'nugs', 'nun', 'nunj', 'nunh', 'nud', 'nul', 'nulg', 'nulm', 'nulb', 'nuls', 'nult', 'nulp', 'nulh', 'num', 'nub', 'nubs', 'nus', 'nuss', 'nung', 'nuj', 'nuc', 'nuk', 'nut', 'nup', 'nuh', 'nweo', 'nweog', 'nweogg', 'nweogs', 'nweon', 'nweonj', 'nweonh', 'nweod', 'nweol', 'nweolg', 'nweolm', 'nweolb', 'nweols', 'nweolt', 'nweolp', 'nweolh', 'nweom', 'nweob', 'nweobs', 'nweos', 'nweoss', 'nweong', 'nweoj', 'nweoc', 'nweok', 'nweot', 'nweop', 'nweoh', 'nwe', 'nweg', 'nwegg', 'nwegs', 'nwen', 'nwenj', 'nwenh', 'nwed', 'nwel', 'nwelg', 'nwelm', 'nwelb', 'nwels', 'nwelt', 'nwelp', 'nwelh', 'nwem', 'nweb', 'nwebs', 'nwes', 'nwess', 'nweng', 'nwej', 'nwec', 'nwek', 'nwet', 'nwep', 'nweh', 'nwi', 'nwig', 'nwigg', 'nwigs', 'nwin', 'nwinj', 'nwinh', 'nwid', 'nwil', 'nwilg', 'nwilm', 'nwilb', 'nwils', 'nwilt', 'nwilp', 'nwilh', 'nwim', 'nwib', 'nwibs', 'nwis', 'nwiss', 'nwing', 'nwij', 'nwic', 'nwik', 'nwit', 'nwip', 'nwih', 'nyu', 'nyug', 'nyugg', 'nyugs', 'nyun', 'nyunj', 'nyunh', 'nyud', 'nyul', 'nyulg', 'nyulm', 'nyulb', 'nyuls', 'nyult', 'nyulp', 'nyulh', 'nyum', 'nyub', 'nyubs', 'nyus', 'nyuss', 'nyung', 'nyuj', 'nyuc', 'nyuk', 'nyut', 'nyup', 'nyuh', 'neu', 'neug', 'neugg', 'neugs', 'neun', 'neunj', 'neunh', 'neud', 'neul', 'neulg', 'neulm', 'neulb', 'neuls', 'neult', 'neulp', 'neulh', 'neum', 'neub', 'neubs', 'neus', 'neuss', 'neung', 'neuj', 'neuc', 'neuk', 'neut', 'neup', 'neuh', 'nyi', 'nyig', 'nyigg', 'nyigs', 'nyin', 'nyinj', 'nyinh', 'nyid', 'nyil', 'nyilg', 'nyilm', 'nyilb', 'nyils', 'nyilt', 'nyilp', 'nyilh', 'nyim', 'nyib', 'nyibs', 'nyis', 'nyiss', 'nying', 'nyij', 'nyic', 'nyik', 'nyit', 'nyip', 'nyih', 'ni', 'nig', 'nigg', 'nigs', 'nin', 'ninj', 'ninh', 'nid', 'nil', 'nilg', 'nilm', 'nilb', 'nils', 'nilt', 'nilp', 'nilh', 'nim', 'nib', 'nibs', 'nis', 'niss', 'ning', 'nij', 'nic', 'nik', 'nit', 'nip', 'nih', 'da', 'dag', 'dagg', 'dags', 'dan', 'danj', 'danh', 'dad', 'dal', 'dalg', 'dalm', 'dalb', 'dals', 'dalt', 'dalp', 'dalh', 'dam', 'dab', 'dabs', 'das', 'dass', 'dang', 'daj', 'dac', 'dak', 'dat', 'dap', 'dah'];
<?php return ['dae', 'daeg', 'daegg', 'daegs', 'daen', 'daenj', 'daenh', 'daed', 'dael', 'daelg', 'daelm', 'daelb', 'daels', 'daelt', 'daelp', 'daelh', 'daem', 'daeb', 'daebs', 'daes', 'daess', 'daeng', 'daej', 'daec', 'daek', 'daet', 'daep', 'daeh', 'dya', 'dyag', 'dyagg', 'dyags', 'dyan', 'dyanj', 'dyanh', 'dyad', 'dyal', 'dyalg', 'dyalm', 'dyalb', 'dyals', 'dyalt', 'dyalp', 'dyalh', 'dyam', 'dyab', 'dyabs', 'dyas', 'dyass', 'dyang', 'dyaj', 'dyac', 'dyak', 'dyat', 'dyap', 'dyah', 'dyae', 'dyaeg', 'dyaegg', 'dyaegs', 'dyaen', 'dyaenj', 'dyaenh', 'dyaed', 'dyael', 'dyaelg', 'dyaelm', 'dyaelb', 'dyaels', 'dyaelt', 'dyaelp', 'dyaelh', 'dyaem', 'dyaeb', 'dyaebs', 'dyaes', 'dyaess', 'dyaeng', 'dyaej', 'dyaec', 'dyaek', 'dyaet', 'dyaep', 'dyaeh', 'deo', 'deog', 'deogg', 'deogs', 'deon', 'deonj', 'deonh', 'deod', 'deol', 'deolg', 'deolm', 'deolb', 'deols', 'deolt', 'deolp', 'deolh', 'deom', 'deob', 'deobs', 'deos', 'deoss', 'deong', 'deoj', 'deoc', 'deok', 'deot', 'deop', 'deoh', 'de', 'deg', 'degg', 'degs', 'den', 'denj', 'denh', 'ded', 'del', 'delg', 'delm', 'delb', 'dels', 'delt', 'delp', 'delh', 'dem', 'deb', 'debs', 'des', 'dess', 'deng', 'dej', 'dec', 'dek', 'det', 'dep', 'deh', 'dyeo', 'dyeog', 'dyeogg', 'dyeogs', 'dyeon', 'dyeonj', 'dyeonh', 'dyeod', 'dyeol', 'dyeolg', 'dyeolm', 'dyeolb', 'dyeols', 'dyeolt', 'dyeolp', 'dyeolh', 'dyeom', 'dyeob', 'dyeobs', 'dyeos', 'dyeoss', 'dyeong', 'dyeoj', 'dyeoc', 'dyeok', 'dyeot', 'dyeop', 'dyeoh', 'dye', 'dyeg', 'dyegg', 'dyegs', 'dyen', 'dyenj', 'dyenh', 'dyed', 'dyel', 'dyelg', 'dyelm', 'dyelb', 'dyels', 'dyelt', 'dyelp', 'dyelh', 'dyem', 'dyeb', 'dyebs', 'dyes', 'dyess', 'dyeng', 'dyej', 'dyec', 'dyek', 'dyet', 'dyep', 'dyeh', 'do', 'dog', 'dogg', 'dogs', 'don', 'donj', 'donh', 'dod', 'dol', 'dolg', 'dolm', 'dolb', 'dols', 'dolt', 'dolp', 'dolh', 'dom', 'dob', 'dobs', 'dos', 'doss', 'dong', 'doj', 'doc', 'dok', 'dot', 'dop', 'doh', 'dwa', 'dwag', 'dwagg', 'dwags', 'dwan', 'dwanj', 'dwanh', 'dwad', 'dwal', 'dwalg', 'dwalm', 'dwalb', 'dwals', 'dwalt', 'dwalp', 'dwalh', 'dwam', 'dwab', 'dwabs', 'dwas', 'dwass', 'dwang', 'dwaj', 'dwac', 'dwak', 'dwat', 'dwap', 'dwah', 'dwae', 'dwaeg', 'dwaegg', 'dwaegs'];
<?php return ['dwaen', 'dwaenj', 'dwaenh', 'dwaed', 'dwael', 'dwaelg', 'dwaelm', 'dwaelb', 'dwaels', 'dwaelt', 'dwaelp', 'dwaelh', 'dwaem', 'dwaeb', 'dwaebs', 'dwaes', 'dwaess', 'dwaeng', 'dwaej', 'dwaec', 'dwaek', 'dwaet', 'dwaep', 'dwaeh', 'doe', 'doeg', 'doegg', 'doegs', 'doen', 'doenj', 'doenh', 'doed', 'doel', 'doelg', 'doelm', 'doelb', 'doels', 'doelt', 'doelp', 'doelh', 'doem', 'doeb', 'doebs', 'does', 'doess', 'doeng', 'doej', 'doec', 'doek', 'doet', 'doep', 'doeh', 'dyo', 'dyog', 'dyogg', 'dyogs', 'dyon', 'dyonj', 'dyonh', 'dyod', 'dyol', 'dyolg', 'dyolm', 'dyolb', 'dyols', 'dyolt', 'dyolp', 'dyolh', 'dyom', 'dyob', 'dyobs', 'dyos', 'dyoss', 'dyong', 'dyoj', 'dyoc', 'dyok', 'dyot', 'dyop', 'dyoh', 'du', 'dug', 'dugg', 'dugs', 'dun', 'dunj', 'dunh', 'dud', 'dul', 'dulg', 'dulm', 'dulb', 'duls', 'dult', 'dulp', 'dulh', 'dum', 'dub', 'dubs', 'dus', 'duss', 'dung', 'duj', 'duc', 'duk', 'dut', 'dup', 'duh', 'dweo', 'dweog', 'dweogg', 'dweogs', 'dweon', 'dweonj', 'dweonh', 'dweod', 'dweol', 'dweolg', 'dweolm', 'dweolb', 'dweols', 'dweolt', 'dweolp', 'dweolh', 'dweom', 'dweob', 'dweobs', 'dweos', 'dweoss', 'dweong', 'dweoj', 'dweoc', 'dweok', 'dweot', 'dweop', 'dweoh', 'dwe', 'dweg', 'dwegg', 'dwegs', 'dwen', 'dwenj', 'dwenh', 'dwed', 'dwel', 'dwelg', 'dwelm', 'dwelb', 'dwels', 'dwelt', 'dwelp', 'dwelh', 'dwem', 'dweb', 'dwebs', 'dwes', 'dwess', 'dweng', 'dwej', 'dwec', 'dwek', 'dwet', 'dwep', 'dweh', 'dwi', 'dwig', 'dwigg', 'dwigs', 'dwin', 'dwinj', 'dwinh', 'dwid', 'dwil', 'dwilg', 'dwilm', 'dwilb', 'dwils', 'dwilt', 'dwilp', 'dwilh', 'dwim', 'dwib', 'dwibs', 'dwis', 'dwiss', 'dwing', 'dwij', 'dwic', 'dwik', 'dwit', 'dwip', 'dwih', 'dyu', 'dyug', 'dyugg', 'dyugs', 'dyun', 'dyunj', 'dyunh', 'dyud', 'dyul', 'dyulg', 'dyulm', 'dyulb', 'dyuls', 'dyult', 'dyulp', 'dyulh', 'dyum', 'dyub', 'dyubs', 'dyus', 'dyuss', 'dyung', 'dyuj', 'dyuc', 'dyuk', 'dyut', 'dyup', 'dyuh', 'deu', 'deug', 'deugg', 'deugs', 'deun', 'deunj', 'deunh', 'deud', 'deul', 'deulg', 'deulm', 'deulb', 'deuls', 'deult', 'deulp', 'deulh', 'deum', 'deub', 'deubs', 'deus', 'deuss', 'deung', 'deuj', 'deuc', 'deuk', 'deut', 'deup', 'deuh', 'dyi', 'dyig', 'dyigg', 'dyigs', 'dyin', 'dyinj', 'dyinh', 'dyid'];
<?php return ['dyil', 'dyilg', 'dyilm', 'dyilb', 'dyils', 'dyilt', 'dyilp', 'dyilh', 'dyim', 'dyib', 'dyibs', 'dyis', 'dyiss', 'dying', 'dyij', 'dyic', 'dyik', 'dyit', 'dyip', 'dyih', 'di', 'dig', 'digg', 'digs', 'din', 'dinj', 'dinh', 'did', 'dil', 'dilg', 'dilm', 'dilb', 'dils', 'dilt', 'dilp', 'dilh', 'dim', 'dib', 'dibs', 'dis', 'diss', 'ding', 'dij', 'dic', 'dik', 'dit', 'dip', 'dih', 'dda', 'ddag', 'ddagg', 'ddags', 'ddan', 'ddanj', 'ddanh', 'ddad', 'ddal', 'ddalg', 'ddalm', 'ddalb', 'ddals', 'ddalt', 'ddalp', 'ddalh', 'ddam', 'ddab', 'ddabs', 'ddas', 'ddass', 'ddang', 'ddaj', 'ddac', 'ddak', 'ddat', 'ddap', 'ddah', 'ddae', 'ddaeg', 'ddaegg', 'ddaegs', 'ddaen', 'ddaenj', 'ddaenh', 'ddaed', 'ddael', 'ddaelg', 'ddaelm', 'ddaelb', 'ddaels', 'ddaelt', 'ddaelp', 'ddaelh', 'ddaem', 'ddaeb', 'ddaebs', 'ddaes', 'ddaess', 'ddaeng', 'ddaej', 'ddaec', 'ddaek', 'ddaet', 'ddaep', 'ddaeh', 'ddya', 'ddyag', 'ddyagg', 'ddyags', 'ddyan', 'ddyanj', 'ddyanh', 'ddyad', 'ddyal', 'ddyalg', 'ddyalm', 'ddyalb', 'ddyals', 'ddyalt', 'ddyalp', 'ddyalh', 'ddyam', 'ddyab', 'ddyabs', 'ddyas', 'ddyass', 'ddyang', 'ddyaj', 'ddyac', 'ddyak', 'ddyat', 'ddyap', 'ddyah', 'ddyae', 'ddyaeg', 'ddyaegg', 'ddyaegs', 'ddyaen', 'ddyaenj', 'ddyaenh', 'ddyaed', 'ddyael', 'ddyaelg', 'ddyaelm', 'ddyaelb', 'ddyaels', 'ddyaelt', 'ddyaelp', 'ddyaelh', 'ddyaem', 'ddyaeb', 'ddyaebs', 'ddyaes', 'ddyaess', 'ddyaeng', 'ddyaej', 'ddyaec', 'ddyaek', 'ddyaet', 'ddyaep', 'ddyaeh', 'ddeo', 'ddeog', 'ddeogg', 'ddeogs', 'ddeon', 'ddeonj', 'ddeonh', 'ddeod', 'ddeol', 'ddeolg', 'ddeolm', 'ddeolb', 'ddeols', 'ddeolt', 'ddeolp', 'ddeolh', 'ddeom', 'ddeob', 'ddeobs', 'ddeos', 'ddeoss', 'ddeong', 'ddeoj', 'ddeoc', 'ddeok', 'ddeot', 'ddeop', 'ddeoh', 'dde', 'ddeg', 'ddegg', 'ddegs', 'dden', 'ddenj', 'ddenh', 'dded', 'ddel', 'ddelg', 'ddelm', 'ddelb', 'ddels', 'ddelt', 'ddelp', 'ddelh', 'ddem', 'ddeb', 'ddebs', 'ddes', 'ddess', 'ddeng', 'ddej', 'ddec', 'ddek', 'ddet', 'ddep', 'ddeh', 'ddyeo', 'ddyeog', 'ddyeogg', 'ddyeogs', 'ddyeon', 'ddyeonj', 'ddyeonh', 'ddyeod', 'ddyeol', 'ddyeolg', 'ddyeolm', 'ddyeolb', 'ddyeols', 'ddyeolt', 'ddyeolp', 'ddyeolh', 'ddyeom', 'ddyeob', 'ddyeobs', 'ddyeos', 'ddyeoss', 'ddyeong', 'ddyeoj', 'ddyeoc', 'ddyeok', 'ddyeot', 'ddyeop', 'ddyeoh', 'ddye', 'ddyeg', 'ddyegg', 'ddyegs', 'ddyen', 'ddyenj', 'ddyenh', 'ddyed', 'ddyel', 'ddyelg', 'ddyelm', 'ddyelb'];
<?php return ['ddyels', 'ddyelt', 'ddyelp', 'ddyelh', 'ddyem', 'ddyeb', 'ddyebs', 'ddyes', 'ddyess', 'ddyeng', 'ddyej', 'ddyec', 'ddyek', 'ddyet', 'ddyep', 'ddyeh', 'ddo', 'ddog', 'ddogg', 'ddogs', 'ddon', 'ddonj', 'ddonh', 'ddod', 'ddol', 'ddolg', 'ddolm', 'ddolb', 'ddols', 'ddolt', 'ddolp', 'ddolh', 'ddom', 'ddob', 'ddobs', 'ddos', 'ddoss', 'ddong', 'ddoj', 'ddoc', 'ddok', 'ddot', 'ddop', 'ddoh', 'ddwa', 'ddwag', 'ddwagg', 'ddwags', 'ddwan', 'ddwanj', 'ddwanh', 'ddwad', 'ddwal', 'ddwalg', 'ddwalm', 'ddwalb', 'ddwals', 'ddwalt', 'ddwalp', 'ddwalh', 'ddwam', 'ddwab', 'ddwabs', 'ddwas', 'ddwass', 'ddwang', 'ddwaj', 'ddwac', 'ddwak', 'ddwat', 'ddwap', 'ddwah', 'ddwae', 'ddwaeg', 'ddwaegg', 'ddwaegs', 'ddwaen', 'ddwaenj', 'ddwaenh', 'ddwaed', 'ddwael', 'ddwaelg', 'ddwaelm', 'ddwaelb', 'ddwaels', 'ddwaelt', 'ddwaelp', 'ddwaelh', 'ddwaem', 'ddwaeb', 'ddwaebs', 'ddwaes', 'ddwaess', 'ddwaeng', 'ddwaej', 'ddwaec', 'ddwaek', 'ddwaet', 'ddwaep', 'ddwaeh', 'ddoe', 'ddoeg', 'ddoegg', 'ddoegs', 'ddoen', 'ddoenj', 'ddoenh', 'ddoed', 'ddoel', 'ddoelg', 'ddoelm', 'ddoelb', 'ddoels', 'ddoelt', 'ddoelp', 'ddoelh', 'ddoem', 'ddoeb', 'ddoebs', 'ddoes', 'ddoess', 'ddoeng', 'ddoej', 'ddoec', 'ddoek', 'ddoet', 'ddoep', 'ddoeh', 'ddyo', 'ddyog', 'ddyogg', 'ddyogs', 'ddyon', 'ddyonj', 'ddyonh', 'ddyod', 'ddyol', 'ddyolg', 'ddyolm', 'ddyolb', 'ddyols', 'ddyolt', 'ddyolp', 'ddyolh', 'ddyom', 'ddyob', 'ddyobs', 'ddyos', 'ddyoss', 'ddyong', 'ddyoj', 'ddyoc', 'ddyok', 'ddyot', 'ddyop', 'ddyoh', 'ddu', 'ddug', 'ddugg', 'ddugs', 'ddun', 'ddunj', 'ddunh', 'ddud', 'ddul', 'ddulg', 'ddulm', 'ddulb', 'dduls', 'ddult', 'ddulp', 'ddulh', 'ddum', 'ddub', 'ddubs', 'ddus', 'dduss', 'ddung', 'dduj', 'dduc', 'dduk', 'ddut', 'ddup', 'dduh', 'ddweo', 'ddweog', 'ddweogg', 'ddweogs', 'ddweon', 'ddweonj', 'ddweonh', 'ddweod', 'ddweol', 'ddweolg', 'ddweolm', 'ddweolb', 'ddweols', 'ddweolt', 'ddweolp', 'ddweolh', 'ddweom', 'ddweob', 'ddweobs', 'ddweos', 'ddweoss', 'ddweong', 'ddweoj', 'ddweoc', 'ddweok', 'ddweot', 'ddweop', 'ddweoh', 'ddwe', 'ddweg', 'ddwegg', 'ddwegs', 'ddwen', 'ddwenj', 'ddwenh', 'ddwed', 'ddwel', 'ddwelg', 'ddwelm', 'ddwelb', 'ddwels', 'ddwelt', 'ddwelp', 'ddwelh', 'ddwem', 'ddweb', 'ddwebs', 'ddwes', 'ddwess', 'ddweng', 'ddwej', 'ddwec', 'ddwek', 'ddwet', 'ddwep', 'ddweh', 'ddwi', 'ddwig', 'ddwigg', 'ddwigs', 'ddwin', 'ddwinj', 'ddwinh', 'ddwid', 'ddwil', 'ddwilg', 'ddwilm', 'ddwilb', 'ddwils', 'ddwilt', 'ddwilp', 'ddwilh'];
<?php return ['ddwim', 'ddwib', 'ddwibs', 'ddwis', 'ddwiss', 'ddwing', 'ddwij', 'ddwic', 'ddwik', 'ddwit', 'ddwip', 'ddwih', 'ddyu', 'ddyug', 'ddyugg', 'ddyugs', 'ddyun', 'ddyunj', 'ddyunh', 'ddyud', 'ddyul', 'ddyulg', 'ddyulm', 'ddyulb', 'ddyuls', 'ddyult', 'ddyulp', 'ddyulh', 'ddyum', 'ddyub', 'ddyubs', 'ddyus', 'ddyuss', 'ddyung', 'ddyuj', 'ddyuc', 'ddyuk', 'ddyut', 'ddyup', 'ddyuh', 'ddeu', 'ddeug', 'ddeugg', 'ddeugs', 'ddeun', 'ddeunj', 'ddeunh', 'ddeud', 'ddeul', 'ddeulg', 'ddeulm', 'ddeulb', 'ddeuls', 'ddeult', 'ddeulp', 'ddeulh', 'ddeum', 'ddeub', 'ddeubs', 'ddeus', 'ddeuss', 'ddeung', 'ddeuj', 'ddeuc', 'ddeuk', 'ddeut', 'ddeup', 'ddeuh', 'ddyi', 'ddyig', 'ddyigg', 'ddyigs', 'ddyin', 'ddyinj', 'ddyinh', 'ddyid', 'ddyil', 'ddyilg', 'ddyilm', 'ddyilb', 'ddyils', 'ddyilt', 'ddyilp', 'ddyilh', 'ddyim', 'ddyib', 'ddyibs', 'ddyis', 'ddyiss', 'ddying', 'ddyij', 'ddyic', 'ddyik', 'ddyit', 'ddyip', 'ddyih', 'ddi', 'ddig', 'ddigg', 'ddigs', 'ddin', 'ddinj', 'ddinh', 'ddid', 'ddil', 'ddilg', 'ddilm', 'ddilb', 'ddils', 'ddilt', 'ddilp', 'ddilh', 'ddim', 'ddib', 'ddibs', 'ddis', 'ddiss', 'dding', 'ddij', 'ddic', 'ddik', 'ddit', 'ddip', 'ddih', 'ra', 'rag', 'ragg', 'rags', 'ran', 'ranj', 'ranh', 'rad', 'ral', 'ralg', 'ralm', 'ralb', 'rals', 'ralt', 'ralp', 'ralh', 'ram', 'rab', 'rabs', 'ras', 'rass', 'rang', 'raj', 'rac', 'rak', 'rat', 'rap', 'rah', 'rae', 'raeg', 'raegg', 'raegs', 'raen', 'raenj', 'raenh', 'raed', 'rael', 'raelg', 'raelm', 'raelb', 'raels', 'raelt', 'raelp', 'raelh', 'raem', 'raeb', 'raebs', 'raes', 'raess', 'raeng', 'raej', 'raec', 'raek', 'raet', 'raep', 'raeh', 'rya', 'ryag', 'ryagg', 'ryags', 'ryan', 'ryanj', 'ryanh', 'ryad', 'ryal', 'ryalg', 'ryalm', 'ryalb', 'ryals', 'ryalt', 'ryalp', 'ryalh', 'ryam', 'ryab', 'ryabs', 'ryas', 'ryass', 'ryang', 'ryaj', 'ryac', 'ryak', 'ryat', 'ryap', 'ryah', 'ryae', 'ryaeg', 'ryaegg', 'ryaegs', 'ryaen', 'ryaenj', 'ryaenh', 'ryaed', 'ryael', 'ryaelg', 'ryaelm', 'ryaelb', 'ryaels', 'ryaelt', 'ryaelp', 'ryaelh', 'ryaem', 'ryaeb', 'ryaebs', 'ryaes', 'ryaess', 'ryaeng', 'ryaej', 'ryaec', 'ryaek', 'ryaet', 'ryaep', 'ryaeh', 'reo', 'reog', 'reogg', 'reogs', 'reon', 'reonj', 'reonh', 'reod', 'reol', 'reolg', 'reolm', 'reolb', 'reols', 'reolt', 'reolp', 'reolh', 'reom', 'reob', 'reobs', 'reos'];
<?php return ['reoss', 'reong', 'reoj', 'reoc', 'reok', 'reot', 'reop', 'reoh', 're', 'reg', 'regg', 'regs', 'ren', 'renj', 'renh', 'red', 'rel', 'relg', 'relm', 'relb', 'rels', 'relt', 'relp', 'relh', 'rem', 'reb', 'rebs', 'res', 'ress', 'reng', 'rej', 'rec', 'rek', 'ret', 'rep', 'reh', 'ryeo', 'ryeog', 'ryeogg', 'ryeogs', 'ryeon', 'ryeonj', 'ryeonh', 'ryeod', 'ryeol', 'ryeolg', 'ryeolm', 'ryeolb', 'ryeols', 'ryeolt', 'ryeolp', 'ryeolh', 'ryeom', 'ryeob', 'ryeobs', 'ryeos', 'ryeoss', 'ryeong', 'ryeoj', 'ryeoc', 'ryeok', 'ryeot', 'ryeop', 'ryeoh', 'rye', 'ryeg', 'ryegg', 'ryegs', 'ryen', 'ryenj', 'ryenh', 'ryed', 'ryel', 'ryelg', 'ryelm', 'ryelb', 'ryels', 'ryelt', 'ryelp', 'ryelh', 'ryem', 'ryeb', 'ryebs', 'ryes', 'ryess', 'ryeng', 'ryej', 'ryec', 'ryek', 'ryet', 'ryep', 'ryeh', 'ro', 'rog', 'rogg', 'rogs', 'ron', 'ronj', 'ronh', 'rod', 'rol', 'rolg', 'rolm', 'rolb', 'rols', 'rolt', 'rolp', 'rolh', 'rom', 'rob', 'robs', 'ros', 'ross', 'rong', 'roj', 'roc', 'rok', 'rot', 'rop', 'roh', 'rwa', 'rwag', 'rwagg', 'rwags', 'rwan', 'rwanj', 'rwanh', 'rwad', 'rwal', 'rwalg', 'rwalm', 'rwalb', 'rwals', 'rwalt', 'rwalp', 'rwalh', 'rwam', 'rwab', 'rwabs', 'rwas', 'rwass', 'rwang', 'rwaj', 'rwac', 'rwak', 'rwat', 'rwap', 'rwah', 'rwae', 'rwaeg', 'rwaegg', 'rwaegs', 'rwaen', 'rwaenj', 'rwaenh', 'rwaed', 'rwael', 'rwaelg', 'rwaelm', 'rwaelb', 'rwaels', 'rwaelt', 'rwaelp', 'rwaelh', 'rwaem', 'rwaeb', 'rwaebs', 'rwaes', 'rwaess', 'rwaeng', 'rwaej', 'rwaec', 'rwaek', 'rwaet', 'rwaep', 'rwaeh', 'roe', 'roeg', 'roegg', 'roegs', 'roen', 'roenj', 'roenh', 'roed', 'roel', 'roelg', 'roelm', 'roelb', 'roels', 'roelt', 'roelp', 'roelh', 'roem', 'roeb', 'roebs', 'roes', 'roess', 'roeng', 'roej', 'roec', 'roek', 'roet', 'roep', 'roeh', 'ryo', 'ryog', 'ryogg', 'ryogs', 'ryon', 'ryonj', 'ryonh', 'ryod', 'ryol', 'ryolg', 'ryolm', 'ryolb', 'ryols', 'ryolt', 'ryolp', 'ryolh', 'ryom', 'ryob', 'ryobs', 'ryos', 'ryoss', 'ryong', 'ryoj', 'ryoc', 'ryok', 'ryot', 'ryop', 'ryoh', 'ru', 'rug', 'rugg', 'rugs', 'run', 'runj', 'runh', 'rud', 'rul', 'rulg', 'rulm', 'rulb', 'ruls', 'rult', 'rulp', 'rulh', 'rum', 'rub', 'rubs', 'rus', 'russ', 'rung', 'ruj', 'ruc'];
<?php return ['ruk', 'rut', 'rup', 'ruh', 'rweo', 'rweog', 'rweogg', 'rweogs', 'rweon', 'rweonj', 'rweonh', 'rweod', 'rweol', 'rweolg', 'rweolm', 'rweolb', 'rweols', 'rweolt', 'rweolp', 'rweolh', 'rweom', 'rweob', 'rweobs', 'rweos', 'rweoss', 'rweong', 'rweoj', 'rweoc', 'rweok', 'rweot', 'rweop', 'rweoh', 'rwe', 'rweg', 'rwegg', 'rwegs', 'rwen', 'rwenj', 'rwenh', 'rwed', 'rwel', 'rwelg', 'rwelm', 'rwelb', 'rwels', 'rwelt', 'rwelp', 'rwelh', 'rwem', 'rweb', 'rwebs', 'rwes', 'rwess', 'rweng', 'rwej', 'rwec', 'rwek', 'rwet', 'rwep', 'rweh', 'rwi', 'rwig', 'rwigg', 'rwigs', 'rwin', 'rwinj', 'rwinh', 'rwid', 'rwil', 'rwilg', 'rwilm', 'rwilb', 'rwils', 'rwilt', 'rwilp', 'rwilh', 'rwim', 'rwib', 'rwibs', 'rwis', 'rwiss', 'rwing', 'rwij', 'rwic', 'rwik', 'rwit', 'rwip', 'rwih', 'ryu', 'ryug', 'ryugg', 'ryugs', 'ryun', 'ryunj', 'ryunh', 'ryud', 'ryul', 'ryulg', 'ryulm', 'ryulb', 'ryuls', 'ryult', 'ryulp', 'ryulh', 'ryum', 'ryub', 'ryubs', 'ryus', 'ryuss', 'ryung', 'ryuj', 'ryuc', 'ryuk', 'ryut', 'ryup', 'ryuh', 'reu', 'reug', 'reugg', 'reugs', 'reun', 'reunj', 'reunh', 'reud', 'reul', 'reulg', 'reulm', 'reulb', 'reuls', 'reult', 'reulp', 'reulh', 'reum', 'reub', 'reubs', 'reus', 'reuss', 'reung', 'reuj', 'reuc', 'reuk', 'reut', 'reup', 'reuh', 'ryi', 'ryig', 'ryigg', 'ryigs', 'ryin', 'ryinj', 'ryinh', 'ryid', 'ryil', 'ryilg', 'ryilm', 'ryilb', 'ryils', 'ryilt', 'ryilp', 'ryilh', 'ryim', 'ryib', 'ryibs', 'ryis', 'ryiss', 'rying', 'ryij', 'ryic', 'ryik', 'ryit', 'ryip', 'ryih', 'ri', 'rig', 'rigg', 'rigs', 'rin', 'rinj', 'rinh', 'rid', 'ril', 'rilg', 'rilm', 'rilb', 'rils', 'rilt', 'rilp', 'rilh', 'rim', 'rib', 'ribs', 'ris', 'riss', 'ring', 'rij', 'ric', 'rik', 'rit', 'rip', 'rih', 'ma', 'mag', 'magg', 'mags', 'man', 'manj', 'manh', 'mad', 'mal', 'malg', 'malm', 'malb', 'mals', 'malt', 'malp', 'malh', 'mam', 'mab', 'mabs', 'mas', 'mass', 'mang', 'maj', 'mac', 'mak', 'mat', 'map', 'mah', 'mae', 'maeg', 'maegg', 'maegs', 'maen', 'maenj', 'maenh', 'maed', 'mael', 'maelg', 'maelm', 'maelb', 'maels', 'maelt', 'maelp', 'maelh', 'maem', 'maeb', 'maebs', 'maes', 'maess', 'maeng', 'maej', 'maec', 'maek', 'maet', 'maep', 'maeh'];
<?php return ['mya', 'myag', 'myagg', 'myags', 'myan', 'myanj', 'myanh', 'myad', 'myal', 'myalg', 'myalm', 'myalb', 'myals', 'myalt', 'myalp', 'myalh', 'myam', 'myab', 'myabs', 'myas', 'myass', 'myang', 'myaj', 'myac', 'myak', 'myat', 'myap', 'myah', 'myae', 'myaeg', 'myaegg', 'myaegs', 'myaen', 'myaenj', 'myaenh', 'myaed', 'myael', 'myaelg', 'myaelm', 'myaelb', 'myaels', 'myaelt', 'myaelp', 'myaelh', 'myaem', 'myaeb', 'myaebs', 'myaes', 'myaess', 'myaeng', 'myaej', 'myaec', 'myaek', 'myaet', 'myaep', 'myaeh', 'meo', 'meog', 'meogg', 'meogs', 'meon', 'meonj', 'meonh', 'meod', 'meol', 'meolg', 'meolm', 'meolb', 'meols', 'meolt', 'meolp', 'meolh', 'meom', 'meob', 'meobs', 'meos', 'meoss', 'meong', 'meoj', 'meoc', 'meok', 'meot', 'meop', 'meoh', 'me', 'meg', 'megg', 'megs', 'men', 'menj', 'menh', 'med', 'mel', 'melg', 'melm', 'melb', 'mels', 'melt', 'melp', 'melh', 'mem', 'meb', 'mebs', 'mes', 'mess', 'meng', 'mej', 'mec', 'mek', 'met', 'mep', 'meh', 'myeo', 'myeog', 'myeogg', 'myeogs', 'myeon', 'myeonj', 'myeonh', 'myeod', 'myeol', 'myeolg', 'myeolm', 'myeolb', 'myeols', 'myeolt', 'myeolp', 'myeolh', 'myeom', 'myeob', 'myeobs', 'myeos', 'myeoss', 'myeong', 'myeoj', 'myeoc', 'myeok', 'myeot', 'myeop', 'myeoh', 'mye', 'myeg', 'myegg', 'myegs', 'myen', 'myenj', 'myenh', 'myed', 'myel', 'myelg', 'myelm', 'myelb', 'myels', 'myelt', 'myelp', 'myelh', 'myem', 'myeb', 'myebs', 'myes', 'myess', 'myeng', 'myej', 'myec', 'myek', 'myet', 'myep', 'myeh', 'mo', 'mog', 'mogg', 'mogs', 'mon', 'monj', 'monh', 'mod', 'mol', 'molg', 'molm', 'molb', 'mols', 'molt', 'molp', 'molh', 'mom', 'mob', 'mobs', 'mos', 'moss', 'mong', 'moj', 'moc', 'mok', 'mot', 'mop', 'moh', 'mwa', 'mwag', 'mwagg', 'mwags', 'mwan', 'mwanj', 'mwanh', 'mwad', 'mwal', 'mwalg', 'mwalm', 'mwalb', 'mwals', 'mwalt', 'mwalp', 'mwalh', 'mwam', 'mwab', 'mwabs', 'mwas', 'mwass', 'mwang', 'mwaj', 'mwac', 'mwak', 'mwat', 'mwap', 'mwah', 'mwae', 'mwaeg', 'mwaegg', 'mwaegs', 'mwaen', 'mwaenj', 'mwaenh', 'mwaed', 'mwael', 'mwaelg', 'mwaelm', 'mwaelb', 'mwaels', 'mwaelt', 'mwaelp', 'mwaelh', 'mwaem', 'mwaeb', 'mwaebs', 'mwaes', 'mwaess', 'mwaeng', 'mwaej', 'mwaec', 'mwaek', 'mwaet', 'mwaep', 'mwaeh', 'moe', 'moeg', 'moegg', 'moegs'];
<?php return ['moen', 'moenj', 'moenh', 'moed', 'moel', 'moelg', 'moelm', 'moelb', 'moels', 'moelt', 'moelp', 'moelh', 'moem', 'moeb', 'moebs', 'moes', 'moess', 'moeng', 'moej', 'moec', 'moek', 'moet', 'moep', 'moeh', 'myo', 'myog', 'myogg', 'myogs', 'myon', 'myonj', 'myonh', 'myod', 'myol', 'myolg', 'myolm', 'myolb', 'myols', 'myolt', 'myolp', 'myolh', 'myom', 'myob', 'myobs', 'myos', 'myoss', 'myong', 'myoj', 'myoc', 'myok', 'myot', 'myop', 'myoh', 'mu', 'mug', 'mugg', 'mugs', 'mun', 'munj', 'munh', 'mud', 'mul', 'mulg', 'mulm', 'mulb', 'muls', 'mult', 'mulp', 'mulh', 'mum', 'mub', 'mubs', 'mus', 'muss', 'mung', 'muj', 'muc', 'muk', 'mut', 'mup', 'muh', 'mweo', 'mweog', 'mweogg', 'mweogs', 'mweon', 'mweonj', 'mweonh', 'mweod', 'mweol', 'mweolg', 'mweolm', 'mweolb', 'mweols', 'mweolt', 'mweolp', 'mweolh', 'mweom', 'mweob', 'mweobs', 'mweos', 'mweoss', 'mweong', 'mweoj', 'mweoc', 'mweok', 'mweot', 'mweop', 'mweoh', 'mwe', 'mweg', 'mwegg', 'mwegs', 'mwen', 'mwenj', 'mwenh', 'mwed', 'mwel', 'mwelg', 'mwelm', 'mwelb', 'mwels', 'mwelt', 'mwelp', 'mwelh', 'mwem', 'mweb', 'mwebs', 'mwes', 'mwess', 'mweng', 'mwej', 'mwec', 'mwek', 'mwet', 'mwep', 'mweh', 'mwi', 'mwig', 'mwigg', 'mwigs', 'mwin', 'mwinj', 'mwinh', 'mwid', 'mwil', 'mwilg', 'mwilm', 'mwilb', 'mwils', 'mwilt', 'mwilp', 'mwilh', 'mwim', 'mwib', 'mwibs', 'mwis', 'mwiss', 'mwing', 'mwij', 'mwic', 'mwik', 'mwit', 'mwip', 'mwih', 'myu', 'myug', 'myugg', 'myugs', 'myun', 'myunj', 'myunh', 'myud', 'myul', 'myulg', 'myulm', 'myulb', 'myuls', 'myult', 'myulp', 'myulh', 'myum', 'myub', 'myubs', 'myus', 'myuss', 'myung', 'myuj', 'myuc', 'myuk', 'myut', 'myup', 'myuh', 'meu', 'meug', 'meugg', 'meugs', 'meun', 'meunj', 'meunh', 'meud', 'meul', 'meulg', 'meulm', 'meulb', 'meuls', 'meult', 'meulp', 'meulh', 'meum', 'meub', 'meubs', 'meus', 'meuss', 'meung', 'meuj', 'meuc', 'meuk', 'meut', 'meup', 'meuh', 'myi', 'myig', 'myigg', 'myigs', 'myin', 'myinj', 'myinh', 'myid', 'myil', 'myilg', 'myilm', 'myilb', 'myils', 'myilt', 'myilp', 'myilh', 'myim', 'myib', 'myibs', 'myis', 'myiss', 'mying', 'myij', 'myic', 'myik', 'myit', 'myip', 'myih', 'mi', 'mig', 'migg', 'migs', 'min', 'minj', 'minh', 'mid'];
<?php return ['mil', 'milg', 'milm', 'milb', 'mils', 'milt', 'milp', 'milh', 'mim', 'mib', 'mibs', 'mis', 'miss', 'ming', 'mij', 'mic', 'mik', 'mit', 'mip', 'mih', 'ba', 'bag', 'bagg', 'bags', 'ban', 'banj', 'banh', 'bad', 'bal', 'balg', 'balm', 'balb', 'bals', 'balt', 'balp', 'balh', 'bam', 'bab', 'babs', 'bas', 'bass', 'bang', 'baj', 'bac', 'bak', 'bat', 'bap', 'bah', 'bae', 'baeg', 'baegg', 'baegs', 'baen', 'baenj', 'baenh', 'baed', 'bael', 'baelg', 'baelm', 'baelb', 'baels', 'baelt', 'baelp', 'baelh', 'baem', 'baeb', 'baebs', 'baes', 'baess', 'baeng', 'baej', 'baec', 'baek', 'baet', 'baep', 'baeh', 'bya', 'byag', 'byagg', 'byags', 'byan', 'byanj', 'byanh', 'byad', 'byal', 'byalg', 'byalm', 'byalb', 'byals', 'byalt', 'byalp', 'byalh', 'byam', 'byab', 'byabs', 'byas', 'byass', 'byang', 'byaj', 'byac', 'byak', 'byat', 'byap', 'byah', 'byae', 'byaeg', 'byaegg', 'byaegs', 'byaen', 'byaenj', 'byaenh', 'byaed', 'byael', 'byaelg', 'byaelm', 'byaelb', 'byaels', 'byaelt', 'byaelp', 'byaelh', 'byaem', 'byaeb', 'byaebs', 'byaes', 'byaess', 'byaeng', 'byaej', 'byaec', 'byaek', 'byaet', 'byaep', 'byaeh', 'beo', 'beog', 'beogg', 'beogs', 'beon', 'beonj', 'beonh', 'beod', 'beol', 'beolg', 'beolm', 'beolb', 'beols', 'beolt', 'beolp', 'beolh', 'beom', 'beob', 'beobs', 'beos', 'beoss', 'beong', 'beoj', 'beoc', 'beok', 'beot', 'beop', 'beoh', 'be', 'beg', 'begg', 'begs', 'ben', 'benj', 'benh', 'bed', 'bel', 'belg', 'belm', 'belb', 'bels', 'belt', 'belp', 'belh', 'bem', 'beb', 'bebs', 'bes', 'bess', 'beng', 'bej', 'bec', 'bek', 'bet', 'bep', 'beh', 'byeo', 'byeog', 'byeogg', 'byeogs', 'byeon', 'byeonj', 'byeonh', 'byeod', 'byeol', 'byeolg', 'byeolm', 'byeolb', 'byeols', 'byeolt', 'byeolp', 'byeolh', 'byeom', 'byeob', 'byeobs', 'byeos', 'byeoss', 'byeong', 'byeoj', 'byeoc', 'byeok', 'byeot', 'byeop', 'byeoh', 'bye', 'byeg', 'byegg', 'byegs', 'byen', 'byenj', 'byenh', 'byed', 'byel', 'byelg', 'byelm', 'byelb', 'byels', 'byelt', 'byelp', 'byelh', 'byem', 'byeb', 'byebs', 'byes', 'byess', 'byeng', 'byej', 'byec', 'byek', 'byet', 'byep', 'byeh', 'bo', 'bog', 'bogg', 'bogs', 'bon', 'bonj', 'bonh', 'bod', 'bol', 'bolg', 'bolm', 'bolb'];
<?php return ['bols', 'bolt', 'bolp', 'bolh', 'bom', 'bob', 'bobs', 'bos', 'boss', 'bong', 'boj', 'boc', 'bok', 'bot', 'bop', 'boh', 'bwa', 'bwag', 'bwagg', 'bwags', 'bwan', 'bwanj', 'bwanh', 'bwad', 'bwal', 'bwalg', 'bwalm', 'bwalb', 'bwals', 'bwalt', 'bwalp', 'bwalh', 'bwam', 'bwab', 'bwabs', 'bwas', 'bwass', 'bwang', 'bwaj', 'bwac', 'bwak', 'bwat', 'bwap', 'bwah', 'bwae', 'bwaeg', 'bwaegg', 'bwaegs', 'bwaen', 'bwaenj', 'bwaenh', 'bwaed', 'bwael', 'bwaelg', 'bwaelm', 'bwaelb', 'bwaels', 'bwaelt', 'bwaelp', 'bwaelh', 'bwaem', 'bwaeb', 'bwaebs', 'bwaes', 'bwaess', 'bwaeng', 'bwaej', 'bwaec', 'bwaek', 'bwaet', 'bwaep', 'bwaeh', 'boe', 'boeg', 'boegg', 'boegs', 'boen', 'boenj', 'boenh', 'boed', 'boel', 'boelg', 'boelm', 'boelb', 'boels', 'boelt', 'boelp', 'boelh', 'boem', 'boeb', 'boebs', 'boes', 'boess', 'boeng', 'boej', 'boec', 'boek', 'boet', 'boep', 'boeh', 'byo', 'byog', 'byogg', 'byogs', 'byon', 'byonj', 'byonh', 'byod', 'byol', 'byolg', 'byolm', 'byolb', 'byols', 'byolt', 'byolp', 'byolh', 'byom', 'byob', 'byobs', 'byos', 'byoss', 'byong', 'byoj', 'byoc', 'byok', 'byot', 'byop', 'byoh', 'bu', 'bug', 'bugg', 'bugs', 'bun', 'bunj', 'bunh', 'bud', 'bul', 'bulg', 'bulm', 'bulb', 'buls', 'bult', 'bulp', 'bulh', 'bum', 'bub', 'bubs', 'bus', 'buss', 'bung', 'buj', 'buc', 'buk', 'but', 'bup', 'buh', 'bweo', 'bweog', 'bweogg', 'bweogs', 'bweon', 'bweonj', 'bweonh', 'bweod', 'bweol', 'bweolg', 'bweolm', 'bweolb', 'bweols', 'bweolt', 'bweolp', 'bweolh', 'bweom', 'bweob', 'bweobs', 'bweos', 'bweoss', 'bweong', 'bweoj', 'bweoc', 'bweok', 'bweot', 'bweop', 'bweoh', 'bwe', 'bweg', 'bwegg', 'bwegs', 'bwen', 'bwenj', 'bwenh', 'bwed', 'bwel', 'bwelg', 'bwelm', 'bwelb', 'bwels', 'bwelt', 'bwelp', 'bwelh', 'bwem', 'bweb', 'bwebs', 'bwes', 'bwess', 'bweng', 'bwej', 'bwec', 'bwek', 'bwet', 'bwep', 'bweh', 'bwi', 'bwig', 'bwigg', 'bwigs', 'bwin', 'bwinj', 'bwinh', 'bwid', 'bwil', 'bwilg', 'bwilm', 'bwilb', 'bwils', 'bwilt', 'bwilp', 'bwilh', 'bwim', 'bwib', 'bwibs', 'bwis', 'bwiss', 'bwing', 'bwij', 'bwic', 'bwik', 'bwit', 'bwip', 'bwih', 'byu', 'byug', 'byugg', 'byugs', 'byun', 'byunj', 'byunh', 'byud', 'byul', 'byulg', 'byulm', 'byulb', 'byuls', 'byult', 'byulp', 'byulh'];
<?php return ['byum', 'byub', 'byubs', 'byus', 'byuss', 'byung', 'byuj', 'byuc', 'byuk', 'byut', 'byup', 'byuh', 'beu', 'beug', 'beugg', 'beugs', 'beun', 'beunj', 'beunh', 'beud', 'beul', 'beulg', 'beulm', 'beulb', 'beuls', 'beult', 'beulp', 'beulh', 'beum', 'beub', 'beubs', 'beus', 'beuss', 'beung', 'beuj', 'beuc', 'beuk', 'beut', 'beup', 'beuh', 'byi', 'byig', 'byigg', 'byigs', 'byin', 'byinj', 'byinh', 'byid', 'byil', 'byilg', 'byilm', 'byilb', 'byils', 'byilt', 'byilp', 'byilh', 'byim', 'byib', 'byibs', 'byis', 'byiss', 'bying', 'byij', 'byic', 'byik', 'byit', 'byip', 'byih', 'bi', 'big', 'bigg', 'bigs', 'bin', 'binj', 'binh', 'bid', 'bil', 'bilg', 'bilm', 'bilb', 'bils', 'bilt', 'bilp', 'bilh', 'bim', 'bib', 'bibs', 'bis', 'biss', 'bing', 'bij', 'bic', 'bik', 'bit', 'bip', 'bih', 'bba', 'bbag', 'bbagg', 'bbags', 'bban', 'bbanj', 'bbanh', 'bbad', 'bbal', 'bbalg', 'bbalm', 'bbalb', 'bbals', 'bbalt', 'bbalp', 'bbalh', 'bbam', 'bbab', 'bbabs', 'bbas', 'bbass', 'bbang', 'bbaj', 'bbac', 'bbak', 'bbat', 'bbap', 'bbah', 'bbae', 'bbaeg', 'bbaegg', 'bbaegs', 'bbaen', 'bbaenj', 'bbaenh', 'bbaed', 'bbael', 'bbaelg', 'bbaelm', 'bbaelb', 'bbaels', 'bbaelt', 'bbaelp', 'bbaelh', 'bbaem', 'bbaeb', 'bbaebs', 'bbaes', 'bbaess', 'bbaeng', 'bbaej', 'bbaec', 'bbaek', 'bbaet', 'bbaep', 'bbaeh', 'bbya', 'bbyag', 'bbyagg', 'bbyags', 'bbyan', 'bbyanj', 'bbyanh', 'bbyad', 'bbyal', 'bbyalg', 'bbyalm', 'bbyalb', 'bbyals', 'bbyalt', 'bbyalp', 'bbyalh', 'bbyam', 'bbyab', 'bbyabs', 'bbyas', 'bbyass', 'bbyang', 'bbyaj', 'bbyac', 'bbyak', 'bbyat', 'bbyap', 'bbyah', 'bbyae', 'bbyaeg', 'bbyaegg', 'bbyaegs', 'bbyaen', 'bbyaenj', 'bbyaenh', 'bbyaed', 'bbyael', 'bbyaelg', 'bbyaelm', 'bbyaelb', 'bbyaels', 'bbyaelt', 'bbyaelp', 'bbyaelh', 'bbyaem', 'bbyaeb', 'bbyaebs', 'bbyaes', 'bbyaess', 'bbyaeng', 'bbyaej', 'bbyaec', 'bbyaek', 'bbyaet', 'bbyaep', 'bbyaeh', 'bbeo', 'bbeog', 'bbeogg', 'bbeogs', 'bbeon', 'bbeonj', 'bbeonh', 'bbeod', 'bbeol', 'bbeolg', 'bbeolm', 'bbeolb', 'bbeols', 'bbeolt', 'bbeolp', 'bbeolh', 'bbeom', 'bbeob', 'bbeobs', 'bbeos', 'bbeoss', 'bbeong', 'bbeoj', 'bbeoc', 'bbeok', 'bbeot', 'bbeop', 'bbeoh', 'bbe', 'bbeg', 'bbegg', 'bbegs', 'bben', 'bbenj', 'bbenh', 'bbed', 'bbel', 'bbelg', 'bbelm', 'bbelb', 'bbels', 'bbelt', 'bbelp', 'bbelh', 'bbem', 'bbeb', 'bbebs', 'bbes'];
<?php return ['bbess', 'bbeng', 'bbej', 'bbec', 'bbek', 'bbet', 'bbep', 'bbeh', 'bbyeo', 'bbyeog', 'bbyeogg', 'bbyeogs', 'bbyeon', 'bbyeonj', 'bbyeonh', 'bbyeod', 'bbyeol', 'bbyeolg', 'bbyeolm', 'bbyeolb', 'bbyeols', 'bbyeolt', 'bbyeolp', 'bbyeolh', 'bbyeom', 'bbyeob', 'bbyeobs', 'bbyeos', 'bbyeoss', 'bbyeong', 'bbyeoj', 'bbyeoc', 'bbyeok', 'bbyeot', 'bbyeop', 'bbyeoh', 'bbye', 'bbyeg', 'bbyegg', 'bbyegs', 'bbyen', 'bbyenj', 'bbyenh', 'bbyed', 'bbyel', 'bbyelg', 'bbyelm', 'bbyelb', 'bbyels', 'bbyelt', 'bbyelp', 'bbyelh', 'bbyem', 'bbyeb', 'bbyebs', 'bbyes', 'bbyess', 'bbyeng', 'bbyej', 'bbyec', 'bbyek', 'bbyet', 'bbyep', 'bbyeh', 'bbo', 'bbog', 'bbogg', 'bbogs', 'bbon', 'bbonj', 'bbonh', 'bbod', 'bbol', 'bbolg', 'bbolm', 'bbolb', 'bbols', 'bbolt', 'bbolp', 'bbolh', 'bbom', 'bbob', 'bbobs', 'bbos', 'bboss', 'bbong', 'bboj', 'bboc', 'bbok', 'bbot', 'bbop', 'bboh', 'bbwa', 'bbwag', 'bbwagg', 'bbwags', 'bbwan', 'bbwanj', 'bbwanh', 'bbwad', 'bbwal', 'bbwalg', 'bbwalm', 'bbwalb', 'bbwals', 'bbwalt', 'bbwalp', 'bbwalh', 'bbwam', 'bbwab', 'bbwabs', 'bbwas', 'bbwass', 'bbwang', 'bbwaj', 'bbwac', 'bbwak', 'bbwat', 'bbwap', 'bbwah', 'bbwae', 'bbwaeg', 'bbwaegg', 'bbwaegs', 'bbwaen', 'bbwaenj', 'bbwaenh', 'bbwaed', 'bbwael', 'bbwaelg', 'bbwaelm', 'bbwaelb', 'bbwaels', 'bbwaelt', 'bbwaelp', 'bbwaelh', 'bbwaem', 'bbwaeb', 'bbwaebs', 'bbwaes', 'bbwaess', 'bbwaeng', 'bbwaej', 'bbwaec', 'bbwaek', 'bbwaet', 'bbwaep', 'bbwaeh', 'bboe', 'bboeg', 'bboegg', 'bboegs', 'bboen', 'bboenj', 'bboenh', 'bboed', 'bboel', 'bboelg', 'bboelm', 'bboelb', 'bboels', 'bboelt', 'bboelp', 'bboelh', 'bboem', 'bboeb', 'bboebs', 'bboes', 'bboess', 'bboeng', 'bboej', 'bboec', 'bboek', 'bboet', 'bboep', 'bboeh', 'bbyo', 'bbyog', 'bbyogg', 'bbyogs', 'bbyon', 'bbyonj', 'bbyonh', 'bbyod', 'bbyol', 'bbyolg', 'bbyolm', 'bbyolb', 'bbyols', 'bbyolt', 'bbyolp', 'bbyolh', 'bbyom', 'bbyob', 'bbyobs', 'bbyos', 'bbyoss', 'bbyong', 'bbyoj', 'bbyoc', 'bbyok', 'bbyot', 'bbyop', 'bbyoh', 'bbu', 'bbug', 'bbugg', 'bbugs', 'bbun', 'bbunj', 'bbunh', 'bbud', 'bbul', 'bbulg', 'bbulm', 'bbulb', 'bbuls', 'bbult', 'bbulp', 'bbulh', 'bbum', 'bbub', 'bbubs', 'bbus', 'bbuss', 'bbung', 'bbuj', 'bbuc', 'bbuk', 'bbut', 'bbup', 'bbuh', 'bbweo', 'bbweog', 'bbweogg', 'bbweogs', 'bbweon', 'bbweonj', 'bbweonh', 'bbweod', 'bbweol', 'bbweolg', 'bbweolm', 'bbweolb', 'bbweols', 'bbweolt', 'bbweolp', 'bbweolh', 'bbweom', 'bbweob', 'bbweobs', 'bbweos', 'bbweoss', 'bbweong', 'bbweoj', 'bbweoc'];
<?php return ['bbweok', 'bbweot', 'bbweop', 'bbweoh', 'bbwe', 'bbweg', 'bbwegg', 'bbwegs', 'bbwen', 'bbwenj', 'bbwenh', 'bbwed', 'bbwel', 'bbwelg', 'bbwelm', 'bbwelb', 'bbwels', 'bbwelt', 'bbwelp', 'bbwelh', 'bbwem', 'bbweb', 'bbwebs', 'bbwes', 'bbwess', 'bbweng', 'bbwej', 'bbwec', 'bbwek', 'bbwet', 'bbwep', 'bbweh', 'bbwi', 'bbwig', 'bbwigg', 'bbwigs', 'bbwin', 'bbwinj', 'bbwinh', 'bbwid', 'bbwil', 'bbwilg', 'bbwilm', 'bbwilb', 'bbwils', 'bbwilt', 'bbwilp', 'bbwilh', 'bbwim', 'bbwib', 'bbwibs', 'bbwis', 'bbwiss', 'bbwing', 'bbwij', 'bbwic', 'bbwik', 'bbwit', 'bbwip', 'bbwih', 'bbyu', 'bbyug', 'bbyugg', 'bbyugs', 'bbyun', 'bbyunj', 'bbyunh', 'bbyud', 'bbyul', 'bbyulg', 'bbyulm', 'bbyulb', 'bbyuls', 'bbyult', 'bbyulp', 'bbyulh', 'bbyum', 'bbyub', 'bbyubs', 'bbyus', 'bbyuss', 'bbyung', 'bbyuj', 'bbyuc', 'bbyuk', 'bbyut', 'bbyup', 'bbyuh', 'bbeu', 'bbeug', 'bbeugg', 'bbeugs', 'bbeun', 'bbeunj', 'bbeunh', 'bbeud', 'bbeul', 'bbeulg', 'bbeulm', 'bbeulb', 'bbeuls', 'bbeult', 'bbeulp', 'bbeulh', 'bbeum', 'bbeub', 'bbeubs', 'bbeus', 'bbeuss', 'bbeung', 'bbeuj', 'bbeuc', 'bbeuk', 'bbeut', 'bbeup', 'bbeuh', 'bbyi', 'bbyig', 'bbyigg', 'bbyigs', 'bbyin', 'bbyinj', 'bbyinh', 'bbyid', 'bbyil', 'bbyilg', 'bbyilm', 'bbyilb', 'bbyils', 'bbyilt', 'bbyilp', 'bbyilh', 'bbyim', 'bbyib', 'bbyibs', 'bbyis', 'bbyiss', 'bbying', 'bbyij', 'bbyic', 'bbyik', 'bbyit', 'bbyip', 'bbyih', 'bbi', 'bbig', 'bbigg', 'bbigs', 'bbin', 'bbinj', 'bbinh', 'bbid', 'bbil', 'bbilg', 'bbilm', 'bbilb', 'bbils', 'bbilt', 'bbilp', 'bbilh', 'bbim', 'bbib', 'bbibs', 'bbis', 'bbiss', 'bbing', 'bbij', 'bbic', 'bbik', 'bbit', 'bbip', 'bbih', 'sa', 'sag', 'sagg', 'sags', 'san', 'sanj', 'sanh', 'sad', 'sal', 'salg', 'salm', 'salb', 'sals', 'salt', 'salp', 'salh', 'sam', 'sab', 'sabs', 'sas', 'sass', 'sang', 'saj', 'sac', 'sak', 'sat', 'sap', 'sah', 'sae', 'saeg', 'saegg', 'saegs', 'saen', 'saenj', 'saenh', 'saed', 'sael', 'saelg', 'saelm', 'saelb', 'saels', 'saelt', 'saelp', 'saelh', 'saem', 'saeb', 'saebs', 'saes', 'saess', 'saeng', 'saej', 'saec', 'saek', 'saet', 'saep', 'saeh', 'sya', 'syag', 'syagg', 'syags', 'syan', 'syanj', 'syanh', 'syad', 'syal', 'syalg', 'syalm', 'syalb', 'syals', 'syalt', 'syalp', 'syalh', 'syam', 'syab', 'syabs', 'syas', 'syass', 'syang', 'syaj', 'syac', 'syak', 'syat', 'syap', 'syah'];
<?php return ['syae', 'syaeg', 'syaegg', 'syaegs', 'syaen', 'syaenj', 'syaenh', 'syaed', 'syael', 'syaelg', 'syaelm', 'syaelb', 'syaels', 'syaelt', 'syaelp', 'syaelh', 'syaem', 'syaeb', 'syaebs', 'syaes', 'syaess', 'syaeng', 'syaej', 'syaec', 'syaek', 'syaet', 'syaep', 'syaeh', 'seo', 'seog', 'seogg', 'seogs', 'seon', 'seonj', 'seonh', 'seod', 'seol', 'seolg', 'seolm', 'seolb', 'seols', 'seolt', 'seolp', 'seolh', 'seom', 'seob', 'seobs', 'seos', 'seoss', 'seong', 'seoj', 'seoc', 'seok', 'seot', 'seop', 'seoh', 'se', 'seg', 'segg', 'segs', 'sen', 'senj', 'senh', 'sed', 'sel', 'selg', 'selm', 'selb', 'sels', 'selt', 'selp', 'selh', 'sem', 'seb', 'sebs', 'ses', 'sess', 'seng', 'sej', 'sec', 'sek', 'set', 'sep', 'seh', 'syeo', 'syeog', 'syeogg', 'syeogs', 'syeon', 'syeonj', 'syeonh', 'syeod', 'syeol', 'syeolg', 'syeolm', 'syeolb', 'syeols', 'syeolt', 'syeolp', 'syeolh', 'syeom', 'syeob', 'syeobs', 'syeos', 'syeoss', 'syeong', 'syeoj', 'syeoc', 'syeok', 'syeot', 'syeop', 'syeoh', 'sye', 'syeg', 'syegg', 'syegs', 'syen', 'syenj', 'syenh', 'syed', 'syel', 'syelg', 'syelm', 'syelb', 'syels', 'syelt', 'syelp', 'syelh', 'syem', 'syeb', 'syebs', 'syes', 'syess', 'syeng', 'syej', 'syec', 'syek', 'syet', 'syep', 'syeh', 'so', 'sog', 'sogg', 'sogs', 'son', 'sonj', 'sonh', 'sod', 'sol', 'solg', 'solm', 'solb', 'sols', 'solt', 'solp', 'solh', 'som', 'sob', 'sobs', 'sos', 'soss', 'song', 'soj', 'soc', 'sok', 'sot', 'sop', 'soh', 'swa', 'swag', 'swagg', 'swags', 'swan', 'swanj', 'swanh', 'swad', 'swal', 'swalg', 'swalm', 'swalb', 'swals', 'swalt', 'swalp', 'swalh', 'swam', 'swab', 'swabs', 'swas', 'swass', 'swang', 'swaj', 'swac', 'swak', 'swat', 'swap', 'swah', 'swae', 'swaeg', 'swaegg', 'swaegs', 'swaen', 'swaenj', 'swaenh', 'swaed', 'swael', 'swaelg', 'swaelm', 'swaelb', 'swaels', 'swaelt', 'swaelp', 'swaelh', 'swaem', 'swaeb', 'swaebs', 'swaes', 'swaess', 'swaeng', 'swaej', 'swaec', 'swaek', 'swaet', 'swaep', 'swaeh', 'soe', 'soeg', 'soegg', 'soegs', 'soen', 'soenj', 'soenh', 'soed', 'soel', 'soelg', 'soelm', 'soelb', 'soels', 'soelt', 'soelp', 'soelh', 'soem', 'soeb', 'soebs', 'soes', 'soess', 'soeng', 'soej', 'soec', 'soek', 'soet', 'soep', 'soeh', 'syo', 'syog', 'syogg', 'syogs'];
<?php return ['syon', 'syonj', 'syonh', 'syod', 'syol', 'syolg', 'syolm', 'syolb', 'syols', 'syolt', 'syolp', 'syolh', 'syom', 'syob', 'syobs', 'syos', 'syoss', 'syong', 'syoj', 'syoc', 'syok', 'syot', 'syop', 'syoh', 'su', 'sug', 'sugg', 'sugs', 'sun', 'sunj', 'sunh', 'sud', 'sul', 'sulg', 'sulm', 'sulb', 'suls', 'sult', 'sulp', 'sulh', 'sum', 'sub', 'subs', 'sus', 'suss', 'sung', 'suj', 'suc', 'suk', 'sut', 'sup', 'suh', 'sweo', 'sweog', 'sweogg', 'sweogs', 'sweon', 'sweonj', 'sweonh', 'sweod', 'sweol', 'sweolg', 'sweolm', 'sweolb', 'sweols', 'sweolt', 'sweolp', 'sweolh', 'sweom', 'sweob', 'sweobs', 'sweos', 'sweoss', 'sweong', 'sweoj', 'sweoc', 'sweok', 'sweot', 'sweop', 'sweoh', 'swe', 'sweg', 'swegg', 'swegs', 'swen', 'swenj', 'swenh', 'swed', 'swel', 'swelg', 'swelm', 'swelb', 'swels', 'swelt', 'swelp', 'swelh', 'swem', 'sweb', 'swebs', 'swes', 'swess', 'sweng', 'swej', 'swec', 'swek', 'swet', 'swep', 'sweh', 'swi', 'swig', 'swigg', 'swigs', 'swin', 'swinj', 'swinh', 'swid', 'swil', 'swilg', 'swilm', 'swilb', 'swils', 'swilt', 'swilp', 'swilh', 'swim', 'swib', 'swibs', 'swis', 'swiss', 'swing', 'swij', 'swic', 'swik', 'swit', 'swip', 'swih', 'syu', 'syug', 'syugg', 'syugs', 'syun', 'syunj', 'syunh', 'syud', 'syul', 'syulg', 'syulm', 'syulb', 'syuls', 'syult', 'syulp', 'syulh', 'syum', 'syub', 'syubs', 'syus', 'syuss', 'syung', 'syuj', 'syuc', 'syuk', 'syut', 'syup', 'syuh', 'seu', 'seug', 'seugg', 'seugs', 'seun', 'seunj', 'seunh', 'seud', 'seul', 'seulg', 'seulm', 'seulb', 'seuls', 'seult', 'seulp', 'seulh', 'seum', 'seub', 'seubs', 'seus', 'seuss', 'seung', 'seuj', 'seuc', 'seuk', 'seut', 'seup', 'seuh', 'syi', 'syig', 'syigg', 'syigs', 'syin', 'syinj', 'syinh', 'syid', 'syil', 'syilg', 'syilm', 'syilb', 'syils', 'syilt', 'syilp', 'syilh', 'syim', 'syib', 'syibs', 'syis', 'syiss', 'sying', 'syij', 'syic', 'syik', 'syit', 'syip', 'syih', 'si', 'sig', 'sigg', 'sigs', 'sin', 'sinj', 'sinh', 'sid', 'sil', 'silg', 'silm', 'silb', 'sils', 'silt', 'silp', 'silh', 'sim', 'sib', 'sibs', 'sis', 'siss', 'sing', 'sij', 'sic', 'sik', 'sit', 'sip', 'sih', 'ssa', 'ssag', 'ssagg', 'ssags', 'ssan', 'ssanj', 'ssanh', 'ssad'];
<?php return ['ssal', 'ssalg', 'ssalm', 'ssalb', 'ssals', 'ssalt', 'ssalp', 'ssalh', 'ssam', 'ssab', 'ssabs', 'ssas', 'ssass', 'ssang', 'ssaj', 'ssac', 'ssak', 'ssat', 'ssap', 'ssah', 'ssae', 'ssaeg', 'ssaegg', 'ssaegs', 'ssaen', 'ssaenj', 'ssaenh', 'ssaed', 'ssael', 'ssaelg', 'ssaelm', 'ssaelb', 'ssaels', 'ssaelt', 'ssaelp', 'ssaelh', 'ssaem', 'ssaeb', 'ssaebs', 'ssaes', 'ssaess', 'ssaeng', 'ssaej', 'ssaec', 'ssaek', 'ssaet', 'ssaep', 'ssaeh', 'ssya', 'ssyag', 'ssyagg', 'ssyags', 'ssyan', 'ssyanj', 'ssyanh', 'ssyad', 'ssyal', 'ssyalg', 'ssyalm', 'ssyalb', 'ssyals', 'ssyalt', 'ssyalp', 'ssyalh', 'ssyam', 'ssyab', 'ssyabs', 'ssyas', 'ssyass', 'ssyang', 'ssyaj', 'ssyac', 'ssyak', 'ssyat', 'ssyap', 'ssyah', 'ssyae', 'ssyaeg', 'ssyaegg', 'ssyaegs', 'ssyaen', 'ssyaenj', 'ssyaenh', 'ssyaed', 'ssyael', 'ssyaelg', 'ssyaelm', 'ssyaelb', 'ssyaels', 'ssyaelt', 'ssyaelp', 'ssyaelh', 'ssyaem', 'ssyaeb', 'ssyaebs', 'ssyaes', 'ssyaess', 'ssyaeng', 'ssyaej', 'ssyaec', 'ssyaek', 'ssyaet', 'ssyaep', 'ssyaeh', 'sseo', 'sseog', 'sseogg', 'sseogs', 'sseon', 'sseonj', 'sseonh', 'sseod', 'sseol', 'sseolg', 'sseolm', 'sseolb', 'sseols', 'sseolt', 'sseolp', 'sseolh', 'sseom', 'sseob', 'sseobs', 'sseos', 'sseoss', 'sseong', 'sseoj', 'sseoc', 'sseok', 'sseot', 'sseop', 'sseoh', 'sse', 'sseg', 'ssegg', 'ssegs', 'ssen', 'ssenj', 'ssenh', 'ssed', 'ssel', 'sselg', 'sselm', 'sselb', 'ssels', 'sselt', 'sselp', 'sselh', 'ssem', 'sseb', 'ssebs', 'sses', 'ssess', 'sseng', 'ssej', 'ssec', 'ssek', 'sset', 'ssep', 'sseh', 'ssyeo', 'ssyeog', 'ssyeogg', 'ssyeogs', 'ssyeon', 'ssyeonj', 'ssyeonh', 'ssyeod', 'ssyeol', 'ssyeolg', 'ssyeolm', 'ssyeolb', 'ssyeols', 'ssyeolt', 'ssyeolp', 'ssyeolh', 'ssyeom', 'ssyeob', 'ssyeobs', 'ssyeos', 'ssyeoss', 'ssyeong', 'ssyeoj', 'ssyeoc', 'ssyeok', 'ssyeot', 'ssyeop', 'ssyeoh', 'ssye', 'ssyeg', 'ssyegg', 'ssyegs', 'ssyen', 'ssyenj', 'ssyenh', 'ssyed', 'ssyel', 'ssyelg', 'ssyelm', 'ssyelb', 'ssyels', 'ssyelt', 'ssyelp', 'ssyelh', 'ssyem', 'ssyeb', 'ssyebs', 'ssyes', 'ssyess', 'ssyeng', 'ssyej', 'ssyec', 'ssyek', 'ssyet', 'ssyep', 'ssyeh', 'sso', 'ssog', 'ssogg', 'ssogs', 'sson', 'ssonj', 'ssonh', 'ssod', 'ssol', 'ssolg', 'ssolm', 'ssolb', 'ssols', 'ssolt', 'ssolp', 'ssolh', 'ssom', 'ssob', 'ssobs', 'ssos', 'ssoss', 'ssong', 'ssoj', 'ssoc', 'ssok', 'ssot', 'ssop', 'ssoh', 'sswa', 'sswag', 'sswagg', 'sswags', 'sswan', 'sswanj', 'sswanh', 'sswad', 'sswal', 'sswalg', 'sswalm', 'sswalb'];
<?php return ['sswals', 'sswalt', 'sswalp', 'sswalh', 'sswam', 'sswab', 'sswabs', 'sswas', 'sswass', 'sswang', 'sswaj', 'sswac', 'sswak', 'sswat', 'sswap', 'sswah', 'sswae', 'sswaeg', 'sswaegg', 'sswaegs', 'sswaen', 'sswaenj', 'sswaenh', 'sswaed', 'sswael', 'sswaelg', 'sswaelm', 'sswaelb', 'sswaels', 'sswaelt', 'sswaelp', 'sswaelh', 'sswaem', 'sswaeb', 'sswaebs', 'sswaes', 'sswaess', 'sswaeng', 'sswaej', 'sswaec', 'sswaek', 'sswaet', 'sswaep', 'sswaeh', 'ssoe', 'ssoeg', 'ssoegg', 'ssoegs', 'ssoen', 'ssoenj', 'ssoenh', 'ssoed', 'ssoel', 'ssoelg', 'ssoelm', 'ssoelb', 'ssoels', 'ssoelt', 'ssoelp', 'ssoelh', 'ssoem', 'ssoeb', 'ssoebs', 'ssoes', 'ssoess', 'ssoeng', 'ssoej', 'ssoec', 'ssoek', 'ssoet', 'ssoep', 'ssoeh', 'ssyo', 'ssyog', 'ssyogg', 'ssyogs', 'ssyon', 'ssyonj', 'ssyonh', 'ssyod', 'ssyol', 'ssyolg', 'ssyolm', 'ssyolb', 'ssyols', 'ssyolt', 'ssyolp', 'ssyolh', 'ssyom', 'ssyob', 'ssyobs', 'ssyos', 'ssyoss', 'ssyong', 'ssyoj', 'ssyoc', 'ssyok', 'ssyot', 'ssyop', 'ssyoh', 'ssu', 'ssug', 'ssugg', 'ssugs', 'ssun', 'ssunj', 'ssunh', 'ssud', 'ssul', 'ssulg', 'ssulm', 'ssulb', 'ssuls', 'ssult', 'ssulp', 'ssulh', 'ssum', 'ssub', 'ssubs', 'ssus', 'ssuss', 'ssung', 'ssuj', 'ssuc', 'ssuk', 'ssut', 'ssup', 'ssuh', 'ssweo', 'ssweog', 'ssweogg', 'ssweogs', 'ssweon', 'ssweonj', 'ssweonh', 'ssweod', 'ssweol', 'ssweolg', 'ssweolm', 'ssweolb', 'ssweols', 'ssweolt', 'ssweolp', 'ssweolh', 'ssweom', 'ssweob', 'ssweobs', 'ssweos', 'ssweoss', 'ssweong', 'ssweoj', 'ssweoc', 'ssweok', 'ssweot', 'ssweop', 'ssweoh', 'sswe', 'ssweg', 'sswegg', 'sswegs', 'sswen', 'sswenj', 'sswenh', 'sswed', 'sswel', 'sswelg', 'sswelm', 'sswelb', 'sswels', 'sswelt', 'sswelp', 'sswelh', 'sswem', 'ssweb', 'sswebs', 'sswes', 'sswess', 'ssweng', 'sswej', 'sswec', 'sswek', 'sswet', 'sswep', 'ssweh', 'sswi', 'sswig', 'sswigg', 'sswigs', 'sswin', 'sswinj', 'sswinh', 'sswid', 'sswil', 'sswilg', 'sswilm', 'sswilb', 'sswils', 'sswilt', 'sswilp', 'sswilh', 'sswim', 'sswib', 'sswibs', 'sswis', 'sswiss', 'sswing', 'sswij', 'sswic', 'sswik', 'sswit', 'sswip', 'sswih', 'ssyu', 'ssyug', 'ssyugg', 'ssyugs', 'ssyun', 'ssyunj', 'ssyunh', 'ssyud', 'ssyul', 'ssyulg', 'ssyulm', 'ssyulb', 'ssyuls', 'ssyult', 'ssyulp', 'ssyulh', 'ssyum', 'ssyub', 'ssyubs', 'ssyus', 'ssyuss', 'ssyung', 'ssyuj', 'ssyuc', 'ssyuk', 'ssyut', 'ssyup', 'ssyuh', 'sseu', 'sseug', 'sseugg', 'sseugs', 'sseun', 'sseunj', 'sseunh', 'sseud', 'sseul', 'sseulg', 'sseulm', 'sseulb', 'sseuls', 'sseult', 'sseulp', 'sseulh'];
<?php return ['sseum', 'sseub', 'sseubs', 'sseus', 'sseuss', 'sseung', 'sseuj', 'sseuc', 'sseuk', 'sseut', 'sseup', 'sseuh', 'ssyi', 'ssyig', 'ssyigg', 'ssyigs', 'ssyin', 'ssyinj', 'ssyinh', 'ssyid', 'ssyil', 'ssyilg', 'ssyilm', 'ssyilb', 'ssyils', 'ssyilt', 'ssyilp', 'ssyilh', 'ssyim', 'ssyib', 'ssyibs', 'ssyis', 'ssyiss', 'ssying', 'ssyij', 'ssyic', 'ssyik', 'ssyit', 'ssyip', 'ssyih', 'ssi', 'ssig', 'ssigg', 'ssigs', 'ssin', 'ssinj', 'ssinh', 'ssid', 'ssil', 'ssilg', 'ssilm', 'ssilb', 'ssils', 'ssilt', 'ssilp', 'ssilh', 'ssim', 'ssib', 'ssibs', 'ssis', 'ssiss', 'ssing', 'ssij', 'ssic', 'ssik', 'ssit', 'ssip', 'ssih', 'a', 'ag', 'agg', 'ags', 'an', 'anj', 'anh', 'ad', 'al', 'alg', 'alm', 'alb', 'als', 'alt', 'alp', 'alh', 'am', 'ab', 'abs', 'as', 'ass', 'ang', 'aj', 'ac', 'ak', 'at', 'ap', 'ah', 'ae', 'aeg', 'aegg', 'aegs', 'aen', 'aenj', 'aenh', 'aed', 'ael', 'aelg', 'aelm', 'aelb', 'aels', 'aelt', 'aelp', 'aelh', 'aem', 'aeb', 'aebs', 'aes', 'aess', 'aeng', 'aej', 'aec', 'aek', 'aet', 'aep', 'aeh', 'ya', 'yag', 'yagg', 'yags', 'yan', 'yanj', 'yanh', 'yad', 'yal', 'yalg', 'yalm', 'yalb', 'yals', 'yalt', 'yalp', 'yalh', 'yam', 'yab', 'yabs', 'yas', 'yass', 'yang', 'yaj', 'yac', 'yak', 'yat', 'yap', 'yah', 'yae', 'yaeg', 'yaegg', 'yaegs', 'yaen', 'yaenj', 'yaenh', 'yaed', 'yael', 'yaelg', 'yaelm', 'yaelb', 'yaels', 'yaelt', 'yaelp', 'yaelh', 'yaem', 'yaeb', 'yaebs', 'yaes', 'yaess', 'yaeng', 'yaej', 'yaec', 'yaek', 'yaet', 'yaep', 'yaeh', 'eo', 'eog', 'eogg', 'eogs', 'eon', 'eonj', 'eonh', 'eod', 'eol', 'eolg', 'eolm', 'eolb', 'eols', 'eolt', 'eolp', 'eolh', 'eom', 'eob', 'eobs', 'eos', 'eoss', 'eong', 'eoj', 'eoc', 'eok', 'eot', 'eop', 'eoh', 'e', 'eg', 'egg', 'egs', 'en', 'enj', 'enh', 'ed', 'el', 'elg', 'elm', 'elb', 'els', 'elt', 'elp', 'elh', 'em', 'eb', 'ebs', 'es', 'ess', 'eng', 'ej', 'ec', 'ek', 'et', 'ep', 'eh', 'yeo', 'yeog', 'yeogg', 'yeogs', 'yeon', 'yeonj', 'yeonh', 'yeod', 'yeol', 'yeolg', 'yeolm', 'yeolb', 'yeols', 'yeolt', 'yeolp', 'yeolh', 'yeom', 'yeob', 'yeobs', 'yeos'];
<?php return ['yeoss', 'yeong', 'yeoj', 'yeoc', 'yeok', 'yeot', 'yeop', 'yeoh', 'ye', 'yeg', 'yegg', 'yegs', 'yen', 'yenj', 'yenh', 'yed', 'yel', 'yelg', 'yelm', 'yelb', 'yels', 'yelt', 'yelp', 'yelh', 'yem', 'yeb', 'yebs', 'yes', 'yess', 'yeng', 'yej', 'yec', 'yek', 'yet', 'yep', 'yeh', 'o', 'og', 'ogg', 'ogs', 'on', 'onj', 'onh', 'od', 'ol', 'olg', 'olm', 'olb', 'ols', 'olt', 'olp', 'olh', 'om', 'ob', 'obs', 'os', 'oss', 'ong', 'oj', 'oc', 'ok', 'ot', 'op', 'oh', 'wa', 'wag', 'wagg', 'wags', 'wan', 'wanj', 'wanh', 'wad', 'wal', 'walg', 'walm', 'walb', 'wals', 'walt', 'walp', 'walh', 'wam', 'wab', 'wabs', 'was', 'wass', 'wang', 'waj', 'wac', 'wak', 'wat', 'wap', 'wah', 'wae', 'waeg', 'waegg', 'waegs', 'waen', 'waenj', 'waenh', 'waed', 'wael', 'waelg', 'waelm', 'waelb', 'waels', 'waelt', 'waelp', 'waelh', 'waem', 'waeb', 'waebs', 'waes', 'waess', 'waeng', 'waej', 'waec', 'waek', 'waet', 'waep', 'waeh', 'oe', 'oeg', 'oegg', 'oegs', 'oen', 'oenj', 'oenh', 'oed', 'oel', 'oelg', 'oelm', 'oelb', 'oels', 'oelt', 'oelp', 'oelh', 'oem', 'oeb', 'oebs', 'oes', 'oess', 'oeng', 'oej', 'oec', 'oek', 'oet', 'oep', 'oeh', 'yo', 'yog', 'yogg', 'yogs', 'yon', 'yonj', 'yonh', 'yod', 'yol', 'yolg', 'yolm', 'yolb', 'yols', 'yolt', 'yolp', 'yolh', 'yom', 'yob', 'yobs', 'yos', 'yoss', 'yong', 'yoj', 'yoc', 'yok', 'yot', 'yop', 'yoh', 'u', 'ug', 'ugg', 'ugs', 'un', 'unj', 'unh', 'ud', 'ul', 'ulg', 'ulm', 'ulb', 'uls', 'ult', 'ulp', 'ulh', 'um', 'ub', 'ubs', 'us', 'uss', 'ung', 'uj', 'uc', 'uk', 'ut', 'up', 'uh', 'weo', 'weog', 'weogg', 'weogs', 'weon', 'weonj', 'weonh', 'weod', 'weol', 'weolg', 'weolm', 'weolb', 'weols', 'weolt', 'weolp', 'weolh', 'weom', 'weob', 'weobs', 'weos', 'weoss', 'weong', 'weoj', 'weoc', 'weok', 'weot', 'weop', 'weoh', 'we', 'weg', 'wegg', 'wegs', 'wen', 'wenj', 'wenh', 'wed', 'wel', 'welg', 'welm', 'welb', 'wels', 'welt', 'welp', 'welh', 'wem', 'web', 'webs', 'wes', 'wess', 'weng', 'wej', 'wec'];
<?php return ['wek', 'wet', 'wep', 'weh', 'wi', 'wig', 'wigg', 'wigs', 'win', 'winj', 'winh', 'wid', 'wil', 'wilg', 'wilm', 'wilb', 'wils', 'wilt', 'wilp', 'wilh', 'wim', 'wib', 'wibs', 'wis', 'wiss', 'wing', 'wij', 'wic', 'wik', 'wit', 'wip', 'wih', 'yu', 'yug', 'yugg', 'yugs', 'yun', 'yunj', 'yunh', 'yud', 'yul', 'yulg', 'yulm', 'yulb', 'yuls', 'yult', 'yulp', 'yulh', 'yum', 'yub', 'yubs', 'yus', 'yuss', 'yung', 'yuj', 'yuc', 'yuk', 'yut', 'yup', 'yuh', 'eu', 'eug', 'eugg', 'eugs', 'eun', 'eunj', 'eunh', 'eud', 'eul', 'eulg', 'eulm', 'eulb', 'euls', 'eult', 'eulp', 'eulh', 'eum', 'eub', 'eubs', 'eus', 'euss', 'eung', 'euj', 'euc', 'euk', 'eut', 'eup', 'euh', 'yi', 'yig', 'yigg', 'yigs', 'yin', 'yinj', 'yinh', 'yid', 'yil', 'yilg', 'yilm', 'yilb', 'yils', 'yilt', 'yilp', 'yilh', 'yim', 'yib', 'yibs', 'yis', 'yiss', 'ying', 'yij', 'yic', 'yik', 'yit', 'yip', 'yih', 'i', 'ig', 'igg', 'igs', 'in', 'inj', 'inh', 'id', 'il', 'ilg', 'ilm', 'ilb', 'ils', 'ilt', 'ilp', 'ilh', 'im', 'ib', 'ibs', 'is', 'iss', 'ing', 'ij', 'ic', 'ik', 'it', 'ip', 'ih', 'ja', 'jag', 'jagg', 'jags', 'jan', 'janj', 'janh', 'jad', 'jal', 'jalg', 'jalm', 'jalb', 'jals', 'jalt', 'jalp', 'jalh', 'jam', 'jab', 'jabs', 'jas', 'jass', 'jang', 'jaj', 'jac', 'jak', 'jat', 'jap', 'jah', 'jae', 'jaeg', 'jaegg', 'jaegs', 'jaen', 'jaenj', 'jaenh', 'jaed', 'jael', 'jaelg', 'jaelm', 'jaelb', 'jaels', 'jaelt', 'jaelp', 'jaelh', 'jaem', 'jaeb', 'jaebs', 'jaes', 'jaess', 'jaeng', 'jaej', 'jaec', 'jaek', 'jaet', 'jaep', 'jaeh', 'jya', 'jyag', 'jyagg', 'jyags', 'jyan', 'jyanj', 'jyanh', 'jyad', 'jyal', 'jyalg', 'jyalm', 'jyalb', 'jyals', 'jyalt', 'jyalp', 'jyalh', 'jyam', 'jyab', 'jyabs', 'jyas', 'jyass', 'jyang', 'jyaj', 'jyac', 'jyak', 'jyat', 'jyap', 'jyah', 'jyae', 'jyaeg', 'jyaegg', 'jyaegs', 'jyaen', 'jyaenj', 'jyaenh', 'jyaed', 'jyael', 'jyaelg', 'jyaelm', 'jyaelb', 'jyaels', 'jyaelt', 'jyaelp', 'jyaelh', 'jyaem', 'jyaeb', 'jyaebs', 'jyaes', 'jyaess', 'jyaeng', 'jyaej', 'jyaec', 'jyaek', 'jyaet', 'jyaep', 'jyaeh'];
<?php return ['jeo', 'jeog', 'jeogg', 'jeogs', 'jeon', 'jeonj', 'jeonh', 'jeod', 'jeol', 'jeolg', 'jeolm', 'jeolb', 'jeols', 'jeolt', 'jeolp', 'jeolh', 'jeom', 'jeob', 'jeobs', 'jeos', 'jeoss', 'jeong', 'jeoj', 'jeoc', 'jeok', 'jeot', 'jeop', 'jeoh', 'je', 'jeg', 'jegg', 'jegs', 'jen', 'jenj', 'jenh', 'jed', 'jel', 'jelg', 'jelm', 'jelb', 'jels', 'jelt', 'jelp', 'jelh', 'jem', 'jeb', 'jebs', 'jes', 'jess', 'jeng', 'jej', 'jec', 'jek', 'jet', 'jep', 'jeh', 'jyeo', 'jyeog', 'jyeogg', 'jyeogs', 'jyeon', 'jyeonj', 'jyeonh', 'jyeod', 'jyeol', 'jyeolg', 'jyeolm', 'jyeolb', 'jyeols', 'jyeolt', 'jyeolp', 'jyeolh', 'jyeom', 'jyeob', 'jyeobs', 'jyeos', 'jyeoss', 'jyeong', 'jyeoj', 'jyeoc', 'jyeok', 'jyeot', 'jyeop', 'jyeoh', 'jye', 'jyeg', 'jyegg', 'jyegs', 'jyen', 'jyenj', 'jyenh', 'jyed', 'jyel', 'jyelg', 'jyelm', 'jyelb', 'jyels', 'jyelt', 'jyelp', 'jyelh', 'jyem', 'jyeb', 'jyebs', 'jyes', 'jyess', 'jyeng', 'jyej', 'jyec', 'jyek', 'jyet', 'jyep', 'jyeh', 'jo', 'jog', 'jogg', 'jogs', 'jon', 'jonj', 'jonh', 'jod', 'jol', 'jolg', 'jolm', 'jolb', 'jols', 'jolt', 'jolp', 'jolh', 'jom', 'job', 'jobs', 'jos', 'joss', 'jong', 'joj', 'joc', 'jok', 'jot', 'jop', 'joh', 'jwa', 'jwag', 'jwagg', 'jwags', 'jwan', 'jwanj', 'jwanh', 'jwad', 'jwal', 'jwalg', 'jwalm', 'jwalb', 'jwals', 'jwalt', 'jwalp', 'jwalh', 'jwam', 'jwab', 'jwabs', 'jwas', 'jwass', 'jwang', 'jwaj', 'jwac', 'jwak', 'jwat', 'jwap', 'jwah', 'jwae', 'jwaeg', 'jwaegg', 'jwaegs', 'jwaen', 'jwaenj', 'jwaenh', 'jwaed', 'jwael', 'jwaelg', 'jwaelm', 'jwaelb', 'jwaels', 'jwaelt', 'jwaelp', 'jwaelh', 'jwaem', 'jwaeb', 'jwaebs', 'jwaes', 'jwaess', 'jwaeng', 'jwaej', 'jwaec', 'jwaek', 'jwaet', 'jwaep', 'jwaeh', 'joe', 'joeg', 'joegg', 'joegs', 'joen', 'joenj', 'joenh', 'joed', 'joel', 'joelg', 'joelm', 'joelb', 'joels', 'joelt', 'joelp', 'joelh', 'joem', 'joeb', 'joebs', 'joes', 'joess', 'joeng', 'joej', 'joec', 'joek', 'joet', 'joep', 'joeh', 'jyo', 'jyog', 'jyogg', 'jyogs', 'jyon', 'jyonj', 'jyonh', 'jyod', 'jyol', 'jyolg', 'jyolm', 'jyolb', 'jyols', 'jyolt', 'jyolp', 'jyolh', 'jyom', 'jyob', 'jyobs', 'jyos', 'jyoss', 'jyong', 'jyoj', 'jyoc', 'jyok', 'jyot', 'jyop', 'jyoh', 'ju', 'jug', 'jugg', 'jugs'];
<?php return ['jun', 'junj', 'junh', 'jud', 'jul', 'julg', 'julm', 'julb', 'juls', 'jult', 'julp', 'julh', 'jum', 'jub', 'jubs', 'jus', 'juss', 'jung', 'juj', 'juc', 'juk', 'jut', 'jup', 'juh', 'jweo', 'jweog', 'jweogg', 'jweogs', 'jweon', 'jweonj', 'jweonh', 'jweod', 'jweol', 'jweolg', 'jweolm', 'jweolb', 'jweols', 'jweolt', 'jweolp', 'jweolh', 'jweom', 'jweob', 'jweobs', 'jweos', 'jweoss', 'jweong', 'jweoj', 'jweoc', 'jweok', 'jweot', 'jweop', 'jweoh', 'jwe', 'jweg', 'jwegg', 'jwegs', 'jwen', 'jwenj', 'jwenh', 'jwed', 'jwel', 'jwelg', 'jwelm', 'jwelb', 'jwels', 'jwelt', 'jwelp', 'jwelh', 'jwem', 'jweb', 'jwebs', 'jwes', 'jwess', 'jweng', 'jwej', 'jwec', 'jwek', 'jwet', 'jwep', 'jweh', 'jwi', 'jwig', 'jwigg', 'jwigs', 'jwin', 'jwinj', 'jwinh', 'jwid', 'jwil', 'jwilg', 'jwilm', 'jwilb', 'jwils', 'jwilt', 'jwilp', 'jwilh', 'jwim', 'jwib', 'jwibs', 'jwis', 'jwiss', 'jwing', 'jwij', 'jwic', 'jwik', 'jwit', 'jwip', 'jwih', 'jyu', 'jyug', 'jyugg', 'jyugs', 'jyun', 'jyunj', 'jyunh', 'jyud', 'jyul', 'jyulg', 'jyulm', 'jyulb', 'jyuls', 'jyult', 'jyulp', 'jyulh', 'jyum', 'jyub', 'jyubs', 'jyus', 'jyuss', 'jyung', 'jyuj', 'jyuc', 'jyuk', 'jyut', 'jyup', 'jyuh', 'jeu', 'jeug', 'jeugg', 'jeugs', 'jeun', 'jeunj', 'jeunh', 'jeud', 'jeul', 'jeulg', 'jeulm', 'jeulb', 'jeuls', 'jeult', 'jeulp', 'jeulh', 'jeum', 'jeub', 'jeubs', 'jeus', 'jeuss', 'jeung', 'jeuj', 'jeuc', 'jeuk', 'jeut', 'jeup', 'jeuh', 'jyi', 'jyig', 'jyigg', 'jyigs', 'jyin', 'jyinj', 'jyinh', 'jyid', 'jyil', 'jyilg', 'jyilm', 'jyilb', 'jyils', 'jyilt', 'jyilp', 'jyilh', 'jyim', 'jyib', 'jyibs', 'jyis', 'jyiss', 'jying', 'jyij', 'jyic', 'jyik', 'jyit', 'jyip', 'jyih', 'ji', 'jig', 'jigg', 'jigs', 'jin', 'jinj', 'jinh', 'jid', 'jil', 'jilg', 'jilm', 'jilb', 'jils', 'jilt', 'jilp', 'jilh', 'jim', 'jib', 'jibs', 'jis', 'jiss', 'jing', 'jij', 'jic', 'jik', 'jit', 'jip', 'jih', 'jja', 'jjag', 'jjagg', 'jjags', 'jjan', 'jjanj', 'jjanh', 'jjad', 'jjal', 'jjalg', 'jjalm', 'jjalb', 'jjals', 'jjalt', 'jjalp', 'jjalh', 'jjam', 'jjab', 'jjabs', 'jjas', 'jjass', 'jjang', 'jjaj', 'jjac', 'jjak', 'jjat', 'jjap', 'jjah', 'jjae', 'jjaeg', 'jjaegg', 'jjaegs', 'jjaen', 'jjaenj', 'jjaenh', 'jjaed'];
<?php return ['jjael', 'jjaelg', 'jjaelm', 'jjaelb', 'jjaels', 'jjaelt', 'jjaelp', 'jjaelh', 'jjaem', 'jjaeb', 'jjaebs', 'jjaes', 'jjaess', 'jjaeng', 'jjaej', 'jjaec', 'jjaek', 'jjaet', 'jjaep', 'jjaeh', 'jjya', 'jjyag', 'jjyagg', 'jjyags', 'jjyan', 'jjyanj', 'jjyanh', 'jjyad', 'jjyal', 'jjyalg', 'jjyalm', 'jjyalb', 'jjyals', 'jjyalt', 'jjyalp', 'jjyalh', 'jjyam', 'jjyab', 'jjyabs', 'jjyas', 'jjyass', 'jjyang', 'jjyaj', 'jjyac', 'jjyak', 'jjyat', 'jjyap', 'jjyah', 'jjyae', 'jjyaeg', 'jjyaegg', 'jjyaegs', 'jjyaen', 'jjyaenj', 'jjyaenh', 'jjyaed', 'jjyael', 'jjyaelg', 'jjyaelm', 'jjyaelb', 'jjyaels', 'jjyaelt', 'jjyaelp', 'jjyaelh', 'jjyaem', 'jjyaeb', 'jjyaebs', 'jjyaes', 'jjyaess', 'jjyaeng', 'jjyaej', 'jjyaec', 'jjyaek', 'jjyaet', 'jjyaep', 'jjyaeh', 'jjeo', 'jjeog', 'jjeogg', 'jjeogs', 'jjeon', 'jjeonj', 'jjeonh', 'jjeod', 'jjeol', 'jjeolg', 'jjeolm', 'jjeolb', 'jjeols', 'jjeolt', 'jjeolp', 'jjeolh', 'jjeom', 'jjeob', 'jjeobs', 'jjeos', 'jjeoss', 'jjeong', 'jjeoj', 'jjeoc', 'jjeok', 'jjeot', 'jjeop', 'jjeoh', 'jje', 'jjeg', 'jjegg', 'jjegs', 'jjen', 'jjenj', 'jjenh', 'jjed', 'jjel', 'jjelg', 'jjelm', 'jjelb', 'jjels', 'jjelt', 'jjelp', 'jjelh', 'jjem', 'jjeb', 'jjebs', 'jjes', 'jjess', 'jjeng', 'jjej', 'jjec', 'jjek', 'jjet', 'jjep', 'jjeh', 'jjyeo', 'jjyeog', 'jjyeogg', 'jjyeogs', 'jjyeon', 'jjyeonj', 'jjyeonh', 'jjyeod', 'jjyeol', 'jjyeolg', 'jjyeolm', 'jjyeolb', 'jjyeols', 'jjyeolt', 'jjyeolp', 'jjyeolh', 'jjyeom', 'jjyeob', 'jjyeobs', 'jjyeos', 'jjyeoss', 'jjyeong', 'jjyeoj', 'jjyeoc', 'jjyeok', 'jjyeot', 'jjyeop', 'jjyeoh', 'jjye', 'jjyeg', 'jjyegg', 'jjyegs', 'jjyen', 'jjyenj', 'jjyenh', 'jjyed', 'jjyel', 'jjyelg', 'jjyelm', 'jjyelb', 'jjyels', 'jjyelt', 'jjyelp', 'jjyelh', 'jjyem', 'jjyeb', 'jjyebs', 'jjyes', 'jjyess', 'jjyeng', 'jjyej', 'jjyec', 'jjyek', 'jjyet', 'jjyep', 'jjyeh', 'jjo', 'jjog', 'jjogg', 'jjogs', 'jjon', 'jjonj', 'jjonh', 'jjod', 'jjol', 'jjolg', 'jjolm', 'jjolb', 'jjols', 'jjolt', 'jjolp', 'jjolh', 'jjom', 'jjob', 'jjobs', 'jjos', 'jjoss', 'jjong', 'jjoj', 'jjoc', 'jjok', 'jjot', 'jjop', 'jjoh', 'jjwa', 'jjwag', 'jjwagg', 'jjwags', 'jjwan', 'jjwanj', 'jjwanh', 'jjwad', 'jjwal', 'jjwalg', 'jjwalm', 'jjwalb', 'jjwals', 'jjwalt', 'jjwalp', 'jjwalh', 'jjwam', 'jjwab', 'jjwabs', 'jjwas', 'jjwass', 'jjwang', 'jjwaj', 'jjwac', 'jjwak', 'jjwat', 'jjwap', 'jjwah', 'jjwae', 'jjwaeg', 'jjwaegg', 'jjwaegs', 'jjwaen', 'jjwaenj', 'jjwaenh', 'jjwaed', 'jjwael', 'jjwaelg', 'jjwaelm', 'jjwaelb'];
<?php return ['jjwaels', 'jjwaelt', 'jjwaelp', 'jjwaelh', 'jjwaem', 'jjwaeb', 'jjwaebs', 'jjwaes', 'jjwaess', 'jjwaeng', 'jjwaej', 'jjwaec', 'jjwaek', 'jjwaet', 'jjwaep', 'jjwaeh', 'jjoe', 'jjoeg', 'jjoegg', 'jjoegs', 'jjoen', 'jjoenj', 'jjoenh', 'jjoed', 'jjoel', 'jjoelg', 'jjoelm', 'jjoelb', 'jjoels', 'jjoelt', 'jjoelp', 'jjoelh', 'jjoem', 'jjoeb', 'jjoebs', 'jjoes', 'jjoess', 'jjoeng', 'jjoej', 'jjoec', 'jjoek', 'jjoet', 'jjoep', 'jjoeh', 'jjyo', 'jjyog', 'jjyogg', 'jjyogs', 'jjyon', 'jjyonj', 'jjyonh', 'jjyod', 'jjyol', 'jjyolg', 'jjyolm', 'jjyolb', 'jjyols', 'jjyolt', 'jjyolp', 'jjyolh', 'jjyom', 'jjyob', 'jjyobs', 'jjyos', 'jjyoss', 'jjyong', 'jjyoj', 'jjyoc', 'jjyok', 'jjyot', 'jjyop', 'jjyoh', 'jju', 'jjug', 'jjugg', 'jjugs', 'jjun', 'jjunj', 'jjunh', 'jjud', 'jjul', 'jjulg', 'jjulm', 'jjulb', 'jjuls', 'jjult', 'jjulp', 'jjulh', 'jjum', 'jjub', 'jjubs', 'jjus', 'jjuss', 'jjung', 'jjuj', 'jjuc', 'jjuk', 'jjut', 'jjup', 'jjuh', 'jjweo', 'jjweog', 'jjweogg', 'jjweogs', 'jjweon', 'jjweonj', 'jjweonh', 'jjweod', 'jjweol', 'jjweolg', 'jjweolm', 'jjweolb', 'jjweols', 'jjweolt', 'jjweolp', 'jjweolh', 'jjweom', 'jjweob', 'jjweobs', 'jjweos', 'jjweoss', 'jjweong', 'jjweoj', 'jjweoc', 'jjweok', 'jjweot', 'jjweop', 'jjweoh', 'jjwe', 'jjweg', 'jjwegg', 'jjwegs', 'jjwen', 'jjwenj', 'jjwenh', 'jjwed', 'jjwel', 'jjwelg', 'jjwelm', 'jjwelb', 'jjwels', 'jjwelt', 'jjwelp', 'jjwelh', 'jjwem', 'jjweb', 'jjwebs', 'jjwes', 'jjwess', 'jjweng', 'jjwej', 'jjwec', 'jjwek', 'jjwet', 'jjwep', 'jjweh', 'jjwi', 'jjwig', 'jjwigg', 'jjwigs', 'jjwin', 'jjwinj', 'jjwinh', 'jjwid', 'jjwil', 'jjwilg', 'jjwilm', 'jjwilb', 'jjwils', 'jjwilt', 'jjwilp', 'jjwilh', 'jjwim', 'jjwib', 'jjwibs', 'jjwis', 'jjwiss', 'jjwing', 'jjwij', 'jjwic', 'jjwik', 'jjwit', 'jjwip', 'jjwih', 'jjyu', 'jjyug', 'jjyugg', 'jjyugs', 'jjyun', 'jjyunj', 'jjyunh', 'jjyud', 'jjyul', 'jjyulg', 'jjyulm', 'jjyulb', 'jjyuls', 'jjyult', 'jjyulp', 'jjyulh', 'jjyum', 'jjyub', 'jjyubs', 'jjyus', 'jjyuss', 'jjyung', 'jjyuj', 'jjyuc', 'jjyuk', 'jjyut', 'jjyup', 'jjyuh', 'jjeu', 'jjeug', 'jjeugg', 'jjeugs', 'jjeun', 'jjeunj', 'jjeunh', 'jjeud', 'jjeul', 'jjeulg', 'jjeulm', 'jjeulb', 'jjeuls', 'jjeult', 'jjeulp', 'jjeulh', 'jjeum', 'jjeub', 'jjeubs', 'jjeus', 'jjeuss', 'jjeung', 'jjeuj', 'jjeuc', 'jjeuk', 'jjeut', 'jjeup', 'jjeuh', 'jjyi', 'jjyig', 'jjyigg', 'jjyigs', 'jjyin', 'jjyinj', 'jjyinh', 'jjyid', 'jjyil', 'jjyilg', 'jjyilm', 'jjyilb', 'jjyils', 'jjyilt', 'jjyilp', 'jjyilh'];
<?php return ['jjyim', 'jjyib', 'jjyibs', 'jjyis', 'jjyiss', 'jjying', 'jjyij', 'jjyic', 'jjyik', 'jjyit', 'jjyip', 'jjyih', 'jji', 'jjig', 'jjigg', 'jjigs', 'jjin', 'jjinj', 'jjinh', 'jjid', 'jjil', 'jjilg', 'jjilm', 'jjilb', 'jjils', 'jjilt', 'jjilp', 'jjilh', 'jjim', 'jjib', 'jjibs', 'jjis', 'jjiss', 'jjing', 'jjij', 'jjic', 'jjik', 'jjit', 'jjip', 'jjih', 'ca', 'cag', 'cagg', 'cags', 'can', 'canj', 'canh', 'cad', 'cal', 'calg', 'calm', 'calb', 'cals', 'calt', 'calp', 'calh', 'cam', 'cab', 'cabs', 'cas', 'cass', 'cang', 'caj', 'cac', 'cak', 'cat', 'cap', 'cah', 'cae', 'caeg', 'caegg', 'caegs', 'caen', 'caenj', 'caenh', 'caed', 'cael', 'caelg', 'caelm', 'caelb', 'caels', 'caelt', 'caelp', 'caelh', 'caem', 'caeb', 'caebs', 'caes', 'caess', 'caeng', 'caej', 'caec', 'caek', 'caet', 'caep', 'caeh', 'cya', 'cyag', 'cyagg', 'cyags', 'cyan', 'cyanj', 'cyanh', 'cyad', 'cyal', 'cyalg', 'cyalm', 'cyalb', 'cyals', 'cyalt', 'cyalp', 'cyalh', 'cyam', 'cyab', 'cyabs', 'cyas', 'cyass', 'cyang', 'cyaj', 'cyac', 'cyak', 'cyat', 'cyap', 'cyah', 'cyae', 'cyaeg', 'cyaegg', 'cyaegs', 'cyaen', 'cyaenj', 'cyaenh', 'cyaed', 'cyael', 'cyaelg', 'cyaelm', 'cyaelb', 'cyaels', 'cyaelt', 'cyaelp', 'cyaelh', 'cyaem', 'cyaeb', 'cyaebs', 'cyaes', 'cyaess', 'cyaeng', 'cyaej', 'cyaec', 'cyaek', 'cyaet', 'cyaep', 'cyaeh', 'ceo', 'ceog', 'ceogg', 'ceogs', 'ceon', 'ceonj', 'ceonh', 'ceod', 'ceol', 'ceolg', 'ceolm', 'ceolb', 'ceols', 'ceolt', 'ceolp', 'ceolh', 'ceom', 'ceob', 'ceobs', 'ceos', 'ceoss', 'ceong', 'ceoj', 'ceoc', 'ceok', 'ceot', 'ceop', 'ceoh', 'ce', 'ceg', 'cegg', 'cegs', 'cen', 'cenj', 'cenh', 'ced', 'cel', 'celg', 'celm', 'celb', 'cels', 'celt', 'celp', 'celh', 'cem', 'ceb', 'cebs', 'ces', 'cess', 'ceng', 'cej', 'cec', 'cek', 'cet', 'cep', 'ceh', 'cyeo', 'cyeog', 'cyeogg', 'cyeogs', 'cyeon', 'cyeonj', 'cyeonh', 'cyeod', 'cyeol', 'cyeolg', 'cyeolm', 'cyeolb', 'cyeols', 'cyeolt', 'cyeolp', 'cyeolh', 'cyeom', 'cyeob', 'cyeobs', 'cyeos', 'cyeoss', 'cyeong', 'cyeoj', 'cyeoc', 'cyeok', 'cyeot', 'cyeop', 'cyeoh', 'cye', 'cyeg', 'cyegg', 'cyegs', 'cyen', 'cyenj', 'cyenh', 'cyed', 'cyel', 'cyelg', 'cyelm', 'cyelb', 'cyels', 'cyelt', 'cyelp', 'cyelh', 'cyem', 'cyeb', 'cyebs', 'cyes'];
<?php return ['cyess', 'cyeng', 'cyej', 'cyec', 'cyek', 'cyet', 'cyep', 'cyeh', 'co', 'cog', 'cogg', 'cogs', 'con', 'conj', 'conh', 'cod', 'col', 'colg', 'colm', 'colb', 'cols', 'colt', 'colp', 'colh', 'com', 'cob', 'cobs', 'cos', 'coss', 'cong', 'coj', 'coc', 'cok', 'cot', 'cop', 'coh', 'cwa', 'cwag', 'cwagg', 'cwags', 'cwan', 'cwanj', 'cwanh', 'cwad', 'cwal', 'cwalg', 'cwalm', 'cwalb', 'cwals', 'cwalt', 'cwalp', 'cwalh', 'cwam', 'cwab', 'cwabs', 'cwas', 'cwass', 'cwang', 'cwaj', 'cwac', 'cwak', 'cwat', 'cwap', 'cwah', 'cwae', 'cwaeg', 'cwaegg', 'cwaegs', 'cwaen', 'cwaenj', 'cwaenh', 'cwaed', 'cwael', 'cwaelg', 'cwaelm', 'cwaelb', 'cwaels', 'cwaelt', 'cwaelp', 'cwaelh', 'cwaem', 'cwaeb', 'cwaebs', 'cwaes', 'cwaess', 'cwaeng', 'cwaej', 'cwaec', 'cwaek', 'cwaet', 'cwaep', 'cwaeh', 'coe', 'coeg', 'coegg', 'coegs', 'coen', 'coenj', 'coenh', 'coed', 'coel', 'coelg', 'coelm', 'coelb', 'coels', 'coelt', 'coelp', 'coelh', 'coem', 'coeb', 'coebs', 'coes', 'coess', 'coeng', 'coej', 'coec', 'coek', 'coet', 'coep', 'coeh', 'cyo', 'cyog', 'cyogg', 'cyogs', 'cyon', 'cyonj', 'cyonh', 'cyod', 'cyol', 'cyolg', 'cyolm', 'cyolb', 'cyols', 'cyolt', 'cyolp', 'cyolh', 'cyom', 'cyob', 'cyobs', 'cyos', 'cyoss', 'cyong', 'cyoj', 'cyoc', 'cyok', 'cyot', 'cyop', 'cyoh', 'cu', 'cug', 'cugg', 'cugs', 'cun', 'cunj', 'cunh', 'cud', 'cul', 'culg', 'culm', 'culb', 'culs', 'cult', 'culp', 'culh', 'cum', 'cub', 'cubs', 'cus', 'cuss', 'cung', 'cuj', 'cuc', 'cuk', 'cut', 'cup', 'cuh', 'cweo', 'cweog', 'cweogg', 'cweogs', 'cweon', 'cweonj', 'cweonh', 'cweod', 'cweol', 'cweolg', 'cweolm', 'cweolb', 'cweols', 'cweolt', 'cweolp', 'cweolh', 'cweom', 'cweob', 'cweobs', 'cweos', 'cweoss', 'cweong', 'cweoj', 'cweoc', 'cweok', 'cweot', 'cweop', 'cweoh', 'cwe', 'cweg', 'cwegg', 'cwegs', 'cwen', 'cwenj', 'cwenh', 'cwed', 'cwel', 'cwelg', 'cwelm', 'cwelb', 'cwels', 'cwelt', 'cwelp', 'cwelh', 'cwem', 'cweb', 'cwebs', 'cwes', 'cwess', 'cweng', 'cwej', 'cwec', 'cwek', 'cwet', 'cwep', 'cweh', 'cwi', 'cwig', 'cwigg', 'cwigs', 'cwin', 'cwinj', 'cwinh', 'cwid', 'cwil', 'cwilg', 'cwilm', 'cwilb', 'cwils', 'cwilt', 'cwilp', 'cwilh', 'cwim', 'cwib', 'cwibs', 'cwis', 'cwiss', 'cwing', 'cwij', 'cwic'];
<?php return ['cwik', 'cwit', 'cwip', 'cwih', 'cyu', 'cyug', 'cyugg', 'cyugs', 'cyun', 'cyunj', 'cyunh', 'cyud', 'cyul', 'cyulg', 'cyulm', 'cyulb', 'cyuls', 'cyult', 'cyulp', 'cyulh', 'cyum', 'cyub', 'cyubs', 'cyus', 'cyuss', 'cyung', 'cyuj', 'cyuc', 'cyuk', 'cyut', 'cyup', 'cyuh', 'ceu', 'ceug', 'ceugg', 'ceugs', 'ceun', 'ceunj', 'ceunh', 'ceud', 'ceul', 'ceulg', 'ceulm', 'ceulb', 'ceuls', 'ceult', 'ceulp', 'ceulh', 'ceum', 'ceub', 'ceubs', 'ceus', 'ceuss', 'ceung', 'ceuj', 'ceuc', 'ceuk', 'ceut', 'ceup', 'ceuh', 'cyi', 'cyig', 'cyigg', 'cyigs', 'cyin', 'cyinj', 'cyinh', 'cyid', 'cyil', 'cyilg', 'cyilm', 'cyilb', 'cyils', 'cyilt', 'cyilp', 'cyilh', 'cyim', 'cyib', 'cyibs', 'cyis', 'cyiss', 'cying', 'cyij', 'cyic', 'cyik', 'cyit', 'cyip', 'cyih', 'ci', 'cig', 'cigg', 'cigs', 'cin', 'cinj', 'cinh', 'cid', 'cil', 'cilg', 'cilm', 'cilb', 'cils', 'cilt', 'cilp', 'cilh', 'cim', 'cib', 'cibs', 'cis', 'ciss', 'cing', 'cij', 'cic', 'cik', 'cit', 'cip', 'cih', 'ka', 'kag', 'kagg', 'kags', 'kan', 'kanj', 'kanh', 'kad', 'kal', 'kalg', 'kalm', 'kalb', 'kals', 'kalt', 'kalp', 'kalh', 'kam', 'kab', 'kabs', 'kas', 'kass', 'kang', 'kaj', 'kac', 'kak', 'kat', 'kap', 'kah', 'kae', 'kaeg', 'kaegg', 'kaegs', 'kaen', 'kaenj', 'kaenh', 'kaed', 'kael', 'kaelg', 'kaelm', 'kaelb', 'kaels', 'kaelt', 'kaelp', 'kaelh', 'kaem', 'kaeb', 'kaebs', 'kaes', 'kaess', 'kaeng', 'kaej', 'kaec', 'kaek', 'kaet', 'kaep', 'kaeh', 'kya', 'kyag', 'kyagg', 'kyags', 'kyan', 'kyanj', 'kyanh', 'kyad', 'kyal', 'kyalg', 'kyalm', 'kyalb', 'kyals', 'kyalt', 'kyalp', 'kyalh', 'kyam', 'kyab', 'kyabs', 'kyas', 'kyass', 'kyang', 'kyaj', 'kyac', 'kyak', 'kyat', 'kyap', 'kyah', 'kyae', 'kyaeg', 'kyaegg', 'kyaegs', 'kyaen', 'kyaenj', 'kyaenh', 'kyaed', 'kyael', 'kyaelg', 'kyaelm', 'kyaelb', 'kyaels', 'kyaelt', 'kyaelp', 'kyaelh', 'kyaem', 'kyaeb', 'kyaebs', 'kyaes', 'kyaess', 'kyaeng', 'kyaej', 'kyaec', 'kyaek', 'kyaet', 'kyaep', 'kyaeh', 'keo', 'keog', 'keogg', 'keogs', 'keon', 'keonj', 'keonh', 'keod', 'keol', 'keolg', 'keolm', 'keolb', 'keols', 'keolt', 'keolp', 'keolh', 'keom', 'keob', 'keobs', 'keos', 'keoss', 'keong', 'keoj', 'keoc', 'keok', 'keot', 'keop', 'keoh'];
<?php return ['ke', 'keg', 'kegg', 'kegs', 'ken', 'kenj', 'kenh', 'ked', 'kel', 'kelg', 'kelm', 'kelb', 'kels', 'kelt', 'kelp', 'kelh', 'kem', 'keb', 'kebs', 'kes', 'kess', 'keng', 'kej', 'kec', 'kek', 'ket', 'kep', 'keh', 'kyeo', 'kyeog', 'kyeogg', 'kyeogs', 'kyeon', 'kyeonj', 'kyeonh', 'kyeod', 'kyeol', 'kyeolg', 'kyeolm', 'kyeolb', 'kyeols', 'kyeolt', 'kyeolp', 'kyeolh', 'kyeom', 'kyeob', 'kyeobs', 'kyeos', 'kyeoss', 'kyeong', 'kyeoj', 'kyeoc', 'kyeok', 'kyeot', 'kyeop', 'kyeoh', 'kye', 'kyeg', 'kyegg', 'kyegs', 'kyen', 'kyenj', 'kyenh', 'kyed', 'kyel', 'kyelg', 'kyelm', 'kyelb', 'kyels', 'kyelt', 'kyelp', 'kyelh', 'kyem', 'kyeb', 'kyebs', 'kyes', 'kyess', 'kyeng', 'kyej', 'kyec', 'kyek', 'kyet', 'kyep', 'kyeh', 'ko', 'kog', 'kogg', 'kogs', 'kon', 'konj', 'konh', 'kod', 'kol', 'kolg', 'kolm', 'kolb', 'kols', 'kolt', 'kolp', 'kolh', 'kom', 'kob', 'kobs', 'kos', 'koss', 'kong', 'koj', 'koc', 'kok', 'kot', 'kop', 'koh', 'kwa', 'kwag', 'kwagg', 'kwags', 'kwan', 'kwanj', 'kwanh', 'kwad', 'kwal', 'kwalg', 'kwalm', 'kwalb', 'kwals', 'kwalt', 'kwalp', 'kwalh', 'kwam', 'kwab', 'kwabs', 'kwas', 'kwass', 'kwang', 'kwaj', 'kwac', 'kwak', 'kwat', 'kwap', 'kwah', 'kwae', 'kwaeg', 'kwaegg', 'kwaegs', 'kwaen', 'kwaenj', 'kwaenh', 'kwaed', 'kwael', 'kwaelg', 'kwaelm', 'kwaelb', 'kwaels', 'kwaelt', 'kwaelp', 'kwaelh', 'kwaem', 'kwaeb', 'kwaebs', 'kwaes', 'kwaess', 'kwaeng', 'kwaej', 'kwaec', 'kwaek', 'kwaet', 'kwaep', 'kwaeh', 'koe', 'koeg', 'koegg', 'koegs', 'koen', 'koenj', 'koenh', 'koed', 'koel', 'koelg', 'koelm', 'koelb', 'koels', 'koelt', 'koelp', 'koelh', 'koem', 'koeb', 'koebs', 'koes', 'koess', 'koeng', 'koej', 'koec', 'koek', 'koet', 'koep', 'koeh', 'kyo', 'kyog', 'kyogg', 'kyogs', 'kyon', 'kyonj', 'kyonh', 'kyod', 'kyol', 'kyolg', 'kyolm', 'kyolb', 'kyols', 'kyolt', 'kyolp', 'kyolh', 'kyom', 'kyob', 'kyobs', 'kyos', 'kyoss', 'kyong', 'kyoj', 'kyoc', 'kyok', 'kyot', 'kyop', 'kyoh', 'ku', 'kug', 'kugg', 'kugs', 'kun', 'kunj', 'kunh', 'kud', 'kul', 'kulg', 'kulm', 'kulb', 'kuls', 'kult', 'kulp', 'kulh', 'kum', 'kub', 'kubs', 'kus', 'kuss', 'kung', 'kuj', 'kuc', 'kuk', 'kut', 'kup', 'kuh', 'kweo', 'kweog', 'kweogg', 'kweogs'];
<?php return ['kweon', 'kweonj', 'kweonh', 'kweod', 'kweol', 'kweolg', 'kweolm', 'kweolb', 'kweols', 'kweolt', 'kweolp', 'kweolh', 'kweom', 'kweob', 'kweobs', 'kweos', 'kweoss', 'kweong', 'kweoj', 'kweoc', 'kweok', 'kweot', 'kweop', 'kweoh', 'kwe', 'kweg', 'kwegg', 'kwegs', 'kwen', 'kwenj', 'kwenh', 'kwed', 'kwel', 'kwelg', 'kwelm', 'kwelb', 'kwels', 'kwelt', 'kwelp', 'kwelh', 'kwem', 'kweb', 'kwebs', 'kwes', 'kwess', 'kweng', 'kwej', 'kwec', 'kwek', 'kwet', 'kwep', 'kweh', 'kwi', 'kwig', 'kwigg', 'kwigs', 'kwin', 'kwinj', 'kwinh', 'kwid', 'kwil', 'kwilg', 'kwilm', 'kwilb', 'kwils', 'kwilt', 'kwilp', 'kwilh', 'kwim', 'kwib', 'kwibs', 'kwis', 'kwiss', 'kwing', 'kwij', 'kwic', 'kwik', 'kwit', 'kwip', 'kwih', 'kyu', 'kyug', 'kyugg', 'kyugs', 'kyun', 'kyunj', 'kyunh', 'kyud', 'kyul', 'kyulg', 'kyulm', 'kyulb', 'kyuls', 'kyult', 'kyulp', 'kyulh', 'kyum', 'kyub', 'kyubs', 'kyus', 'kyuss', 'kyung', 'kyuj', 'kyuc', 'kyuk', 'kyut', 'kyup', 'kyuh', 'keu', 'keug', 'keugg', 'keugs', 'keun', 'keunj', 'keunh', 'keud', 'keul', 'keulg', 'keulm', 'keulb', 'keuls', 'keult', 'keulp', 'keulh', 'keum', 'keub', 'keubs', 'keus', 'keuss', 'keung', 'keuj', 'keuc', 'keuk', 'keut', 'keup', 'keuh', 'kyi', 'kyig', 'kyigg', 'kyigs', 'kyin', 'kyinj', 'kyinh', 'kyid', 'kyil', 'kyilg', 'kyilm', 'kyilb', 'kyils', 'kyilt', 'kyilp', 'kyilh', 'kyim', 'kyib', 'kyibs', 'kyis', 'kyiss', 'kying', 'kyij', 'kyic', 'kyik', 'kyit', 'kyip', 'kyih', 'ki', 'kig', 'kigg', 'kigs', 'kin', 'kinj', 'kinh', 'kid', 'kil', 'kilg', 'kilm', 'kilb', 'kils', 'kilt', 'kilp', 'kilh', 'kim', 'kib', 'kibs', 'kis', 'kiss', 'king', 'kij', 'kic', 'kik', 'kit', 'kip', 'kih', 'ta', 'tag', 'tagg', 'tags', 'tan', 'tanj', 'tanh', 'tad', 'tal', 'talg', 'talm', 'talb', 'tals', 'talt', 'talp', 'talh', 'tam', 'tab', 'tabs', 'tas', 'tass', 'tang', 'taj', 'tac', 'tak', 'tat', 'tap', 'tah', 'tae', 'taeg', 'taegg', 'taegs', 'taen', 'taenj', 'taenh', 'taed', 'tael', 'taelg', 'taelm', 'taelb', 'taels', 'taelt', 'taelp', 'taelh', 'taem', 'taeb', 'taebs', 'taes', 'taess', 'taeng', 'taej', 'taec', 'taek', 'taet', 'taep', 'taeh', 'tya', 'tyag', 'tyagg', 'tyags', 'tyan', 'tyanj', 'tyanh', 'tyad'];
<?php return ['tyal', 'tyalg', 'tyalm', 'tyalb', 'tyals', 'tyalt', 'tyalp', 'tyalh', 'tyam', 'tyab', 'tyabs', 'tyas', 'tyass', 'tyang', 'tyaj', 'tyac', 'tyak', 'tyat', 'tyap', 'tyah', 'tyae', 'tyaeg', 'tyaegg', 'tyaegs', 'tyaen', 'tyaenj', 'tyaenh', 'tyaed', 'tyael', 'tyaelg', 'tyaelm', 'tyaelb', 'tyaels', 'tyaelt', 'tyaelp', 'tyaelh', 'tyaem', 'tyaeb', 'tyaebs', 'tyaes', 'tyaess', 'tyaeng', 'tyaej', 'tyaec', 'tyaek', 'tyaet', 'tyaep', 'tyaeh', 'teo', 'teog', 'teogg', 'teogs', 'teon', 'teonj', 'teonh', 'teod', 'teol', 'teolg', 'teolm', 'teolb', 'teols', 'teolt', 'teolp', 'teolh', 'teom', 'teob', 'teobs', 'teos', 'teoss', 'teong', 'teoj', 'teoc', 'teok', 'teot', 'teop', 'teoh', 'te', 'teg', 'tegg', 'tegs', 'ten', 'tenj', 'tenh', 'ted', 'tel', 'telg', 'telm', 'telb', 'tels', 'telt', 'telp', 'telh', 'tem', 'teb', 'tebs', 'tes', 'tess', 'teng', 'tej', 'tec', 'tek', 'tet', 'tep', 'teh', 'tyeo', 'tyeog', 'tyeogg', 'tyeogs', 'tyeon', 'tyeonj', 'tyeonh', 'tyeod', 'tyeol', 'tyeolg', 'tyeolm', 'tyeolb', 'tyeols', 'tyeolt', 'tyeolp', 'tyeolh', 'tyeom', 'tyeob', 'tyeobs', 'tyeos', 'tyeoss', 'tyeong', 'tyeoj', 'tyeoc', 'tyeok', 'tyeot', 'tyeop', 'tyeoh', 'tye', 'tyeg', 'tyegg', 'tyegs', 'tyen', 'tyenj', 'tyenh', 'tyed', 'tyel', 'tyelg', 'tyelm', 'tyelb', 'tyels', 'tyelt', 'tyelp', 'tyelh', 'tyem', 'tyeb', 'tyebs', 'tyes', 'tyess', 'tyeng', 'tyej', 'tyec', 'tyek', 'tyet', 'tyep', 'tyeh', 'to', 'tog', 'togg', 'togs', 'ton', 'tonj', 'tonh', 'tod', 'tol', 'tolg', 'tolm', 'tolb', 'tols', 'tolt', 'tolp', 'tolh', 'tom', 'tob', 'tobs', 'tos', 'toss', 'tong', 'toj', 'toc', 'tok', 'tot', 'top', 'toh', 'twa', 'twag', 'twagg', 'twags', 'twan', 'twanj', 'twanh', 'twad', 'twal', 'twalg', 'twalm', 'twalb', 'twals', 'twalt', 'twalp', 'twalh', 'twam', 'twab', 'twabs', 'twas', 'twass', 'twang', 'twaj', 'twac', 'twak', 'twat', 'twap', 'twah', 'twae', 'twaeg', 'twaegg', 'twaegs', 'twaen', 'twaenj', 'twaenh', 'twaed', 'twael', 'twaelg', 'twaelm', 'twaelb', 'twaels', 'twaelt', 'twaelp', 'twaelh', 'twaem', 'twaeb', 'twaebs', 'twaes', 'twaess', 'twaeng', 'twaej', 'twaec', 'twaek', 'twaet', 'twaep', 'twaeh', 'toe', 'toeg', 'toegg', 'toegs', 'toen', 'toenj', 'toenh', 'toed', 'toel', 'toelg', 'toelm', 'toelb'];
<?php return ['toels', 'toelt', 'toelp', 'toelh', 'toem', 'toeb', 'toebs', 'toes', 'toess', 'toeng', 'toej', 'toec', 'toek', 'toet', 'toep', 'toeh', 'tyo', 'tyog', 'tyogg', 'tyogs', 'tyon', 'tyonj', 'tyonh', 'tyod', 'tyol', 'tyolg', 'tyolm', 'tyolb', 'tyols', 'tyolt', 'tyolp', 'tyolh', 'tyom', 'tyob', 'tyobs', 'tyos', 'tyoss', 'tyong', 'tyoj', 'tyoc', 'tyok', 'tyot', 'tyop', 'tyoh', 'tu', 'tug', 'tugg', 'tugs', 'tun', 'tunj', 'tunh', 'tud', 'tul', 'tulg', 'tulm', 'tulb', 'tuls', 'tult', 'tulp', 'tulh', 'tum', 'tub', 'tubs', 'tus', 'tuss', 'tung', 'tuj', 'tuc', 'tuk', 'tut', 'tup', 'tuh', 'tweo', 'tweog', 'tweogg', 'tweogs', 'tweon', 'tweonj', 'tweonh', 'tweod', 'tweol', 'tweolg', 'tweolm', 'tweolb', 'tweols', 'tweolt', 'tweolp', 'tweolh', 'tweom', 'tweob', 'tweobs', 'tweos', 'tweoss', 'tweong', 'tweoj', 'tweoc', 'tweok', 'tweot', 'tweop', 'tweoh', 'twe', 'tweg', 'twegg', 'twegs', 'twen', 'twenj', 'twenh', 'twed', 'twel', 'twelg', 'twelm', 'twelb', 'twels', 'twelt', 'twelp', 'twelh', 'twem', 'tweb', 'twebs', 'twes', 'twess', 'tweng', 'twej', 'twec', 'twek', 'twet', 'twep', 'tweh', 'twi', 'twig', 'twigg', 'twigs', 'twin', 'twinj', 'twinh', 'twid', 'twil', 'twilg', 'twilm', 'twilb', 'twils', 'twilt', 'twilp', 'twilh', 'twim', 'twib', 'twibs', 'twis', 'twiss', 'twing', 'twij', 'twic', 'twik', 'twit', 'twip', 'twih', 'tyu', 'tyug', 'tyugg', 'tyugs', 'tyun', 'tyunj', 'tyunh', 'tyud', 'tyul', 'tyulg', 'tyulm', 'tyulb', 'tyuls', 'tyult', 'tyulp', 'tyulh', 'tyum', 'tyub', 'tyubs', 'tyus', 'tyuss', 'tyung', 'tyuj', 'tyuc', 'tyuk', 'tyut', 'tyup', 'tyuh', 'teu', 'teug', 'teugg', 'teugs', 'teun', 'teunj', 'teunh', 'teud', 'teul', 'teulg', 'teulm', 'teulb', 'teuls', 'teult', 'teulp', 'teulh', 'teum', 'teub', 'teubs', 'teus', 'teuss', 'teung', 'teuj', 'teuc', 'teuk', 'teut', 'teup', 'teuh', 'tyi', 'tyig', 'tyigg', 'tyigs', 'tyin', 'tyinj', 'tyinh', 'tyid', 'tyil', 'tyilg', 'tyilm', 'tyilb', 'tyils', 'tyilt', 'tyilp', 'tyilh', 'tyim', 'tyib', 'tyibs', 'tyis', 'tyiss', 'tying', 'tyij', 'tyic', 'tyik', 'tyit', 'tyip', 'tyih', 'ti', 'tig', 'tigg', 'tigs', 'tin', 'tinj', 'tinh', 'tid', 'til', 'tilg', 'tilm', 'tilb', 'tils', 'tilt', 'tilp', 'tilh'];
<?php return ['tim', 'tib', 'tibs', 'tis', 'tiss', 'ting', 'tij', 'tic', 'tik', 'tit', 'tip', 'tih', 'pa', 'pag', 'pagg', 'pags', 'pan', 'panj', 'panh', 'pad', 'pal', 'palg', 'palm', 'palb', 'pals', 'palt', 'palp', 'palh', 'pam', 'pab', 'pabs', 'pas', 'pass', 'pang', 'paj', 'pac', 'pak', 'pat', 'pap', 'pah', 'pae', 'paeg', 'paegg', 'paegs', 'paen', 'paenj', 'paenh', 'paed', 'pael', 'paelg', 'paelm', 'paelb', 'paels', 'paelt', 'paelp', 'paelh', 'paem', 'paeb', 'paebs', 'paes', 'paess', 'paeng', 'paej', 'paec', 'paek', 'paet', 'paep', 'paeh', 'pya', 'pyag', 'pyagg', 'pyags', 'pyan', 'pyanj', 'pyanh', 'pyad', 'pyal', 'pyalg', 'pyalm', 'pyalb', 'pyals', 'pyalt', 'pyalp', 'pyalh', 'pyam', 'pyab', 'pyabs', 'pyas', 'pyass', 'pyang', 'pyaj', 'pyac', 'pyak', 'pyat', 'pyap', 'pyah', 'pyae', 'pyaeg', 'pyaegg', 'pyaegs', 'pyaen', 'pyaenj', 'pyaenh', 'pyaed', 'pyael', 'pyaelg', 'pyaelm', 'pyaelb', 'pyaels', 'pyaelt', 'pyaelp', 'pyaelh', 'pyaem', 'pyaeb', 'pyaebs', 'pyaes', 'pyaess', 'pyaeng', 'pyaej', 'pyaec', 'pyaek', 'pyaet', 'pyaep', 'pyaeh', 'peo', 'peog', 'peogg', 'peogs', 'peon', 'peonj', 'peonh', 'peod', 'peol', 'peolg', 'peolm', 'peolb', 'peols', 'peolt', 'peolp', 'peolh', 'peom', 'peob', 'peobs', 'peos', 'peoss', 'peong', 'peoj', 'peoc', 'peok', 'peot', 'peop', 'peoh', 'pe', 'peg', 'pegg', 'pegs', 'pen', 'penj', 'penh', 'ped', 'pel', 'pelg', 'pelm', 'pelb', 'pels', 'pelt', 'pelp', 'pelh', 'pem', 'peb', 'pebs', 'pes', 'pess', 'peng', 'pej', 'pec', 'pek', 'pet', 'pep', 'peh', 'pyeo', 'pyeog', 'pyeogg', 'pyeogs', 'pyeon', 'pyeonj', 'pyeonh', 'pyeod', 'pyeol', 'pyeolg', 'pyeolm', 'pyeolb', 'pyeols', 'pyeolt', 'pyeolp', 'pyeolh', 'pyeom', 'pyeob', 'pyeobs', 'pyeos', 'pyeoss', 'pyeong', 'pyeoj', 'pyeoc', 'pyeok', 'pyeot', 'pyeop', 'pyeoh', 'pye', 'pyeg', 'pyegg', 'pyegs', 'pyen', 'pyenj', 'pyenh', 'pyed', 'pyel', 'pyelg', 'pyelm', 'pyelb', 'pyels', 'pyelt', 'pyelp', 'pyelh', 'pyem', 'pyeb', 'pyebs', 'pyes', 'pyess', 'pyeng', 'pyej', 'pyec', 'pyek', 'pyet', 'pyep', 'pyeh', 'po', 'pog', 'pogg', 'pogs', 'pon', 'ponj', 'ponh', 'pod', 'pol', 'polg', 'polm', 'polb', 'pols', 'polt', 'polp', 'polh', 'pom', 'pob', 'pobs', 'pos'];
<?php return ['poss', 'pong', 'poj', 'poc', 'pok', 'pot', 'pop', 'poh', 'pwa', 'pwag', 'pwagg', 'pwags', 'pwan', 'pwanj', 'pwanh', 'pwad', 'pwal', 'pwalg', 'pwalm', 'pwalb', 'pwals', 'pwalt', 'pwalp', 'pwalh', 'pwam', 'pwab', 'pwabs', 'pwas', 'pwass', 'pwang', 'pwaj', 'pwac', 'pwak', 'pwat', 'pwap', 'pwah', 'pwae', 'pwaeg', 'pwaegg', 'pwaegs', 'pwaen', 'pwaenj', 'pwaenh', 'pwaed', 'pwael', 'pwaelg', 'pwaelm', 'pwaelb', 'pwaels', 'pwaelt', 'pwaelp', 'pwaelh', 'pwaem', 'pwaeb', 'pwaebs', 'pwaes', 'pwaess', 'pwaeng', 'pwaej', 'pwaec', 'pwaek', 'pwaet', 'pwaep', 'pwaeh', 'poe', 'poeg', 'poegg', 'poegs', 'poen', 'poenj', 'poenh', 'poed', 'poel', 'poelg', 'poelm', 'poelb', 'poels', 'poelt', 'poelp', 'poelh', 'poem', 'poeb', 'poebs', 'poes', 'poess', 'poeng', 'poej', 'poec', 'poek', 'poet', 'poep', 'poeh', 'pyo', 'pyog', 'pyogg', 'pyogs', 'pyon', 'pyonj', 'pyonh', 'pyod', 'pyol', 'pyolg', 'pyolm', 'pyolb', 'pyols', 'pyolt', 'pyolp', 'pyolh', 'pyom', 'pyob', 'pyobs', 'pyos', 'pyoss', 'pyong', 'pyoj', 'pyoc', 'pyok', 'pyot', 'pyop', 'pyoh', 'pu', 'pug', 'pugg', 'pugs', 'pun', 'punj', 'punh', 'pud', 'pul', 'pulg', 'pulm', 'pulb', 'puls', 'pult', 'pulp', 'pulh', 'pum', 'pub', 'pubs', 'pus', 'puss', 'pung', 'puj', 'puc', 'puk', 'put', 'pup', 'puh', 'pweo', 'pweog', 'pweogg', 'pweogs', 'pweon', 'pweonj', 'pweonh', 'pweod', 'pweol', 'pweolg', 'pweolm', 'pweolb', 'pweols', 'pweolt', 'pweolp', 'pweolh', 'pweom', 'pweob', 'pweobs', 'pweos', 'pweoss', 'pweong', 'pweoj', 'pweoc', 'pweok', 'pweot', 'pweop', 'pweoh', 'pwe', 'pweg', 'pwegg', 'pwegs', 'pwen', 'pwenj', 'pwenh', 'pwed', 'pwel', 'pwelg', 'pwelm', 'pwelb', 'pwels', 'pwelt', 'pwelp', 'pwelh', 'pwem', 'pweb', 'pwebs', 'pwes', 'pwess', 'pweng', 'pwej', 'pwec', 'pwek', 'pwet', 'pwep', 'pweh', 'pwi', 'pwig', 'pwigg', 'pwigs', 'pwin', 'pwinj', 'pwinh', 'pwid', 'pwil', 'pwilg', 'pwilm', 'pwilb', 'pwils', 'pwilt', 'pwilp', 'pwilh', 'pwim', 'pwib', 'pwibs', 'pwis', 'pwiss', 'pwing', 'pwij', 'pwic', 'pwik', 'pwit', 'pwip', 'pwih', 'pyu', 'pyug', 'pyugg', 'pyugs', 'pyun', 'pyunj', 'pyunh', 'pyud', 'pyul', 'pyulg', 'pyulm', 'pyulb', 'pyuls', 'pyult', 'pyulp', 'pyulh', 'pyum', 'pyub', 'pyubs', 'pyus', 'pyuss', 'pyung', 'pyuj', 'pyuc'];
<?php return ['pyuk', 'pyut', 'pyup', 'pyuh', 'peu', 'peug', 'peugg', 'peugs', 'peun', 'peunj', 'peunh', 'peud', 'peul', 'peulg', 'peulm', 'peulb', 'peuls', 'peult', 'peulp', 'peulh', 'peum', 'peub', 'peubs', 'peus', 'peuss', 'peung', 'peuj', 'peuc', 'peuk', 'peut', 'peup', 'peuh', 'pyi', 'pyig', 'pyigg', 'pyigs', 'pyin', 'pyinj', 'pyinh', 'pyid', 'pyil', 'pyilg', 'pyilm', 'pyilb', 'pyils', 'pyilt', 'pyilp', 'pyilh', 'pyim', 'pyib', 'pyibs', 'pyis', 'pyiss', 'pying', 'pyij', 'pyic', 'pyik', 'pyit', 'pyip', 'pyih', 'pi', 'pig', 'pigg', 'pigs', 'pin', 'pinj', 'pinh', 'pid', 'pil', 'pilg', 'pilm', 'pilb', 'pils', 'pilt', 'pilp', 'pilh', 'pim', 'pib', 'pibs', 'pis', 'piss', 'ping', 'pij', 'pic', 'pik', 'pit', 'pip', 'pih', 'ha', 'hag', 'hagg', 'hags', 'han', 'hanj', 'hanh', 'had', 'hal', 'halg', 'halm', 'halb', 'hals', 'halt', 'halp', 'halh', 'ham', 'hab', 'habs', 'has', 'hass', 'hang', 'haj', 'hac', 'hak', 'hat', 'hap', 'hah', 'hae', 'haeg', 'haegg', 'haegs', 'haen', 'haenj', 'haenh', 'haed', 'hael', 'haelg', 'haelm', 'haelb', 'haels', 'haelt', 'haelp', 'haelh', 'haem', 'haeb', 'haebs', 'haes', 'haess', 'haeng', 'haej', 'haec', 'haek', 'haet', 'haep', 'haeh', 'hya', 'hyag', 'hyagg', 'hyags', 'hyan', 'hyanj', 'hyanh', 'hyad', 'hyal', 'hyalg', 'hyalm', 'hyalb', 'hyals', 'hyalt', 'hyalp', 'hyalh', 'hyam', 'hyab', 'hyabs', 'hyas', 'hyass', 'hyang', 'hyaj', 'hyac', 'hyak', 'hyat', 'hyap', 'hyah', 'hyae', 'hyaeg', 'hyaegg', 'hyaegs', 'hyaen', 'hyaenj', 'hyaenh', 'hyaed', 'hyael', 'hyaelg', 'hyaelm', 'hyaelb', 'hyaels', 'hyaelt', 'hyaelp', 'hyaelh', 'hyaem', 'hyaeb', 'hyaebs', 'hyaes', 'hyaess', 'hyaeng', 'hyaej', 'hyaec', 'hyaek', 'hyaet', 'hyaep', 'hyaeh', 'heo', 'heog', 'heogg', 'heogs', 'heon', 'heonj', 'heonh', 'heod', 'heol', 'heolg', 'heolm', 'heolb', 'heols', 'heolt', 'heolp', 'heolh', 'heom', 'heob', 'heobs', 'heos', 'heoss', 'heong', 'heoj', 'heoc', 'heok', 'heot', 'heop', 'heoh', 'he', 'heg', 'hegg', 'hegs', 'hen', 'henj', 'henh', 'hed', 'hel', 'helg', 'helm', 'helb', 'hels', 'helt', 'help', 'helh', 'hem', 'heb', 'hebs', 'hes', 'hess', 'heng', 'hej', 'hec', 'hek', 'het', 'hep', 'heh'];
<?php return ['hyeo', 'hyeog', 'hyeogg', 'hyeogs', 'hyeon', 'hyeonj', 'hyeonh', 'hyeod', 'hyeol', 'hyeolg', 'hyeolm', 'hyeolb', 'hyeols', 'hyeolt', 'hyeolp', 'hyeolh', 'hyeom', 'hyeob', 'hyeobs', 'hyeos', 'hyeoss', 'hyeong', 'hyeoj', 'hyeoc', 'hyeok', 'hyeot', 'hyeop', 'hyeoh', 'hye', 'hyeg', 'hyegg', 'hyegs', 'hyen', 'hyenj', 'hyenh', 'hyed', 'hyel', 'hyelg', 'hyelm', 'hyelb', 'hyels', 'hyelt', 'hyelp', 'hyelh', 'hyem', 'hyeb', 'hyebs', 'hyes', 'hyess', 'hyeng', 'hyej', 'hyec', 'hyek', 'hyet', 'hyep', 'hyeh', 'ho', 'hog', 'hogg', 'hogs', 'hon', 'honj', 'honh', 'hod', 'hol', 'holg', 'holm', 'holb', 'hols', 'holt', 'holp', 'holh', 'hom', 'hob', 'hobs', 'hos', 'hoss', 'hong', 'hoj', 'hoc', 'hok', 'hot', 'hop', 'hoh', 'hwa', 'hwag', 'hwagg', 'hwags', 'hwan', 'hwanj', 'hwanh', 'hwad', 'hwal', 'hwalg', 'hwalm', 'hwalb', 'hwals', 'hwalt', 'hwalp', 'hwalh', 'hwam', 'hwab', 'hwabs', 'hwas', 'hwass', 'hwang', 'hwaj', 'hwac', 'hwak', 'hwat', 'hwap', 'hwah', 'hwae', 'hwaeg', 'hwaegg', 'hwaegs', 'hwaen', 'hwaenj', 'hwaenh', 'hwaed', 'hwael', 'hwaelg', 'hwaelm', 'hwaelb', 'hwaels', 'hwaelt', 'hwaelp', 'hwaelh', 'hwaem', 'hwaeb', 'hwaebs', 'hwaes', 'hwaess', 'hwaeng', 'hwaej', 'hwaec', 'hwaek', 'hwaet', 'hwaep', 'hwaeh', 'hoe', 'hoeg', 'hoegg', 'hoegs', 'hoen', 'hoenj', 'hoenh', 'hoed', 'hoel', 'hoelg', 'hoelm', 'hoelb', 'hoels', 'hoelt', 'hoelp', 'hoelh', 'hoem', 'hoeb', 'hoebs', 'hoes', 'hoess', 'hoeng', 'hoej', 'hoec', 'hoek', 'hoet', 'hoep', 'hoeh', 'hyo', 'hyog', 'hyogg', 'hyogs', 'hyon', 'hyonj', 'hyonh', 'hyod', 'hyol', 'hyolg', 'hyolm', 'hyolb', 'hyols', 'hyolt', 'hyolp', 'hyolh', 'hyom', 'hyob', 'hyobs', 'hyos', 'hyoss', 'hyong', 'hyoj', 'hyoc', 'hyok', 'hyot', 'hyop', 'hyoh', 'hu', 'hug', 'hugg', 'hugs', 'hun', 'hunj', 'hunh', 'hud', 'hul', 'hulg', 'hulm', 'hulb', 'huls', 'hult', 'hulp', 'hulh', 'hum', 'hub', 'hubs', 'hus', 'huss', 'hung', 'huj', 'huc', 'huk', 'hut', 'hup', 'huh', 'hweo', 'hweog', 'hweogg', 'hweogs', 'hweon', 'hweonj', 'hweonh', 'hweod', 'hweol', 'hweolg', 'hweolm', 'hweolb', 'hweols', 'hweolt', 'hweolp', 'hweolh', 'hweom', 'hweob', 'hweobs', 'hweos', 'hweoss', 'hweong', 'hweoj', 'hweoc', 'hweok', 'hweot', 'hweop', 'hweoh', 'hwe', 'hweg', 'hwegg', 'hwegs'];
<?php return ['hwen', 'hwenj', 'hwenh', 'hwed', 'hwel', 'hwelg', 'hwelm', 'hwelb', 'hwels', 'hwelt', 'hwelp', 'hwelh', 'hwem', 'hweb', 'hwebs', 'hwes', 'hwess', 'hweng', 'hwej', 'hwec', 'hwek', 'hwet', 'hwep', 'hweh', 'hwi', 'hwig', 'hwigg', 'hwigs', 'hwin', 'hwinj', 'hwinh', 'hwid', 'hwil', 'hwilg', 'hwilm', 'hwilb', 'hwils', 'hwilt', 'hwilp', 'hwilh', 'hwim', 'hwib', 'hwibs', 'hwis', 'hwiss', 'hwing', 'hwij', 'hwic', 'hwik', 'hwit', 'hwip', 'hwih', 'hyu', 'hyug', 'hyugg', 'hyugs', 'hyun', 'hyunj', 'hyunh', 'hyud', 'hyul', 'hyulg', 'hyulm', 'hyulb', 'hyuls', 'hyult', 'hyulp', 'hyulh', 'hyum', 'hyub', 'hyubs', 'hyus', 'hyuss', 'hyung', 'hyuj', 'hyuc', 'hyuk', 'hyut', 'hyup', 'hyuh', 'heu', 'heug', 'heugg', 'heugs', 'heun', 'heunj', 'heunh', 'heud', 'heul', 'heulg', 'heulm', 'heulb', 'heuls', 'heult', 'heulp', 'heulh', 'heum', 'heub', 'heubs', 'heus', 'heuss', 'heung', 'heuj', 'heuc', 'heuk', 'heut', 'heup', 'heuh', 'hyi', 'hyig', 'hyigg', 'hyigs', 'hyin', 'hyinj', 'hyinh', 'hyid', 'hyil', 'hyilg', 'hyilm', 'hyilb', 'hyils', 'hyilt', 'hyilp', 'hyilh', 'hyim', 'hyib', 'hyibs', 'hyis', 'hyiss', 'hying', 'hyij', 'hyic', 'hyik', 'hyit', 'hyip', 'hyih', 'hi', 'hig', 'higg', 'higs', 'hin', 'hinj', 'hinh', 'hid', 'hil', 'hilg', 'hilm', 'hilb', 'hils', 'hilt', 'hilp', 'hilh', 'him', 'hib', 'hibs', 'his', 'hiss', 'hing', 'hij', 'hic', 'hik', 'hit', 'hip', 'hih', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['Kay ', 'Kayng ', 'Ke ', 'Ko ', 'Kol ', 'Koc ', 'Kwi ', 'Kwi ', 'Kyun ', 'Kul ', 'Kum ', 'Na ', 'Na ', 'Na ', 'La ', 'Na ', 'Na ', 'Na ', 'Na ', 'Na ', 'Nak ', 'Nak ', 'Nak ', 'Nak ', 'Nak ', 'Nak ', 'Nak ', 'Nan ', 'Nan ', 'Nan ', 'Nan ', 'Nan ', 'Nan ', 'Nam ', 'Nam ', 'Nam ', 'Nam ', 'Nap ', 'Nap ', 'Nap ', 'Nang ', 'Nang ', 'Nang ', 'Nang ', 'Nang ', 'Nay ', 'Nayng ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'No ', 'Nok ', 'Nok ', 'Nok ', 'Nok ', 'Nok ', 'Nok ', 'Non ', 'Nong ', 'Nong ', 'Nong ', 'Nong ', 'Noy ', 'Noy ', 'Noy ', 'Noy ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nwu ', 'Nuk ', 'Nuk ', 'Num ', 'Nung ', 'Nung ', 'Nung ', 'Nung ', 'Nung ', 'Twu ', 'La ', 'Lak ', 'Lak ', 'Lan ', 'Lyeng ', 'Lo ', 'Lyul ', 'Li ', 'Pey ', 'Pen ', 'Pyen ', 'Pwu ', 'Pwul ', 'Pi ', 'Sak ', 'Sak ', 'Sam ', 'Sayk ', 'Sayng ', 'Sep ', 'Sey ', 'Sway ', 'Sin ', 'Sim ', 'Sip ', 'Ya ', 'Yak ', 'Yak ', 'Yang ', 'Yang ', 'Yang ', 'Yang ', 'Yang ', 'Yang ', 'Yang ', 'Yang ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Ye ', 'Yek ', 'Yek ', 'Yek ', 'Yek ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yen ', 'Yel ', 'Yel ', 'Yel ', 'Yel ', 'Yel ', 'Yel ', 'Yem ', 'Yem ', 'Yem ', 'Yem ', 'Yem ', 'Yep ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yeng ', 'Yey ', 'Yey ', 'Yey ', 'Yey ', 'O ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yo ', 'Yong ', 'Wun ', 'Wen ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yu ', 'Yuk ', 'Yuk ', 'Yuk ', 'Yun ', 'Yun ', 'Yun ', 'Yun ', 'Yul ', 'Yul ', 'Yul ', 'Yul ', 'Yung ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'I ', 'Ik ', 'Ik ', 'In ', 'In ', 'In ', 'In ', 'In ', 'In ', 'In ', 'Im ', 'Im ', 'Im ', 'Ip ', 'Ip ', 'Ip ', 'Cang ', 'Cek ', 'Ci ', 'Cip ', 'Cha ', 'Chek '];
<?php return ['Chey ', 'Thak ', 'Thak ', 'Thang ', 'Thayk ', 'Thong ', 'Pho ', 'Phok ', 'Hang ', 'Hang ', 'Hyen ', 'Hwak ', 'Wu ', 'Huo ', '[?] ', '[?] ', 'Zhong ', '[?] ', 'Qing ', '[?] ', '[?] ', 'Xi ', 'Zhu ', 'Yi ', 'Li ', 'Shen ', 'Xiang ', 'Fu ', 'Jing ', 'Jing ', 'Yu ', '[?] ', 'Hagi ', '[?] ', 'Zhu ', '[?] ', '[?] ', 'Yi ', 'Du ', '[?] ', '[?] ', '[?] ', 'Fan ', 'Si ', 'Guan ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]'];
<?php return ['ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', 'mn', 'me', 'mi', 'vn', 'mkh', '[?]', '[?]', '[?]', '[?]', '[?]', 'yi', '', 'ay', '`', '', 'd', 'h', 'k', 'l', 'm', 'm', 't', '+', 'sh', 's', 'sh', 's', 'a', 'a', '', 'b', 'g', 'd', 'h', 'v', 'z', '[?]', 't', 'y', 'k', 'k', 'l', '[?]', 'l', '[?]', 'n', 'n', '[?]', 'p', 'p', '[?]', 'ts', 'ts', 'r', 'sh', 't', 'vo', 'b', 'k', 'p', 'l', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '{Salla}', '{Qala}', 'Allah', 'Akbar', 'Mohammed', 'SL`M', 'Rasul', '{Alayhi}', '{WaSallam}', '{Salla}', '{Salla Llahu Alayhi WaSallam}', '{Jalla Jalalahu}', 'Rial ', '{Bismillah Ar-Rahman Ar-Rahimi}', '[?]', '[?]'];
<?php return ['[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '~', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '..', '--', '-', '_', '_', '(', ') ', '{', '} ', '[', '] ', '[(', ')] ', '<<', '>> ', '<', '> ', '[', '] ', '{', '}', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', ',', ',', '.', '', ';', ':', '?', '!', '-', '(', ')', '{', '}', '{', '}', '#', '&', '*', '+', '-', '<', '>', '=', '', '\\', '$', '%', '@', '[?]', '[?]', '[?]', '[?]', '', '', '', '[?]', '', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', ''];
<?php return ['[?]', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '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', '[', '\\', ']', '^', '_', '`', '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', '{', '|', '}', '~', '[?]', '[?]', '.', '[', ']', ',', '*', 'wo', 'a', 'i', 'u', 'e', 'o', 'ya', 'yu', 'yo', 'tu', '+', 'a', 'i', 'u', 'e', 'o', 'ka', 'ki', 'ku', 'ke', 'ko', 'sa', 'si', 'su', 'se', 'so', 'ta', 'ti', 'tu', 'te', 'to', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'hi', 'hu', 'he', 'ho', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'yu', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'n', ':', ';', '', 'g', 'gg', 'gs', 'n', 'nj', 'nh', 'd', 'dd', 'r', 'lg', 'lm', 'lb', 'ls', 'lt', 'lp', 'rh', 'm', 'b', 'bb', 'bs', 's', 'ss', '', 'j', 'jj', 'c', 'k', 't', 'p', 'h', '[?]', '[?]', '[?]', 'a', 'ae', 'ya', 'yae', 'eo', 'e', '[?]', '[?]', 'yeo', 'ye', 'o', 'wa', 'wae', 'oe', '[?]', '[?]', 'yo', 'u', 'weo', 'we', 'wi', 'yu', '[?]', '[?]', 'eu', 'yi', 'i', '[?]', '[?]', '[?]', '/C', 'PS', '!', '-', '|', 'Y=', 'W=', '[?]', '|', '-', '|', '-', '|', '#', 'O', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '{', '|', '}', '', '', '', ''];
<?php return ['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', 26 => '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', 52 => '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', 78 => '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', 104 => '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', 130 => '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', 156 => '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', 181 => 'Z', 182 => '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', 208 => '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', 234 => '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'];
<?php

return [
    0 => 'w', 'x', 'y', 'z', 4 => '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', 30 => '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', 56 => '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', 82 => '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', 108 => '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', 134 => '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', 160 => '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', 186 => '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', 212 => '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', 238 => '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', ];
<?php return ['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', 'i', 'j', '', '', 'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa', 'Lamda', 'Mu', 'Nu', 'Xi', 'Omicron', 'Pi', 'Rho', 'Theta', 'Sigma', 'Tau', 'Upsilon', 'Phi', 'Chi', 'Psi', 'Omega', 'nabla', 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'lamda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'sigma', 'tai', 'upsilon', 'phi', 'chi', 'psi', 'omega', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
<?php return ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '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'];
<?php return ['0.', '0,', '1,', '2,', '3,', '4,', '5,', '6,', '7,', '8,', '9,', '', '', '', '', '', '(A)', '(B)', '(C)', '(D)', '(E)', '(F)', '(G)', '(H)', '(I)', '(J)', '(K)',   // 0x1a
    '(L)', '(M)', '(N)', '(O)', '(P)', '(Q)', '(R)', '(S)', '(T)', '(U)', '(V)', '(W)', '(X)', '(Y)', '(Z)', 48 => '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', 80 => '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', 112 => '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', 230 => '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', ];
<?php

use voku\helper\Bootup;
use voku\helper\UTF8;

Bootup::initAll(); // Enables UTF-8 for PHP
UTF8::checkForSupport(); // Check UTF-8 support for PHP
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * @psalm-immutable
 */
class Bootup
{
    /**
     * Normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * @param mixed  $input
     * @param int    $normalization_form
     * @param string $leading_combining
     *
     * @return mixed
     */
    public static function filterString(
        $input,
        int $normalization_form = \Normalizer::NFC,
        string $leading_combining = '◌'
    ) {
        return UTF8::filter(
            $input,
            $normalization_form,
            $leading_combining
        );
    }

    /**
     * Get random bytes via "random_bytes()"
     *
     * @param int $length <p>output length</p>
     *
     * @throws \Exception if it was not possible to gather sufficient entropy
     *
     * @return false|string
     *                      <strong>false</strong> on error
     */
    public static function get_random_bytes($length)
    {
        if (!$length) {
            return false;
        }

        $length = (int) $length;

        if ($length <= 0) {
            return false;
        }

        return \random_bytes($length);
    }

    /**
     * Constant FILTER_SANITIZE_STRING polyfill for PHP > 8.1
     *
     * INFO: https://stackoverflow.com/a/69207369/1155858
     *
     * @param string $str
     *
     * @return false|string
     */
    public static function filter_sanitize_string_polyfill(string $str)
    {
        $str = \preg_replace('/\x00|<[^>]*>?/', '', $str);
        if ($str === null) {
            return false;
        }

        return \str_replace(["'", '"'], ['&#39;', '&#34;'], $str);
    }

    /**
     * @return bool
     */
    public static function initAll(): bool
    {
        $result = \ini_set('default_charset', 'UTF-8');

        // everything else is init via composer, so we are done here ...

        return $result !== false;
    }

    /**
     * Determines if the current version of PHP is equal to or greater than the supplied value.
     *
     * @param string $version <p>e.g. "7.1"<p>
     *
     * @return bool
     *              <p>Return <strong>true</strong> if the current version is $version or greater.</p>
     *
     * @psalm-pure
     */
    public static function is_php($version): bool
    {
        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var bool[]
         */
        static $_IS_PHP;

        $version = (string) $version;

        if (!isset($_IS_PHP[$version])) {
            $_IS_PHP[$version] = \version_compare(\PHP_VERSION, $version, '>=');
        }

        return $_IS_PHP[$version];
    }
}
<?php

return [
    0 => [
        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  => 'ᾇ',
        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  => 'ᾡ',
        51  => 'ᾢ',
        52  => 'ᾣ',
        53  => 'ᾤ',
        54  => 'ᾥ',
        55  => 'ᾦ',
        56  => 'ᾧ',
        57  => 'ᾨ',
        58  => 'ᾩ',
        59  => 'ᾪ',
        60  => 'ᾫ',
        61  => 'ᾬ',
        62  => 'ᾭ',
        63  => 'ᾮ',
        64  => 'ᾯ',
        65  => 'ᾲ',
        66  => 'ᾳ',
        67  => 'ᾴ',
        68  => 'ᾶ',
        69  => 'ᾷ',
        70  => 'ᾼ',
        71  => 'ῂ',
        72  => 'ῃ',
        73  => 'ῄ',
        74  => 'ῆ',
        75  => 'ῇ',
        76  => 'ῌ',
        77  => 'ῒ',
        78  => 'ΐ',
        79  => 'ῖ',
        80  => 'ῗ',
        81  => 'ῢ',
        82  => 'ΰ',
        83  => 'ῤ',
        84  => 'ῦ',
        85  => 'ῧ',
        86  => 'ῲ',
        87  => 'ῳ',
        88  => 'ῴ',
        89  => 'ῶ',
        90  => 'ῷ',
        91  => 'ῼ',
        92  => 'ﬀ',
        93  => 'ﬁ',
        94  => 'ﬂ',
        95  => 'ﬃ',
        96  => 'ﬄ',
        97  => 'ﬅ',
        98  => 'ﬆ',
        99  => 'ﬓ',
        100 => 'ﬔ',
        101 => 'ﬕ',
        102 => 'ﬖ',
        103 => 'ﬗ',
        104 => 'J̌̌',
    ],
    1 => [
        0   => 'ss',
        1   => 'i̇',
        2   => 'ʼn',
        3   => 'ǰ',
        4   => 'ΐ',
        5   => 'ΰ',
        6   => 'եւ',
        7   => 'ẖ',
        8   => 'ẗ',
        9   => 'ẘ',
        10  => 'ẙ',
        11  => 'aʾ',
        12  => 'ss',
        13  => 'ὐ',
        14  => 'ὒ',
        15  => 'ὔ',
        16  => 'ὖ',
        17  => 'ἀι',
        18  => 'ἁι',
        19  => 'ἂι',
        20  => 'ἃι',
        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  => 'ὡι',
        51  => 'ὢι',
        52  => 'ὣι',
        53  => 'ὤι',
        54  => 'ὥι',
        55  => 'ὦι',
        56  => 'ὧι',
        57  => 'ὠι',
        58  => 'ὡι',
        59  => 'ὢι',
        60  => 'ὣι',
        61  => 'ὤι',
        62  => 'ὥι',
        63  => 'ὦι',
        64  => 'ὧι',
        65  => 'ὰι',
        66  => 'αι',
        67  => 'άι',
        68  => 'ᾶ',
        69  => 'ᾶι',
        70  => 'αι',
        71  => 'ὴι',
        72  => 'ηι',
        73  => 'ήι',
        74  => 'ῆ',
        75  => 'ῆι',
        76  => 'ηι',
        77  => 'ῒ',
        78  => 'ΐ',
        79  => 'ῖ',
        80  => 'ῗ',
        81  => 'ῢ',
        82  => 'ΰ',
        83  => 'ῤ',
        84  => 'ῦ',
        85  => 'ῧ',
        86  => 'ὼι',
        87  => 'ωι',
        88  => 'ώι',
        89  => 'ῶ',
        90  => 'ῶι',
        91  => 'ωι',
        92  => 'ff',
        93  => 'fi',
        94  => 'fl',
        95  => 'ffi',
        96  => 'ffl',
        97  => 'st',
        98  => 'st',
        99  => 'մն',
        100 => 'մե',
        101 => 'մի',
        102 => 'վն',
        103 => 'մխ',
        104 => 'ǰ',
    ],
];
<?php return [0 => "\x00", 1 => "\x01", 2 => "\x02", 3 => "\x03", 4 => "\x04", 5 => "\x05", 6 => "\x06", 7 => "\x07", 8 => "\x08", 9 => "\x09", 10 => "\x0A", 11 => "\x0B", 12 => "\x0C", 13 => "\x0D", 14 => "\x0E", 15 => "\x0F", 16 => "\x10", 17 => "\x11", 18 => "\x12", 19 => "\x13", 20 => "\x14", 21 => "\x15", 22 => "\x16", 23 => "\x17", 24 => "\x18", 25 => "\x19", 26 => "\x1A", 27 => "\x1B", 28 => "\x1C", 29 => "\x1D", 30 => "\x1E", 31 => "\x1F", 32 => "\x20", 33 => "\x21", 34 => "\x22", 35 => "\x23", 36 => "\x24", 37 => "\x25", 38 => "\x26", 39 => "\x27", 40 => "\x28", 41 => "\x29", 42 => "\x2A", 43 => "\x2B", 44 => "\x2C", 45 => "\x2D", 46 => "\x2E", 47 => "\x2F", 48 => "\x30", 49 => "\x31", 50 => "\x32", 51 => "\x33", 52 => "\x34", 53 => "\x35", 54 => "\x36", 55 => "\x37", 56 => "\x38", 57 => "\x39", 58 => "\x3A", 59 => "\x3B", 60 => "\x3C", 61 => "\x3D", 62 => "\x3E", 63 => "\x3F", 64 => "\x40", 65 => "\x41", 66 => "\x42", 67 => "\x43", 68 => "\x44", 69 => "\x45", 70 => "\x46", 71 => "\x47", 72 => "\x48", 73 => "\x49", 74 => "\x4A", 75 => "\x4B", 76 => "\x4C", 77 => "\x4D", 78 => "\x4E", 79 => "\x4F", 80 => "\x50", 81 => "\x51", 82 => "\x52", 83 => "\x53", 84 => "\x54", 85 => "\x55", 86 => "\x56", 87 => "\x57", 88 => "\x58", 89 => "\x59", 90 => "\x5A", 91 => "\x5B", 92 => "\x5C", 93 => "\x5D", 94 => "\x5E", 95 => "\x5F", 96 => "\x60", 97 => "\x61", 98 => "\x62", 99 => "\x63", 100 => "\x64", 101 => "\x65", 102 => "\x66", 103 => "\x67", 104 => "\x68", 105 => "\x69", 106 => "\x6A", 107 => "\x6B", 108 => "\x6C", 109 => "\x6D", 110 => "\x6E", 111 => "\x6F", 112 => "\x70", 113 => "\x71", 114 => "\x72", 115 => "\x73", 116 => "\x74", 117 => "\x75", 118 => "\x76", 119 => "\x77", 120 => "\x78", 121 => "\x79", 122 => "\x7A", 123 => "\x7B", 124 => "\x7C", 125 => "\x7D", 126 => "\x7E", 127 => "\x7F", 128 => "\x80", 129 => "\x81", 130 => "\x82", 131 => "\x83", 132 => "\x84", 133 => "\x85", 134 => "\x86", 135 => "\x87", 136 => "\x88", 137 => "\x89", 138 => "\x8A", 139 => "\x8B", 140 => "\x8C", 141 => "\x8D", 142 => "\x8E", 143 => "\x8F", 144 => "\x90", 145 => "\x91", 146 => "\x92", 147 => "\x93", 148 => "\x94", 149 => "\x95", 150 => "\x96", 151 => "\x97", 152 => "\x98", 153 => "\x99", 154 => "\x9A", 155 => "\x9B", 156 => "\x9C", 157 => "\x9D", 158 => "\x9E", 159 => "\x9F", 160 => "\xA0", 161 => "\xA1", 162 => "\xA2", 163 => "\xA3", 164 => "\xA4", 165 => "\xA5", 166 => "\xA6", 167 => "\xA7", 168 => "\xA8", 169 => "\xA9", 170 => "\xAA", 171 => "\xAB", 172 => "\xAC", 173 => "\xAD", 174 => "\xAE", 175 => "\xAF", 176 => "\xB0", 177 => "\xB1", 178 => "\xB2", 179 => "\xB3", 180 => "\xB4", 181 => "\xB5", 182 => "\xB6", 183 => "\xB7", 184 => "\xB8", 185 => "\xB9", 186 => "\xBA", 187 => "\xBB", 188 => "\xBC", 189 => "\xBD", 190 => "\xBE", 191 => "\xBF", 192 => "\xC0", 193 => "\xC1", 194 => "\xC2", 195 => "\xC3", 196 => "\xC4", 197 => "\xC5", 198 => "\xC6", 199 => "\xC7", 200 => "\xC8", 201 => "\xC9", 202 => "\xCA", 203 => "\xCB", 204 => "\xCC", 205 => "\xCD", 206 => "\xCE", 207 => "\xCF", 208 => "\xD0", 209 => "\xD1", 210 => "\xD2", 211 => "\xD3", 212 => "\xD4", 213 => "\xD5", 214 => "\xD6", 215 => "\xD7", 216 => "\xD8", 217 => "\xD9", 218 => "\xDA", 219 => "\xDB", 220 => "\xDC", 221 => "\xDD", 222 => "\xDE", 223 => "\xDF", 224 => "\xE0", 225 => "\xE1", 226 => "\xE2", 227 => "\xE3", 228 => "\xE4", 229 => "\xE5", 230 => "\xE6", 231 => "\xE7", 232 => "\xE8", 233 => "\xE9", 234 => "\xEA", 235 => "\xEB", 236 => "\xEC", 237 => "\xED", 238 => "\xEE", 239 => "\xEF", 240 => "\xF0", 241 => "\xF1", 242 => "\xF2", 243 => "\xF3", 244 => "\xF4", 245 => "\xF5", 246 => "\xF6", 247 => "\xF7", 248 => "\xF8", 249 => "\xF9", 250 => "\xFA", 251 => "\xFB", 252 => "\xFC", 253 => "\xFD", 254 => "\xFE", 255 => "\xFF"];
<?php

// ########## Unicode Emoji v11.0 ##########
// ##### Emoji group: Smileys & People #####
// ##### Emoji subgroup: Face-positive #####

return ['CHARACTER_GRINNING_FACE' => "\u{1F600}", 'CHARACTER_BEAMING_FACE_WITH_SMILING_EYES' => "\u{1F601}", 'CHARACTER_FACE_WITH_TEARS_OF_JOY' => "\u{1F602}", 'CHARACTER_ROLLING_ON_THE_FLOOR_LAUGHING' => "\u{1F923}", 'CHARACTER_GRINNING_FACE_WITH_BIG_EYES' => "\u{1F603}", 'CHARACTER_GRINNING_FACE_WITH_SMILING_EYES' => "\u{1F604}", 'CHARACTER_GRINNING_FACE_WITH_SWEAT' => "\u{1F605}", 'CHARACTER_GRINNING_SQUINTING_FACE' => "\u{1F606}", 'CHARACTER_WINKING_FACE' => "\u{1F609}", 'CHARACTER_SMILING_FACE_WITH_SMILING_EYES' => "\u{1F60A}", 'CHARACTER_FACE_SAVORING_FOOD' => "\u{1F60B}", 'CHARACTER_SMILING_FACE_WITH_SUNGLASSES' => "\u{1F60E}", 'CHARACTER_SMILING_FACE_WITH_HEART_EYES' => "\u{1F60D}", 'CHARACTER_FACE_BLOWING_A_KISS' => "\u{1F618}", 'CHARACTER_SMILING_FACE_WITH_3_HEARTS' => "\u{1F970}", 'CHARACTER_KISSING_FACE' => "\u{1F617}", 'CHARACTER_KISSING_FACE_WITH_SMILING_EYES' => "\u{1F619}", 'CHARACTER_KISSING_FACE_WITH_CLOSED_EYES' => "\u{1F61A}", 'CHARACTER_SMILING_FACE' => "\u{263A}\u{FE0F}", 'CHARACTER_SLIGHTLY_SMILING_FACE' => "\u{1F642}", 'CHARACTER_HUGGING_FACE' => "\u{1F917}", 'CHARACTER_STAR_STRUCK' => "\u{1F929}", 'CHARACTER_THINKING_FACE' => "\u{1F914}", 'CHARACTER_FACE_WITH_RAISED_EYEBROW' => "\u{1F928}", 'CHARACTER_NEUTRAL_FACE' => "\u{1F610}", 'CHARACTER_EXPRESSIONLESS_FACE' => "\u{1F611}", 'CHARACTER_FACE_WITHOUT_MOUTH' => "\u{1F636}", 'CHARACTER_FACE_WITH_ROLLING_EYES' => "\u{1F644}", 'CHARACTER_SMIRKING_FACE' => "\u{1F60F}", 'CHARACTER_PERSEVERING_FACE' => "\u{1F623}", 'CHARACTER_SAD_BUT_RELIEVED_FACE' => "\u{1F625}", 'CHARACTER_FACE_WITH_OPEN_MOUTH' => "\u{1F62E}", 'CHARACTER_ZIPPER_MOUTH_FACE' => "\u{1F910}", 'CHARACTER_HUSHED_FACE' => "\u{1F62F}", 'CHARACTER_SLEEPY_FACE' => "\u{1F62A}", 'CHARACTER_TIRED_FACE' => "\u{1F62B}", 'CHARACTER_SLEEPING_FACE' => "\u{1F634}", 'CHARACTER_RELIEVED_FACE' => "\u{1F60C}", 'CHARACTER_FACE_WITH_TONGUE' => "\u{1F61B}", 'CHARACTER_WINKING_FACE_WITH_TONGUE' => "\u{1F61C}", 'CHARACTER_SQUINTING_FACE_WITH_TONGUE' => "\u{1F61D}", 'CHARACTER_DROOLING_FACE' => "\u{1F924}", 'CHARACTER_UNAMUSED_FACE' => "\u{1F612}", 'CHARACTER_DOWNCAST_FACE_WITH_SWEAT' => "\u{1F613}", 'CHARACTER_PENSIVE_FACE' => "\u{1F614}", 'CHARACTER_CONFUSED_FACE' => "\u{1F615}", 'CHARACTER_UPSIDE_DOWN_FACE' => "\u{1F643}", 'CHARACTER_MONEY_MOUTH_FACE' => "\u{1F911}", 'CHARACTER_ASTONISHED_FACE' => "\u{1F632}", 'CHARACTER_FROWNING_FACE' => "\u{2639}\u{FE0F}", 'CHARACTER_SLIGHTLY_FROWNING_FACE' => "\u{1F641}", 'CHARACTER_CONFOUNDED_FACE' => "\u{1F616}", 'CHARACTER_DISAPPOINTED_FACE' => "\u{1F61E}", 'CHARACTER_WORRIED_FACE' => "\u{1F61F}", 'CHARACTER_FACE_WITH_STEAM_FROM_NOSE' => "\u{1F624}", 'CHARACTER_CRYING_FACE' => "\u{1F622}", 'CHARACTER_LOUDLY_CRYING_FACE' => "\u{1F62D}", 'CHARACTER_FROWNING_FACE_WITH_OPEN_MOUTH' => "\u{1F626}", 'CHARACTER_ANGUISHED_FACE' => "\u{1F627}", 'CHARACTER_FEARFUL_FACE' => "\u{1F628}", 'CHARACTER_WEARY_FACE' => "\u{1F629}", 'CHARACTER_EXPLODING_HEAD' => "\u{1F92F}", 'CHARACTER_GRIMACING_FACE' => "\u{1F62C}", 'CHARACTER_ANXIOUS_FACE_WITH_SWEAT' => "\u{1F630}", 'CHARACTER_FACE_SCREAMING_IN_FEAR' => "\u{1F631}", 'CHARACTER_HOT_FACE' => "\u{1F975}", 'CHARACTER_COLD_FACE' => "\u{1F976}", 'CHARACTER_FLUSHED_FACE' => "\u{1F633}", 'CHARACTER_ZANY_FACE' => "\u{1F92A}", 'CHARACTER_DIZZY_FACE' => "\u{1F635}", 'CHARACTER_POUTING_FACE' => "\u{1F621}", 'CHARACTER_ANGRY_FACE' => "\u{1F620}", 'CHARACTER_FACE_WITH_SYMBOLS_ON_MOUTH' => "\u{1F92C}", 'CHARACTER_FACE_WITH_MEDICAL_MASK' => "\u{1F637}", 'CHARACTER_FACE_WITH_THERMOMETER' => "\u{1F912}", 'CHARACTER_FACE_WITH_HEAD_BANDAGE' => "\u{1F915}", 'CHARACTER_NAUSEATED_FACE' => "\u{1F922}", 'CHARACTER_FACE_VOMITING' => "\u{1F92E}", 'CHARACTER_SNEEZING_FACE' => "\u{1F927}", 'CHARACTER_SMILING_FACE_WITH_HALO' => "\u{1F607}", 'CHARACTER_COWBOY_HAT_FACE' => "\u{1F920}", 'CHARACTER_PARTYING_FACE' => "\u{1F973}", 'CHARACTER_WOOZY_FACE' => "\u{1F974}", 'CHARACTER_PLEADING_FACE' => "\u{1F97A}", 'CHARACTER_LYING_FACE' => "\u{1F925}", 'CHARACTER_SHUSHING_FACE' => "\u{1F92B}", 'CHARACTER_FACE_WITH_HAND_OVER_MOUTH' => "\u{1F92D}", 'CHARACTER_FACE_WITH_MONOCLE' => "\u{1F9D0}", 'CHARACTER_NERD_FACE' => "\u{1F913}", 'CHARACTER_SMILING_FACE_WITH_HORNS' => "\u{1F608}", 'CHARACTER_ANGRY_FACE_WITH_HORNS' => "\u{1F47F}", 'CHARACTER_CLOWN_FACE' => "\u{1F921}", 'CHARACTER_OGRE' => "\u{1F479}", 'CHARACTER_GOBLIN' => "\u{1F47A}", 'CHARACTER_SKULL' => "\u{1F480}", 'CHARACTER_SKULL_AND_CROSSBONES' => "\u{2620}\u{FE0F}", 'CHARACTER_GHOST' => "\u{1F47B}", 'CHARACTER_ALIEN' => "\u{1F47D}", 'CHARACTER_ALIEN_MONSTER' => "\u{1F47E}", 'CHARACTER_ROBOT_FACE' => "\u{1F916}", 'CHARACTER_PILE_OF_POO' => "\u{1F4A9}", 'CHARACTER_GRINNING_CAT_FACE' => "\u{1F63A}", 'CHARACTER_GRINNING_CAT_FACE_WITH_SMILING_EYES' => "\u{1F638}", 'CHARACTER_CAT_FACE_WITH_TEARS_OF_JOY' => "\u{1F639}", 'CHARACTER_SMILING_CAT_FACE_WITH_HEART_EYES' => "\u{1F63B}", 'CHARACTER_CAT_FACE_WITH_WRY_SMILE' => "\u{1F63C}", 'CHARACTER_KISSING_CAT_FACE' => "\u{1F63D}", 'CHARACTER_WEARY_CAT_FACE' => "\u{1F640}", 'CHARACTER_CRYING_CAT_FACE' => "\u{1F63F}", 'CHARACTER_POUTING_CAT_FACE' => "\u{1F63E}", 'CHARACTER_SEE_NO_EVIL_MONKEY' => "\u{1F648}", 'CHARACTER_HEAR_NO_EVIL_MONKEY' => "\u{1F649}", 'CHARACTER_SPEAK_NO_EVIL_MONKEY' => "\u{1F64A}", 'CHARACTER_LIGHT_SKIN_TONE' => "\u{1F3FB}", 'CHARACTER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3FC}", 'CHARACTER_MEDIUM_SKIN_TONE' => "\u{1F3FD}", 'CHARACTER_MEDIUM_DARK_SKIN_TONE' => "\u{1F3FE}", 'CHARACTER_DARK_SKIN_TONE' => "\u{1F3FF}", 'CHARACTER_BABY' => "\u{1F476}", 'CHARACTER_BABY_LIGHT_SKIN_TONE' => "\u{1F476}\u{1F3FB}", 'CHARACTER_BABY_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F476}\u{1F3FC}", 'CHARACTER_BABY_MEDIUM_SKIN_TONE' => "\u{1F476}\u{1F3FD}", 'CHARACTER_BABY_MEDIUM_DARK_SKIN_TONE' => "\u{1F476}\u{1F3FE}", 'CHARACTER_BABY_DARK_SKIN_TONE' => "\u{1F476}\u{1F3FF}", 'CHARACTER_CHILD' => "\u{1F9D2}", 'CHARACTER_CHILD_LIGHT_SKIN_TONE' => "\u{1F9D2}\u{1F3FB}", 'CHARACTER_CHILD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D2}\u{1F3FC}", 'CHARACTER_CHILD_MEDIUM_SKIN_TONE' => "\u{1F9D2}\u{1F3FD}", 'CHARACTER_CHILD_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D2}\u{1F3FE}", 'CHARACTER_CHILD_DARK_SKIN_TONE' => "\u{1F9D2}\u{1F3FF}", 'CHARACTER_BOY' => "\u{1F466}", 'CHARACTER_BOY_LIGHT_SKIN_TONE' => "\u{1F466}\u{1F3FB}", 'CHARACTER_BOY_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F466}\u{1F3FC}", 'CHARACTER_BOY_MEDIUM_SKIN_TONE' => "\u{1F466}\u{1F3FD}", 'CHARACTER_BOY_MEDIUM_DARK_SKIN_TONE' => "\u{1F466}\u{1F3FE}", 'CHARACTER_BOY_DARK_SKIN_TONE' => "\u{1F466}\u{1F3FF}", 'CHARACTER_GIRL' => "\u{1F467}", 'CHARACTER_GIRL_LIGHT_SKIN_TONE' => "\u{1F467}\u{1F3FB}", 'CHARACTER_GIRL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F467}\u{1F3FC}", 'CHARACTER_GIRL_MEDIUM_SKIN_TONE' => "\u{1F467}\u{1F3FD}", 'CHARACTER_GIRL_MEDIUM_DARK_SKIN_TONE' => "\u{1F467}\u{1F3FE}", 'CHARACTER_GIRL_DARK_SKIN_TONE' => "\u{1F467}\u{1F3FF}", 'CHARACTER_ADULT' => "\u{1F9D1}", 'CHARACTER_ADULT_LIGHT_SKIN_TONE' => "\u{1F9D1}\u{1F3FB}", 'CHARACTER_ADULT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D1}\u{1F3FC}", 'CHARACTER_ADULT_MEDIUM_SKIN_TONE' => "\u{1F9D1}\u{1F3FD}", 'CHARACTER_ADULT_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D1}\u{1F3FE}", 'CHARACTER_ADULT_DARK_SKIN_TONE' => "\u{1F9D1}\u{1F3FF}", 'CHARACTER_MAN' => "\u{1F468}", 'CHARACTER_MAN_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}", 'CHARACTER_MAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}", 'CHARACTER_MAN_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}", 'CHARACTER_MAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}", 'CHARACTER_MAN_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}", 'CHARACTER_WOMAN' => "\u{1F469}", 'CHARACTER_WOMAN_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}", 'CHARACTER_WOMAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}", 'CHARACTER_WOMAN_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}", 'CHARACTER_WOMAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}", 'CHARACTER_WOMAN_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}", 'CHARACTER_OLDER_ADULT' => "\u{1F9D3}", 'CHARACTER_OLDER_ADULT_LIGHT_SKIN_TONE' => "\u{1F9D3}\u{1F3FB}", 'CHARACTER_OLDER_ADULT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D3}\u{1F3FC}", 'CHARACTER_OLDER_ADULT_MEDIUM_SKIN_TONE' => "\u{1F9D3}\u{1F3FD}", 'CHARACTER_OLDER_ADULT_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D3}\u{1F3FE}", 'CHARACTER_OLDER_ADULT_DARK_SKIN_TONE' => "\u{1F9D3}\u{1F3FF}", 'CHARACTER_OLD_MAN' => "\u{1F474}", 'CHARACTER_OLD_MAN_LIGHT_SKIN_TONE' => "\u{1F474}\u{1F3FB}", 'CHARACTER_OLD_MAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F474}\u{1F3FC}", 'CHARACTER_OLD_MAN_MEDIUM_SKIN_TONE' => "\u{1F474}\u{1F3FD}", 'CHARACTER_OLD_MAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F474}\u{1F3FE}", 'CHARACTER_OLD_MAN_DARK_SKIN_TONE' => "\u{1F474}\u{1F3FF}", 'CHARACTER_OLD_WOMAN' => "\u{1F475}", 'CHARACTER_OLD_WOMAN_LIGHT_SKIN_TONE' => "\u{1F475}\u{1F3FB}", 'CHARACTER_OLD_WOMAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F475}\u{1F3FC}", 'CHARACTER_OLD_WOMAN_MEDIUM_SKIN_TONE' => "\u{1F475}\u{1F3FD}", 'CHARACTER_OLD_WOMAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F475}\u{1F3FE}", 'CHARACTER_OLD_WOMAN_DARK_SKIN_TONE' => "\u{1F475}\u{1F3FF}", 'CHARACTER_MAN_HEALTH_WORKER' => "\u{1F468}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_HEALTH_WORKER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_HEALTH_WORKER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_HEALTH_WORKER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER' => "\u{1F469}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_WOMAN_HEALTH_WORKER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{2695}\u{FE0F}", 'CHARACTER_MAN_STUDENT' => "\u{1F468}\u{200D}\u{1F393}", 'CHARACTER_MAN_STUDENT_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F393}", 'CHARACTER_MAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F393}", 'CHARACTER_MAN_STUDENT_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F393}", 'CHARACTER_MAN_STUDENT_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F393}", 'CHARACTER_MAN_STUDENT_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT' => "\u{1F469}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F393}", 'CHARACTER_WOMAN_STUDENT_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F393}", 'CHARACTER_MAN_TEACHER' => "\u{1F468}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_TEACHER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_TEACHER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_TEACHER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_TEACHER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER' => "\u{1F469}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F3EB}", 'CHARACTER_WOMAN_TEACHER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F3EB}", 'CHARACTER_MAN_JUDGE' => "\u{1F468}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_JUDGE_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_JUDGE_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_JUDGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_JUDGE_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE' => "\u{1F469}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_WOMAN_JUDGE_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{2696}\u{FE0F}", 'CHARACTER_MAN_FARMER' => "\u{1F468}\u{200D}\u{1F33E}", 'CHARACTER_MAN_FARMER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F33E}", 'CHARACTER_MAN_FARMER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F33E}", 'CHARACTER_MAN_FARMER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F33E}", 'CHARACTER_MAN_FARMER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F33E}", 'CHARACTER_MAN_FARMER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER' => "\u{1F469}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F33E}", 'CHARACTER_WOMAN_FARMER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F33E}", 'CHARACTER_MAN_COOK' => "\u{1F468}\u{200D}\u{1F373}", 'CHARACTER_MAN_COOK_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F373}", 'CHARACTER_MAN_COOK_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F373}", 'CHARACTER_MAN_COOK_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F373}", 'CHARACTER_MAN_COOK_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F373}", 'CHARACTER_MAN_COOK_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK' => "\u{1F469}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F373}", 'CHARACTER_WOMAN_COOK_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F373}", 'CHARACTER_MAN_MECHANIC' => "\u{1F468}\u{200D}\u{1F527}", 'CHARACTER_MAN_MECHANIC_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F527}", 'CHARACTER_MAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F527}", 'CHARACTER_MAN_MECHANIC_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F527}", 'CHARACTER_MAN_MECHANIC_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F527}", 'CHARACTER_MAN_MECHANIC_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC' => "\u{1F469}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F527}", 'CHARACTER_WOMAN_MECHANIC_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F527}", 'CHARACTER_MAN_FACTORY_WORKER' => "\u{1F468}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_FACTORY_WORKER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_FACTORY_WORKER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_FACTORY_WORKER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER' => "\u{1F469}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F3ED}", 'CHARACTER_WOMAN_FACTORY_WORKER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F3ED}", 'CHARACTER_MAN_OFFICE_WORKER' => "\u{1F468}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_OFFICE_WORKER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_OFFICE_WORKER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_OFFICE_WORKER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER' => "\u{1F469}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F4BC}", 'CHARACTER_WOMAN_OFFICE_WORKER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F4BC}", 'CHARACTER_MAN_SCIENTIST' => "\u{1F468}\u{200D}\u{1F52C}", 'CHARACTER_MAN_SCIENTIST_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F52C}", 'CHARACTER_MAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F52C}", 'CHARACTER_MAN_SCIENTIST_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F52C}", 'CHARACTER_MAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F52C}", 'CHARACTER_MAN_SCIENTIST_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST' => "\u{1F469}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F52C}", 'CHARACTER_WOMAN_SCIENTIST_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F52C}", 'CHARACTER_MAN_TECHNOLOGIST' => "\u{1F468}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_TECHNOLOGIST_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_TECHNOLOGIST_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_TECHNOLOGIST_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST' => "\u{1F469}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F4BB}", 'CHARACTER_WOMAN_TECHNOLOGIST_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F4BB}", 'CHARACTER_MAN_SINGER' => "\u{1F468}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_SINGER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_SINGER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_SINGER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_SINGER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_SINGER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER' => "\u{1F469}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F3A4}", 'CHARACTER_WOMAN_SINGER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F3A4}", 'CHARACTER_MAN_ARTIST' => "\u{1F468}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_ARTIST_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_ARTIST_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_ARTIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_ARTIST_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST' => "\u{1F469}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F3A8}", 'CHARACTER_WOMAN_ARTIST_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F3A8}", 'CHARACTER_MAN_PILOT' => "\u{1F468}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_PILOT_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_PILOT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_PILOT_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_PILOT_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_PILOT_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT' => "\u{1F469}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_WOMAN_PILOT_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{2708}\u{FE0F}", 'CHARACTER_MAN_ASTRONAUT' => "\u{1F468}\u{200D}\u{1F680}", 'CHARACTER_MAN_ASTRONAUT_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F680}", 'CHARACTER_MAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F680}", 'CHARACTER_MAN_ASTRONAUT_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F680}", 'CHARACTER_MAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F680}", 'CHARACTER_MAN_ASTRONAUT_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT' => "\u{1F469}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F680}", 'CHARACTER_WOMAN_ASTRONAUT_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F680}", 'CHARACTER_MAN_FIREFIGHTER' => "\u{1F468}\u{200D}\u{1F692}", 'CHARACTER_MAN_FIREFIGHTER_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F692}", 'CHARACTER_MAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F692}", 'CHARACTER_MAN_FIREFIGHTER_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F692}", 'CHARACTER_MAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F692}", 'CHARACTER_MAN_FIREFIGHTER_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER' => "\u{1F469}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F692}", 'CHARACTER_WOMAN_FIREFIGHTER_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F692}", 'CHARACTER_POLICE_OFFICER' => "\u{1F46E}", 'CHARACTER_POLICE_OFFICER_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FB}", 'CHARACTER_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FC}", 'CHARACTER_POLICE_OFFICER_MEDIUM_SKIN_TONE' => "\u{1F46E}\u{1F3FD}", 'CHARACTER_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FE}", 'CHARACTER_POLICE_OFFICER_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FF}", 'CHARACTER_MAN_POLICE_OFFICER' => "\u{1F46E}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POLICE_OFFICER_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POLICE_OFFICER_MEDIUM_SKIN_TONE' => "\u{1F46E}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POLICE_OFFICER_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER' => "\u{1F46E}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F46E}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER_MEDIUM_SKIN_TONE' => "\u{1F46E}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POLICE_OFFICER_DARK_SKIN_TONE' => "\u{1F46E}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_DETECTIVE' => "\u{1F575}\u{FE0F}", 'CHARACTER_DETECTIVE_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FB}", 'CHARACTER_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FC}", 'CHARACTER_DETECTIVE_MEDIUM_SKIN_TONE' => "\u{1F575}\u{1F3FD}", 'CHARACTER_DETECTIVE_MEDIUM_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FE}", 'CHARACTER_DETECTIVE_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FF}", 'CHARACTER_MAN_DETECTIVE' => "\u{1F575}\u{FE0F}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_DETECTIVE_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_DETECTIVE_MEDIUM_SKIN_TONE' => "\u{1F575}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_DETECTIVE_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE' => "\u{1F575}\u{FE0F}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F575}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE_MEDIUM_SKIN_TONE' => "\u{1F575}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DETECTIVE_DARK_SKIN_TONE' => "\u{1F575}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_GUARD' => "\u{1F482}", 'CHARACTER_GUARD_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FB}", 'CHARACTER_GUARD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FC}", 'CHARACTER_GUARD_MEDIUM_SKIN_TONE' => "\u{1F482}\u{1F3FD}", 'CHARACTER_GUARD_MEDIUM_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FE}", 'CHARACTER_GUARD_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FF}", 'CHARACTER_MAN_GUARD' => "\u{1F482}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GUARD_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GUARD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GUARD_MEDIUM_SKIN_TONE' => "\u{1F482}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GUARD_MEDIUM_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GUARD_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GUARD' => "\u{1F482}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GUARD_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GUARD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F482}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GUARD_MEDIUM_SKIN_TONE' => "\u{1F482}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GUARD_MEDIUM_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GUARD_DARK_SKIN_TONE' => "\u{1F482}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_CONSTRUCTION_WORKER' => "\u{1F477}", 'CHARACTER_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FB}", 'CHARACTER_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FC}", 'CHARACTER_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE' => "\u{1F477}\u{1F3FD}", 'CHARACTER_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FE}", 'CHARACTER_CONSTRUCTION_WORKER_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FF}", 'CHARACTER_MAN_CONSTRUCTION_WORKER' => "\u{1F477}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE' => "\u{1F477}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER' => "\u{1F477}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F477}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE' => "\u{1F477}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE' => "\u{1F477}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PRINCE' => "\u{1F934}", 'CHARACTER_PRINCE_LIGHT_SKIN_TONE' => "\u{1F934}\u{1F3FB}", 'CHARACTER_PRINCE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F934}\u{1F3FC}", 'CHARACTER_PRINCE_MEDIUM_SKIN_TONE' => "\u{1F934}\u{1F3FD}", 'CHARACTER_PRINCE_MEDIUM_DARK_SKIN_TONE' => "\u{1F934}\u{1F3FE}", 'CHARACTER_PRINCE_DARK_SKIN_TONE' => "\u{1F934}\u{1F3FF}", 'CHARACTER_PRINCESS' => "\u{1F478}", 'CHARACTER_PRINCESS_LIGHT_SKIN_TONE' => "\u{1F478}\u{1F3FB}", 'CHARACTER_PRINCESS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F478}\u{1F3FC}", 'CHARACTER_PRINCESS_MEDIUM_SKIN_TONE' => "\u{1F478}\u{1F3FD}", 'CHARACTER_PRINCESS_MEDIUM_DARK_SKIN_TONE' => "\u{1F478}\u{1F3FE}", 'CHARACTER_PRINCESS_DARK_SKIN_TONE' => "\u{1F478}\u{1F3FF}", 'CHARACTER_PERSON_WEARING_TURBAN' => "\u{1F473}", 'CHARACTER_PERSON_WEARING_TURBAN_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FB}", 'CHARACTER_PERSON_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FC}", 'CHARACTER_PERSON_WEARING_TURBAN_MEDIUM_SKIN_TONE' => "\u{1F473}\u{1F3FD}", 'CHARACTER_PERSON_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FE}", 'CHARACTER_PERSON_WEARING_TURBAN_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FF}", 'CHARACTER_MAN_WEARING_TURBAN' => "\u{1F473}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WEARING_TURBAN_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WEARING_TURBAN_MEDIUM_SKIN_TONE' => "\u{1F473}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WEARING_TURBAN_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN' => "\u{1F473}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F473}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN_MEDIUM_SKIN_TONE' => "\u{1F473}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WEARING_TURBAN_DARK_SKIN_TONE' => "\u{1F473}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_WITH_CHINESE_CAP' => "\u{1F472}", 'CHARACTER_MAN_WITH_CHINESE_CAP_LIGHT_SKIN_TONE' => "\u{1F472}\u{1F3FB}", 'CHARACTER_MAN_WITH_CHINESE_CAP_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F472}\u{1F3FC}", 'CHARACTER_MAN_WITH_CHINESE_CAP_MEDIUM_SKIN_TONE' => "\u{1F472}\u{1F3FD}", 'CHARACTER_MAN_WITH_CHINESE_CAP_MEDIUM_DARK_SKIN_TONE' => "\u{1F472}\u{1F3FE}", 'CHARACTER_MAN_WITH_CHINESE_CAP_DARK_SKIN_TONE' => "\u{1F472}\u{1F3FF}", 'CHARACTER_WOMAN_WITH_HEADSCARF' => "\u{1F9D5}", 'CHARACTER_WOMAN_WITH_HEADSCARF_LIGHT_SKIN_TONE' => "\u{1F9D5}\u{1F3FB}", 'CHARACTER_WOMAN_WITH_HEADSCARF_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D5}\u{1F3FC}", 'CHARACTER_WOMAN_WITH_HEADSCARF_MEDIUM_SKIN_TONE' => "\u{1F9D5}\u{1F3FD}", 'CHARACTER_WOMAN_WITH_HEADSCARF_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D5}\u{1F3FE}", 'CHARACTER_WOMAN_WITH_HEADSCARF_DARK_SKIN_TONE' => "\u{1F9D5}\u{1F3FF}", 'CHARACTER_BEARDED_PERSON' => "\u{1F9D4}", 'CHARACTER_BEARDED_PERSON_LIGHT_SKIN_TONE' => "\u{1F9D4}\u{1F3FB}", 'CHARACTER_BEARDED_PERSON_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D4}\u{1F3FC}", 'CHARACTER_BEARDED_PERSON_MEDIUM_SKIN_TONE' => "\u{1F9D4}\u{1F3FD}", 'CHARACTER_BEARDED_PERSON_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D4}\u{1F3FE}", 'CHARACTER_BEARDED_PERSON_DARK_SKIN_TONE' => "\u{1F9D4}\u{1F3FF}", 'CHARACTER_BLOND_HAIRED_PERSON' => "\u{1F471}", 'CHARACTER_BLOND_HAIRED_PERSON_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FB}", 'CHARACTER_BLOND_HAIRED_PERSON_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FC}", 'CHARACTER_BLOND_HAIRED_PERSON_MEDIUM_SKIN_TONE' => "\u{1F471}\u{1F3FD}", 'CHARACTER_BLOND_HAIRED_PERSON_MEDIUM_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FE}", 'CHARACTER_BLOND_HAIRED_PERSON_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FF}", 'CHARACTER_BLOND_HAIRED_MAN' => "\u{1F471}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_MAN_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_MAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_MAN_MEDIUM_SKIN_TONE' => "\u{1F471}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_MAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_MAN_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN' => "\u{1F471}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F471}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN_MEDIUM_SKIN_TONE' => "\u{1F471}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_BLOND_HAIRED_WOMAN_DARK_SKIN_TONE' => "\u{1F471}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_RED_HAIRED' => "\u{1F468}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_RED_HAIRED_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_RED_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_RED_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_RED_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_RED_HAIRED_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED' => "\u{1F469}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F9B0}", 'CHARACTER_WOMAN_RED_HAIRED_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F9B0}", 'CHARACTER_MAN_CURLY_HAIRED' => "\u{1F468}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_CURLY_HAIRED_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_CURLY_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_CURLY_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_CURLY_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_CURLY_HAIRED_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED' => "\u{1F469}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F9B1}", 'CHARACTER_WOMAN_CURLY_HAIRED_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F9B1}", 'CHARACTER_MAN_BALD' => "\u{1F468}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_BALD_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_BALD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_BALD_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_BALD_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_BALD_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD' => "\u{1F469}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F9B2}", 'CHARACTER_WOMAN_BALD_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F9B2}", 'CHARACTER_MAN_WHITE_HAIRED' => "\u{1F468}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_WHITE_HAIRED_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FB}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_WHITE_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F468}\u{1F3FC}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_WHITE_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F468}\u{1F3FD}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_WHITE_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FE}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_WHITE_HAIRED_DARK_SKIN_TONE' => "\u{1F468}\u{1F3FF}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED' => "\u{1F469}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FB}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F469}\u{1F3FC}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED_MEDIUM_SKIN_TONE' => "\u{1F469}\u{1F3FD}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED_MEDIUM_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FE}\u{200D}\u{1F9B3}", 'CHARACTER_WOMAN_WHITE_HAIRED_DARK_SKIN_TONE' => "\u{1F469}\u{1F3FF}\u{200D}\u{1F9B3}", 'CHARACTER_MAN_IN_TUXEDO' => "\u{1F935}", 'CHARACTER_MAN_IN_TUXEDO_LIGHT_SKIN_TONE' => "\u{1F935}\u{1F3FB}", 'CHARACTER_MAN_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F935}\u{1F3FC}", 'CHARACTER_MAN_IN_TUXEDO_MEDIUM_SKIN_TONE' => "\u{1F935}\u{1F3FD}", 'CHARACTER_MAN_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE' => "\u{1F935}\u{1F3FE}", 'CHARACTER_MAN_IN_TUXEDO_DARK_SKIN_TONE' => "\u{1F935}\u{1F3FF}", 'CHARACTER_BRIDE_WITH_VEIL' => "\u{1F470}", 'CHARACTER_BRIDE_WITH_VEIL_LIGHT_SKIN_TONE' => "\u{1F470}\u{1F3FB}", 'CHARACTER_BRIDE_WITH_VEIL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F470}\u{1F3FC}", 'CHARACTER_BRIDE_WITH_VEIL_MEDIUM_SKIN_TONE' => "\u{1F470}\u{1F3FD}", 'CHARACTER_BRIDE_WITH_VEIL_MEDIUM_DARK_SKIN_TONE' => "\u{1F470}\u{1F3FE}", 'CHARACTER_BRIDE_WITH_VEIL_DARK_SKIN_TONE' => "\u{1F470}\u{1F3FF}", 'CHARACTER_PREGNANT_WOMAN' => "\u{1F930}", 'CHARACTER_PREGNANT_WOMAN_LIGHT_SKIN_TONE' => "\u{1F930}\u{1F3FB}", 'CHARACTER_PREGNANT_WOMAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F930}\u{1F3FC}", 'CHARACTER_PREGNANT_WOMAN_MEDIUM_SKIN_TONE' => "\u{1F930}\u{1F3FD}", 'CHARACTER_PREGNANT_WOMAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F930}\u{1F3FE}", 'CHARACTER_PREGNANT_WOMAN_DARK_SKIN_TONE' => "\u{1F930}\u{1F3FF}", 'CHARACTER_BREAST_FEEDING' => "\u{1F931}", 'CHARACTER_BREAST_FEEDING_LIGHT_SKIN_TONE' => "\u{1F931}\u{1F3FB}", 'CHARACTER_BREAST_FEEDING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F931}\u{1F3FC}", 'CHARACTER_BREAST_FEEDING_MEDIUM_SKIN_TONE' => "\u{1F931}\u{1F3FD}", 'CHARACTER_BREAST_FEEDING_MEDIUM_DARK_SKIN_TONE' => "\u{1F931}\u{1F3FE}", 'CHARACTER_BREAST_FEEDING_DARK_SKIN_TONE' => "\u{1F931}\u{1F3FF}", 'CHARACTER_BABY_ANGEL' => "\u{1F47C}", 'CHARACTER_BABY_ANGEL_LIGHT_SKIN_TONE' => "\u{1F47C}\u{1F3FB}", 'CHARACTER_BABY_ANGEL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F47C}\u{1F3FC}", 'CHARACTER_BABY_ANGEL_MEDIUM_SKIN_TONE' => "\u{1F47C}\u{1F3FD}", 'CHARACTER_BABY_ANGEL_MEDIUM_DARK_SKIN_TONE' => "\u{1F47C}\u{1F3FE}", 'CHARACTER_BABY_ANGEL_DARK_SKIN_TONE' => "\u{1F47C}\u{1F3FF}", 'CHARACTER_SANTA_CLAUS' => "\u{1F385}", 'CHARACTER_SANTA_CLAUS_LIGHT_SKIN_TONE' => "\u{1F385}\u{1F3FB}", 'CHARACTER_SANTA_CLAUS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F385}\u{1F3FC}", 'CHARACTER_SANTA_CLAUS_MEDIUM_SKIN_TONE' => "\u{1F385}\u{1F3FD}", 'CHARACTER_SANTA_CLAUS_MEDIUM_DARK_SKIN_TONE' => "\u{1F385}\u{1F3FE}", 'CHARACTER_SANTA_CLAUS_DARK_SKIN_TONE' => "\u{1F385}\u{1F3FF}", 'CHARACTER_MRS_CLAUS' => "\u{1F936}", 'CHARACTER_MRS_CLAUS_LIGHT_SKIN_TONE' => "\u{1F936}\u{1F3FB}", 'CHARACTER_MRS_CLAUS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F936}\u{1F3FC}", 'CHARACTER_MRS_CLAUS_MEDIUM_SKIN_TONE' => "\u{1F936}\u{1F3FD}", 'CHARACTER_MRS_CLAUS_MEDIUM_DARK_SKIN_TONE' => "\u{1F936}\u{1F3FE}", 'CHARACTER_MRS_CLAUS_DARK_SKIN_TONE' => "\u{1F936}\u{1F3FF}", 'CHARACTER_SUPERHERO' => "\u{1F9B8}", 'CHARACTER_SUPERHERO_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FB}", 'CHARACTER_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FC}", 'CHARACTER_SUPERHERO_MEDIUM_SKIN_TONE' => "\u{1F9B8}\u{1F3FD}", 'CHARACTER_SUPERHERO_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FE}", 'CHARACTER_SUPERHERO_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FF}", 'CHARACTER_WOMAN_SUPERHERO' => "\u{1F9B8}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERHERO_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERHERO_MEDIUM_SKIN_TONE' => "\u{1F9B8}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERHERO_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO' => "\u{1F9B8}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B8}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO_MEDIUM_SKIN_TONE' => "\u{1F9B8}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERHERO_DARK_SKIN_TONE' => "\u{1F9B8}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_SUPERVILLAIN' => "\u{1F9B9}", 'CHARACTER_SUPERVILLAIN_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FB}", 'CHARACTER_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FC}", 'CHARACTER_SUPERVILLAIN_MEDIUM_SKIN_TONE' => "\u{1F9B9}\u{1F3FD}", 'CHARACTER_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FE}", 'CHARACTER_SUPERVILLAIN_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FF}", 'CHARACTER_WOMAN_SUPERVILLAIN' => "\u{1F9B9}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERVILLAIN_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERVILLAIN_MEDIUM_SKIN_TONE' => "\u{1F9B9}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SUPERVILLAIN_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN' => "\u{1F9B9}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B9}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN_MEDIUM_SKIN_TONE' => "\u{1F9B9}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SUPERVILLAIN_DARK_SKIN_TONE' => "\u{1F9B9}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAGE' => "\u{1F9D9}", 'CHARACTER_MAGE_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FB}", 'CHARACTER_MAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FC}", 'CHARACTER_MAGE_MEDIUM_SKIN_TONE' => "\u{1F9D9}\u{1F3FD}", 'CHARACTER_MAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FE}", 'CHARACTER_MAGE_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FF}", 'CHARACTER_WOMAN_MAGE' => "\u{1F9D9}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MAGE_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MAGE_MEDIUM_SKIN_TONE' => "\u{1F9D9}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MAGE_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_MAGE' => "\u{1F9D9}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MAGE_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D9}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MAGE_MEDIUM_SKIN_TONE' => "\u{1F9D9}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MAGE_DARK_SKIN_TONE' => "\u{1F9D9}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_FAIRY' => "\u{1F9DA}", 'CHARACTER_FAIRY_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FB}", 'CHARACTER_FAIRY_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FC}", 'CHARACTER_FAIRY_MEDIUM_SKIN_TONE' => "\u{1F9DA}\u{1F3FD}", 'CHARACTER_FAIRY_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FE}", 'CHARACTER_FAIRY_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FF}", 'CHARACTER_WOMAN_FAIRY' => "\u{1F9DA}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FAIRY_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FAIRY_MEDIUM_SKIN_TONE' => "\u{1F9DA}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FAIRY_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FAIRY_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_FAIRY' => "\u{1F9DA}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FAIRY_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DA}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FAIRY_MEDIUM_SKIN_TONE' => "\u{1F9DA}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FAIRY_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FAIRY_DARK_SKIN_TONE' => "\u{1F9DA}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_VAMPIRE' => "\u{1F9DB}", 'CHARACTER_VAMPIRE_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FB}", 'CHARACTER_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FC}", 'CHARACTER_VAMPIRE_MEDIUM_SKIN_TONE' => "\u{1F9DB}\u{1F3FD}", 'CHARACTER_VAMPIRE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FE}", 'CHARACTER_VAMPIRE_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FF}", 'CHARACTER_WOMAN_VAMPIRE' => "\u{1F9DB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_VAMPIRE_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_VAMPIRE_MEDIUM_SKIN_TONE' => "\u{1F9DB}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_VAMPIRE_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE' => "\u{1F9DB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DB}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE_MEDIUM_SKIN_TONE' => "\u{1F9DB}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_VAMPIRE_DARK_SKIN_TONE' => "\u{1F9DB}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERPERSON' => "\u{1F9DC}", 'CHARACTER_MERPERSON_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FB}", 'CHARACTER_MERPERSON_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FC}", 'CHARACTER_MERPERSON_MEDIUM_SKIN_TONE' => "\u{1F9DC}\u{1F3FD}", 'CHARACTER_MERPERSON_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FE}", 'CHARACTER_MERPERSON_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FF}", 'CHARACTER_MERMAID' => "\u{1F9DC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAID_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAID_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAID_MEDIUM_SKIN_TONE' => "\u{1F9DC}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAID_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAID_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MERMAN' => "\u{1F9DC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERMAN_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERMAN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DC}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERMAN_MEDIUM_SKIN_TONE' => "\u{1F9DC}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERMAN_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MERMAN_DARK_SKIN_TONE' => "\u{1F9DC}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_ELF' => "\u{1F9DD}", 'CHARACTER_ELF_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FB}", 'CHARACTER_ELF_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FC}", 'CHARACTER_ELF_MEDIUM_SKIN_TONE' => "\u{1F9DD}\u{1F3FD}", 'CHARACTER_ELF_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FE}", 'CHARACTER_ELF_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FF}", 'CHARACTER_WOMAN_ELF' => "\u{1F9DD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ELF_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ELF_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ELF_MEDIUM_SKIN_TONE' => "\u{1F9DD}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ELF_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ELF_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_ELF' => "\u{1F9DD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ELF_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ELF_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9DD}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ELF_MEDIUM_SKIN_TONE' => "\u{1F9DD}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ELF_MEDIUM_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ELF_DARK_SKIN_TONE' => "\u{1F9DD}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_GENIE' => "\u{1F9DE}", 'CHARACTER_WOMAN_GENIE' => "\u{1F9DE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_GENIE' => "\u{1F9DE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_ZOMBIE' => "\u{1F9DF}", 'CHARACTER_WOMAN_ZOMBIE' => "\u{1F9DF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_ZOMBIE' => "\u{1F9DF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_PERSON_FROWNING' => "\u{1F64D}", 'CHARACTER_PERSON_FROWNING_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FB}", 'CHARACTER_PERSON_FROWNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FC}", 'CHARACTER_PERSON_FROWNING_MEDIUM_SKIN_TONE' => "\u{1F64D}\u{1F3FD}", 'CHARACTER_PERSON_FROWNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FE}", 'CHARACTER_PERSON_FROWNING_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FF}", 'CHARACTER_MAN_FROWNING' => "\u{1F64D}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FROWNING_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FROWNING_MEDIUM_SKIN_TONE' => "\u{1F64D}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FROWNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FROWNING_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING' => "\u{1F64D}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64D}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING_MEDIUM_SKIN_TONE' => "\u{1F64D}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FROWNING_DARK_SKIN_TONE' => "\u{1F64D}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_POUTING' => "\u{1F64E}", 'CHARACTER_PERSON_POUTING_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FB}", 'CHARACTER_PERSON_POUTING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FC}", 'CHARACTER_PERSON_POUTING_MEDIUM_SKIN_TONE' => "\u{1F64E}\u{1F3FD}", 'CHARACTER_PERSON_POUTING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FE}", 'CHARACTER_PERSON_POUTING_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FF}", 'CHARACTER_MAN_POUTING' => "\u{1F64E}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POUTING_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POUTING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POUTING_MEDIUM_SKIN_TONE' => "\u{1F64E}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POUTING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_POUTING_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_POUTING' => "\u{1F64E}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POUTING_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POUTING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64E}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POUTING_MEDIUM_SKIN_TONE' => "\u{1F64E}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POUTING_MEDIUM_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_POUTING_DARK_SKIN_TONE' => "\u{1F64E}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_GESTURING_NO' => "\u{1F645}", 'CHARACTER_PERSON_GESTURING_NO_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FB}", 'CHARACTER_PERSON_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FC}", 'CHARACTER_PERSON_GESTURING_NO_MEDIUM_SKIN_TONE' => "\u{1F645}\u{1F3FD}", 'CHARACTER_PERSON_GESTURING_NO_MEDIUM_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FE}", 'CHARACTER_PERSON_GESTURING_NO_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FF}", 'CHARACTER_MAN_GESTURING_NO' => "\u{1F645}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_NO_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_NO_MEDIUM_SKIN_TONE' => "\u{1F645}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_NO_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO' => "\u{1F645}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F645}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO_MEDIUM_SKIN_TONE' => "\u{1F645}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_NO_DARK_SKIN_TONE' => "\u{1F645}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_GESTURING_OK' => "\u{1F646}", 'CHARACTER_PERSON_GESTURING_OK_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FB}", 'CHARACTER_PERSON_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FC}", 'CHARACTER_PERSON_GESTURING_OK_MEDIUM_SKIN_TONE' => "\u{1F646}\u{1F3FD}", 'CHARACTER_PERSON_GESTURING_OK_MEDIUM_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FE}", 'CHARACTER_PERSON_GESTURING_OK_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FF}", 'CHARACTER_MAN_GESTURING_OK' => "\u{1F646}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_OK_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_OK_MEDIUM_SKIN_TONE' => "\u{1F646}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GESTURING_OK_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK' => "\u{1F646}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F646}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK_MEDIUM_SKIN_TONE' => "\u{1F646}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GESTURING_OK_DARK_SKIN_TONE' => "\u{1F646}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_TIPPING_HAND' => "\u{1F481}", 'CHARACTER_PERSON_TIPPING_HAND_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FB}", 'CHARACTER_PERSON_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FC}", 'CHARACTER_PERSON_TIPPING_HAND_MEDIUM_SKIN_TONE' => "\u{1F481}\u{1F3FD}", 'CHARACTER_PERSON_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FE}", 'CHARACTER_PERSON_TIPPING_HAND_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FF}", 'CHARACTER_MAN_TIPPING_HAND' => "\u{1F481}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_TIPPING_HAND_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_TIPPING_HAND_MEDIUM_SKIN_TONE' => "\u{1F481}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_TIPPING_HAND_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND' => "\u{1F481}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F481}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND_MEDIUM_SKIN_TONE' => "\u{1F481}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_TIPPING_HAND_DARK_SKIN_TONE' => "\u{1F481}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_RAISING_HAND' => "\u{1F64B}", 'CHARACTER_PERSON_RAISING_HAND_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FB}", 'CHARACTER_PERSON_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FC}", 'CHARACTER_PERSON_RAISING_HAND_MEDIUM_SKIN_TONE' => "\u{1F64B}\u{1F3FD}", 'CHARACTER_PERSON_RAISING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FE}", 'CHARACTER_PERSON_RAISING_HAND_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FF}", 'CHARACTER_MAN_RAISING_HAND' => "\u{1F64B}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RAISING_HAND_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RAISING_HAND_MEDIUM_SKIN_TONE' => "\u{1F64B}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RAISING_HAND_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND' => "\u{1F64B}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64B}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND_MEDIUM_SKIN_TONE' => "\u{1F64B}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RAISING_HAND_DARK_SKIN_TONE' => "\u{1F64B}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_BOWING' => "\u{1F647}", 'CHARACTER_PERSON_BOWING_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FB}", 'CHARACTER_PERSON_BOWING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FC}", 'CHARACTER_PERSON_BOWING_MEDIUM_SKIN_TONE' => "\u{1F647}\u{1F3FD}", 'CHARACTER_PERSON_BOWING_MEDIUM_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FE}", 'CHARACTER_PERSON_BOWING_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FF}", 'CHARACTER_MAN_BOWING' => "\u{1F647}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOWING_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOWING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOWING_MEDIUM_SKIN_TONE' => "\u{1F647}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOWING_MEDIUM_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOWING_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_BOWING' => "\u{1F647}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOWING_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOWING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F647}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOWING_MEDIUM_SKIN_TONE' => "\u{1F647}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOWING_MEDIUM_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOWING_DARK_SKIN_TONE' => "\u{1F647}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_FACEPALMING' => "\u{1F926}", 'CHARACTER_PERSON_FACEPALMING_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FB}", 'CHARACTER_PERSON_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FC}", 'CHARACTER_PERSON_FACEPALMING_MEDIUM_SKIN_TONE' => "\u{1F926}\u{1F3FD}", 'CHARACTER_PERSON_FACEPALMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FE}", 'CHARACTER_PERSON_FACEPALMING_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FF}", 'CHARACTER_MAN_FACEPALMING' => "\u{1F926}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FACEPALMING_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FACEPALMING_MEDIUM_SKIN_TONE' => "\u{1F926}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_FACEPALMING_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING' => "\u{1F926}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F926}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING_MEDIUM_SKIN_TONE' => "\u{1F926}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_FACEPALMING_DARK_SKIN_TONE' => "\u{1F926}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_SHRUGGING' => "\u{1F937}", 'CHARACTER_PERSON_SHRUGGING_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FB}", 'CHARACTER_PERSON_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FC}", 'CHARACTER_PERSON_SHRUGGING_MEDIUM_SKIN_TONE' => "\u{1F937}\u{1F3FD}", 'CHARACTER_PERSON_SHRUGGING_MEDIUM_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FE}", 'CHARACTER_PERSON_SHRUGGING_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FF}", 'CHARACTER_MAN_SHRUGGING' => "\u{1F937}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SHRUGGING_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SHRUGGING_MEDIUM_SKIN_TONE' => "\u{1F937}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SHRUGGING_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING' => "\u{1F937}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F937}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING_MEDIUM_SKIN_TONE' => "\u{1F937}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SHRUGGING_DARK_SKIN_TONE' => "\u{1F937}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_GETTING_MASSAGE' => "\u{1F486}", 'CHARACTER_PERSON_GETTING_MASSAGE_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FB}", 'CHARACTER_PERSON_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FC}", 'CHARACTER_PERSON_GETTING_MASSAGE_MEDIUM_SKIN_TONE' => "\u{1F486}\u{1F3FD}", 'CHARACTER_PERSON_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FE}", 'CHARACTER_PERSON_GETTING_MASSAGE_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FF}", 'CHARACTER_MAN_GETTING_MASSAGE' => "\u{1F486}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_MASSAGE_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE' => "\u{1F486}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_MASSAGE_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE' => "\u{1F486}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F486}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE' => "\u{1F486}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_MASSAGE_DARK_SKIN_TONE' => "\u{1F486}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_GETTING_HAIRCUT' => "\u{1F487}", 'CHARACTER_PERSON_GETTING_HAIRCUT_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FB}", 'CHARACTER_PERSON_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FC}", 'CHARACTER_PERSON_GETTING_HAIRCUT_MEDIUM_SKIN_TONE' => "\u{1F487}\u{1F3FD}", 'CHARACTER_PERSON_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FE}", 'CHARACTER_PERSON_GETTING_HAIRCUT_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FF}", 'CHARACTER_MAN_GETTING_HAIRCUT' => "\u{1F487}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE' => "\u{1F487}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GETTING_HAIRCUT_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT' => "\u{1F487}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F487}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE' => "\u{1F487}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GETTING_HAIRCUT_DARK_SKIN_TONE' => "\u{1F487}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_WALKING' => "\u{1F6B6}", 'CHARACTER_PERSON_WALKING_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FB}", 'CHARACTER_PERSON_WALKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FC}", 'CHARACTER_PERSON_WALKING_MEDIUM_SKIN_TONE' => "\u{1F6B6}\u{1F3FD}", 'CHARACTER_PERSON_WALKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FE}", 'CHARACTER_PERSON_WALKING_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FF}", 'CHARACTER_MAN_WALKING' => "\u{1F6B6}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WALKING_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WALKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WALKING_MEDIUM_SKIN_TONE' => "\u{1F6B6}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WALKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_WALKING_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_WALKING' => "\u{1F6B6}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WALKING_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WALKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B6}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WALKING_MEDIUM_SKIN_TONE' => "\u{1F6B6}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WALKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_WALKING_DARK_SKIN_TONE' => "\u{1F6B6}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_RUNNING' => "\u{1F3C3}", 'CHARACTER_PERSON_RUNNING_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FB}", 'CHARACTER_PERSON_RUNNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FC}", 'CHARACTER_PERSON_RUNNING_MEDIUM_SKIN_TONE' => "\u{1F3C3}\u{1F3FD}", 'CHARACTER_PERSON_RUNNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FE}", 'CHARACTER_PERSON_RUNNING_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FF}", 'CHARACTER_MAN_RUNNING' => "\u{1F3C3}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RUNNING_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RUNNING_MEDIUM_SKIN_TONE' => "\u{1F3C3}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RUNNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_RUNNING_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING' => "\u{1F3C3}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C3}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING_MEDIUM_SKIN_TONE' => "\u{1F3C3}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_RUNNING_DARK_SKIN_TONE' => "\u{1F3C3}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_DANCING' => "\u{1F483}", 'CHARACTER_WOMAN_DANCING_LIGHT_SKIN_TONE' => "\u{1F483}\u{1F3FB}", 'CHARACTER_WOMAN_DANCING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F483}\u{1F3FC}", 'CHARACTER_WOMAN_DANCING_MEDIUM_SKIN_TONE' => "\u{1F483}\u{1F3FD}", 'CHARACTER_WOMAN_DANCING_MEDIUM_DARK_SKIN_TONE' => "\u{1F483}\u{1F3FE}", 'CHARACTER_WOMAN_DANCING_DARK_SKIN_TONE' => "\u{1F483}\u{1F3FF}", 'CHARACTER_MAN_DANCING' => "\u{1F57A}", 'CHARACTER_MAN_DANCING_LIGHT_SKIN_TONE' => "\u{1F57A}\u{1F3FB}", 'CHARACTER_MAN_DANCING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F57A}\u{1F3FC}", 'CHARACTER_MAN_DANCING_MEDIUM_SKIN_TONE' => "\u{1F57A}\u{1F3FD}", 'CHARACTER_MAN_DANCING_MEDIUM_DARK_SKIN_TONE' => "\u{1F57A}\u{1F3FE}", 'CHARACTER_MAN_DANCING_DARK_SKIN_TONE' => "\u{1F57A}\u{1F3FF}", 'CHARACTER_PEOPLE_WITH_BUNNY_EARS' => "\u{1F46F}", 'CHARACTER_MEN_WITH_BUNNY_EARS' => "\u{1F46F}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMEN_WITH_BUNNY_EARS' => "\u{1F46F}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_IN_STEAMY_ROOM' => "\u{1F9D6}", 'CHARACTER_PERSON_IN_STEAMY_ROOM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FB}", 'CHARACTER_PERSON_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FC}", 'CHARACTER_PERSON_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE' => "\u{1F9D6}\u{1F3FD}", 'CHARACTER_PERSON_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FE}", 'CHARACTER_PERSON_IN_STEAMY_ROOM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FF}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM' => "\u{1F9D6}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE' => "\u{1F9D6}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_STEAMY_ROOM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM' => "\u{1F9D6}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D6}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE' => "\u{1F9D6}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_STEAMY_ROOM_DARK_SKIN_TONE' => "\u{1F9D6}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_PERSON_CLIMBING' => "\u{1F9D7}", 'CHARACTER_PERSON_CLIMBING_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FB}", 'CHARACTER_PERSON_CLIMBING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FC}", 'CHARACTER_PERSON_CLIMBING_MEDIUM_SKIN_TONE' => "\u{1F9D7}\u{1F3FD}", 'CHARACTER_PERSON_CLIMBING_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FE}", 'CHARACTER_PERSON_CLIMBING_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FF}", 'CHARACTER_WOMAN_CLIMBING' => "\u{1F9D7}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CLIMBING_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CLIMBING_MEDIUM_SKIN_TONE' => "\u{1F9D7}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CLIMBING_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CLIMBING_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_CLIMBING' => "\u{1F9D7}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CLIMBING_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D7}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CLIMBING_MEDIUM_SKIN_TONE' => "\u{1F9D7}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CLIMBING_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CLIMBING_DARK_SKIN_TONE' => "\u{1F9D7}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_PERSON_IN_LOTUS_POSITION' => "\u{1F9D8}", 'CHARACTER_PERSON_IN_LOTUS_POSITION_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FB}", 'CHARACTER_PERSON_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FC}", 'CHARACTER_PERSON_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE' => "\u{1F9D8}\u{1F3FD}", 'CHARACTER_PERSON_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FE}", 'CHARACTER_PERSON_IN_LOTUS_POSITION_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FF}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION' => "\u{1F9D8}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE' => "\u{1F9D8}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_IN_LOTUS_POSITION_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION' => "\u{1F9D8}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9D8}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE' => "\u{1F9D8}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_IN_LOTUS_POSITION_DARK_SKIN_TONE' => "\u{1F9D8}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_PERSON_TAKING_BATH' => "\u{1F6C0}", 'CHARACTER_PERSON_TAKING_BATH_LIGHT_SKIN_TONE' => "\u{1F6C0}\u{1F3FB}", 'CHARACTER_PERSON_TAKING_BATH_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6C0}\u{1F3FC}", 'CHARACTER_PERSON_TAKING_BATH_MEDIUM_SKIN_TONE' => "\u{1F6C0}\u{1F3FD}", 'CHARACTER_PERSON_TAKING_BATH_MEDIUM_DARK_SKIN_TONE' => "\u{1F6C0}\u{1F3FE}", 'CHARACTER_PERSON_TAKING_BATH_DARK_SKIN_TONE' => "\u{1F6C0}\u{1F3FF}", 'CHARACTER_PERSON_IN_BED' => "\u{1F6CC}", 'CHARACTER_PERSON_IN_BED_LIGHT_SKIN_TONE' => "\u{1F6CC}\u{1F3FB}", 'CHARACTER_PERSON_IN_BED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6CC}\u{1F3FC}", 'CHARACTER_PERSON_IN_BED_MEDIUM_SKIN_TONE' => "\u{1F6CC}\u{1F3FD}", 'CHARACTER_PERSON_IN_BED_MEDIUM_DARK_SKIN_TONE' => "\u{1F6CC}\u{1F3FE}", 'CHARACTER_PERSON_IN_BED_DARK_SKIN_TONE' => "\u{1F6CC}\u{1F3FF}", 'CHARACTER_MAN_IN_SUIT_LEVITATING' => "\u{1F574}\u{FE0F}", 'CHARACTER_MAN_IN_SUIT_LEVITATING_LIGHT_SKIN_TONE' => "\u{1F574}\u{1F3FB}", 'CHARACTER_MAN_IN_SUIT_LEVITATING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F574}\u{1F3FC}", 'CHARACTER_MAN_IN_SUIT_LEVITATING_MEDIUM_SKIN_TONE' => "\u{1F574}\u{1F3FD}", 'CHARACTER_MAN_IN_SUIT_LEVITATING_MEDIUM_DARK_SKIN_TONE' => "\u{1F574}\u{1F3FE}", 'CHARACTER_MAN_IN_SUIT_LEVITATING_DARK_SKIN_TONE' => "\u{1F574}\u{1F3FF}", 'CHARACTER_SPEAKING_HEAD' => "\u{1F5E3}\u{FE0F}", 'CHARACTER_BUST_IN_SILHOUETTE' => "\u{1F464}", 'CHARACTER_BUSTS_IN_SILHOUETTE' => "\u{1F465}", 'CHARACTER_PERSON_FENCING' => "\u{1F93A}", 'CHARACTER_HORSE_RACING' => "\u{1F3C7}", 'CHARACTER_HORSE_RACING_LIGHT_SKIN_TONE' => "\u{1F3C7}\u{1F3FB}", 'CHARACTER_HORSE_RACING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C7}\u{1F3FC}", 'CHARACTER_HORSE_RACING_MEDIUM_SKIN_TONE' => "\u{1F3C7}\u{1F3FD}", 'CHARACTER_HORSE_RACING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C7}\u{1F3FE}", 'CHARACTER_HORSE_RACING_DARK_SKIN_TONE' => "\u{1F3C7}\u{1F3FF}", 'CHARACTER_SKIER' => "\u{26F7}\u{FE0F}", 'CHARACTER_SNOWBOARDER' => "\u{1F3C2}", 'CHARACTER_SNOWBOARDER_LIGHT_SKIN_TONE' => "\u{1F3C2}\u{1F3FB}", 'CHARACTER_SNOWBOARDER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C2}\u{1F3FC}", 'CHARACTER_SNOWBOARDER_MEDIUM_SKIN_TONE' => "\u{1F3C2}\u{1F3FD}", 'CHARACTER_SNOWBOARDER_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C2}\u{1F3FE}", 'CHARACTER_SNOWBOARDER_DARK_SKIN_TONE' => "\u{1F3C2}\u{1F3FF}", 'CHARACTER_PERSON_GOLFING' => "\u{1F3CC}\u{FE0F}", 'CHARACTER_PERSON_GOLFING_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FB}", 'CHARACTER_PERSON_GOLFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FC}", 'CHARACTER_PERSON_GOLFING_MEDIUM_SKIN_TONE' => "\u{1F3CC}\u{1F3FD}", 'CHARACTER_PERSON_GOLFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FE}", 'CHARACTER_PERSON_GOLFING_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FF}", 'CHARACTER_MAN_GOLFING' => "\u{1F3CC}\u{FE0F}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GOLFING_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GOLFING_MEDIUM_SKIN_TONE' => "\u{1F3CC}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GOLFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_GOLFING_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING' => "\u{1F3CC}\u{FE0F}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CC}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING_MEDIUM_SKIN_TONE' => "\u{1F3CC}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_GOLFING_DARK_SKIN_TONE' => "\u{1F3CC}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_SURFING' => "\u{1F3C4}", 'CHARACTER_PERSON_SURFING_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FB}", 'CHARACTER_PERSON_SURFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FC}", 'CHARACTER_PERSON_SURFING_MEDIUM_SKIN_TONE' => "\u{1F3C4}\u{1F3FD}", 'CHARACTER_PERSON_SURFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FE}", 'CHARACTER_PERSON_SURFING_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FF}", 'CHARACTER_MAN_SURFING' => "\u{1F3C4}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SURFING_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SURFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SURFING_MEDIUM_SKIN_TONE' => "\u{1F3C4}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SURFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SURFING_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_SURFING' => "\u{1F3C4}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SURFING_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SURFING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3C4}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SURFING_MEDIUM_SKIN_TONE' => "\u{1F3C4}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SURFING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SURFING_DARK_SKIN_TONE' => "\u{1F3C4}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_ROWING_BOAT' => "\u{1F6A3}", 'CHARACTER_PERSON_ROWING_BOAT_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FB}", 'CHARACTER_PERSON_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FC}", 'CHARACTER_PERSON_ROWING_BOAT_MEDIUM_SKIN_TONE' => "\u{1F6A3}\u{1F3FD}", 'CHARACTER_PERSON_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FE}", 'CHARACTER_PERSON_ROWING_BOAT_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FF}", 'CHARACTER_MAN_ROWING_BOAT' => "\u{1F6A3}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ROWING_BOAT_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ROWING_BOAT_MEDIUM_SKIN_TONE' => "\u{1F6A3}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_ROWING_BOAT_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT' => "\u{1F6A3}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6A3}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT_MEDIUM_SKIN_TONE' => "\u{1F6A3}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_ROWING_BOAT_DARK_SKIN_TONE' => "\u{1F6A3}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_SWIMMING' => "\u{1F3CA}", 'CHARACTER_PERSON_SWIMMING_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FB}", 'CHARACTER_PERSON_SWIMMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FC}", 'CHARACTER_PERSON_SWIMMING_MEDIUM_SKIN_TONE' => "\u{1F3CA}\u{1F3FD}", 'CHARACTER_PERSON_SWIMMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FE}", 'CHARACTER_PERSON_SWIMMING_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FF}", 'CHARACTER_MAN_SWIMMING' => "\u{1F3CA}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SWIMMING_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SWIMMING_MEDIUM_SKIN_TONE' => "\u{1F3CA}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SWIMMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_SWIMMING_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING' => "\u{1F3CA}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CA}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING_MEDIUM_SKIN_TONE' => "\u{1F3CA}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_SWIMMING_DARK_SKIN_TONE' => "\u{1F3CA}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_BOUNCING_BALL' => "\u{26F9}\u{FE0F}", 'CHARACTER_PERSON_BOUNCING_BALL_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FB}", 'CHARACTER_PERSON_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FC}", 'CHARACTER_PERSON_BOUNCING_BALL_MEDIUM_SKIN_TONE' => "\u{26F9}\u{1F3FD}", 'CHARACTER_PERSON_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FE}", 'CHARACTER_PERSON_BOUNCING_BALL_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FF}", 'CHARACTER_MAN_BOUNCING_BALL' => "\u{26F9}\u{FE0F}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOUNCING_BALL_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOUNCING_BALL_MEDIUM_SKIN_TONE' => "\u{26F9}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BOUNCING_BALL_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL' => "\u{26F9}\u{FE0F}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{26F9}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL_MEDIUM_SKIN_TONE' => "\u{26F9}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BOUNCING_BALL_DARK_SKIN_TONE' => "\u{26F9}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_LIFTING_WEIGHTS' => "\u{1F3CB}\u{FE0F}", 'CHARACTER_PERSON_LIFTING_WEIGHTS_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FB}", 'CHARACTER_PERSON_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FC}", 'CHARACTER_PERSON_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE' => "\u{1F3CB}\u{1F3FD}", 'CHARACTER_PERSON_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FE}", 'CHARACTER_PERSON_LIFTING_WEIGHTS_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FF}", 'CHARACTER_MAN_LIFTING_WEIGHTS' => "\u{1F3CB}\u{FE0F}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE' => "\u{1F3CB}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_LIFTING_WEIGHTS_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS' => "\u{1F3CB}\u{FE0F}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F3CB}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE' => "\u{1F3CB}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_LIFTING_WEIGHTS_DARK_SKIN_TONE' => "\u{1F3CB}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_BIKING' => "\u{1F6B4}", 'CHARACTER_PERSON_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FB}", 'CHARACTER_PERSON_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FC}", 'CHARACTER_PERSON_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B4}\u{1F3FD}", 'CHARACTER_PERSON_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FE}", 'CHARACTER_PERSON_BIKING_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FF}", 'CHARACTER_MAN_BIKING' => "\u{1F6B4}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B4}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_BIKING_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_BIKING' => "\u{1F6B4}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B4}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B4}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_BIKING_DARK_SKIN_TONE' => "\u{1F6B4}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_MOUNTAIN_BIKING' => "\u{1F6B5}", 'CHARACTER_PERSON_MOUNTAIN_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FB}", 'CHARACTER_PERSON_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FC}", 'CHARACTER_PERSON_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B5}\u{1F3FD}", 'CHARACTER_PERSON_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FE}", 'CHARACTER_PERSON_MOUNTAIN_BIKING_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FF}", 'CHARACTER_MAN_MOUNTAIN_BIKING' => "\u{1F6B5}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B5}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_MOUNTAIN_BIKING_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING' => "\u{1F6B5}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F6B5}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE' => "\u{1F6B5}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_MOUNTAIN_BIKING_DARK_SKIN_TONE' => "\u{1F6B5}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_RACING_CAR' => "\u{1F3CE}\u{FE0F}", 'CHARACTER_MOTORCYCLE' => "\u{1F3CD}\u{FE0F}", 'CHARACTER_PERSON_CARTWHEELING' => "\u{1F938}", 'CHARACTER_PERSON_CARTWHEELING_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FB}", 'CHARACTER_PERSON_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FC}", 'CHARACTER_PERSON_CARTWHEELING_MEDIUM_SKIN_TONE' => "\u{1F938}\u{1F3FD}", 'CHARACTER_PERSON_CARTWHEELING_MEDIUM_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FE}", 'CHARACTER_PERSON_CARTWHEELING_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FF}", 'CHARACTER_MAN_CARTWHEELING' => "\u{1F938}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CARTWHEELING_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CARTWHEELING_MEDIUM_SKIN_TONE' => "\u{1F938}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_CARTWHEELING_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING' => "\u{1F938}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F938}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING_MEDIUM_SKIN_TONE' => "\u{1F938}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_CARTWHEELING_DARK_SKIN_TONE' => "\u{1F938}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PEOPLE_WRESTLING' => "\u{1F93C}", 'CHARACTER_MEN_WRESTLING' => "\u{1F93C}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMEN_WRESTLING' => "\u{1F93C}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_PLAYING_WATER_POLO' => "\u{1F93D}", 'CHARACTER_PERSON_PLAYING_WATER_POLO_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FB}", 'CHARACTER_PERSON_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FC}", 'CHARACTER_PERSON_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE' => "\u{1F93D}\u{1F3FD}", 'CHARACTER_PERSON_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FE}", 'CHARACTER_PERSON_PLAYING_WATER_POLO_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FF}", 'CHARACTER_MAN_PLAYING_WATER_POLO' => "\u{1F93D}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE' => "\u{1F93D}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_WATER_POLO_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO' => "\u{1F93D}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93D}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE' => "\u{1F93D}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_WATER_POLO_DARK_SKIN_TONE' => "\u{1F93D}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_PLAYING_HANDBALL' => "\u{1F93E}", 'CHARACTER_PERSON_PLAYING_HANDBALL_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FB}", 'CHARACTER_PERSON_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FC}", 'CHARACTER_PERSON_PLAYING_HANDBALL_MEDIUM_SKIN_TONE' => "\u{1F93E}\u{1F3FD}", 'CHARACTER_PERSON_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FE}", 'CHARACTER_PERSON_PLAYING_HANDBALL_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FF}", 'CHARACTER_MAN_PLAYING_HANDBALL' => "\u{1F93E}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE' => "\u{1F93E}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_PLAYING_HANDBALL_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL' => "\u{1F93E}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F93E}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE' => "\u{1F93E}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_PLAYING_HANDBALL_DARK_SKIN_TONE' => "\u{1F93E}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_PERSON_JUGGLING' => "\u{1F939}", 'CHARACTER_PERSON_JUGGLING_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FB}", 'CHARACTER_PERSON_JUGGLING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FC}", 'CHARACTER_PERSON_JUGGLING_MEDIUM_SKIN_TONE' => "\u{1F939}\u{1F3FD}", 'CHARACTER_PERSON_JUGGLING_MEDIUM_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FE}", 'CHARACTER_PERSON_JUGGLING_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FF}", 'CHARACTER_MAN_JUGGLING' => "\u{1F939}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_JUGGLING_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FB}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FC}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_JUGGLING_MEDIUM_SKIN_TONE' => "\u{1F939}\u{1F3FD}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_JUGGLING_MEDIUM_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FE}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_MAN_JUGGLING_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FF}\u{200D}\u{2642}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING' => "\u{1F939}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FB}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F939}\u{1F3FC}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING_MEDIUM_SKIN_TONE' => "\u{1F939}\u{1F3FD}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING_MEDIUM_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FE}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_WOMAN_JUGGLING_DARK_SKIN_TONE' => "\u{1F939}\u{1F3FF}\u{200D}\u{2640}\u{FE0F}", 'CHARACTER_MAN_AND_WOMAN_HOLDING_HANDS' => "\u{1F46B}", 'CHARACTER_TWO_MEN_HOLDING_HANDS' => "\u{1F46C}", 'CHARACTER_TWO_WOMEN_HOLDING_HANDS' => "\u{1F46D}", 'CHARACTER_KISS' => "\u{1F48F}", 'CHARACTER_KISS_WOMAN_MAN' => "\u{1F469}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F48B}\u{200D}\u{1F468}", 'CHARACTER_KISS_MAN_MAN' => "\u{1F468}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F48B}\u{200D}\u{1F468}", 'CHARACTER_KISS_WOMAN_WOMAN' => "\u{1F469}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F48B}\u{200D}\u{1F469}", 'CHARACTER_COUPLE_WITH_HEART' => "\u{1F491}", 'CHARACTER_COUPLE_WITH_HEART_WOMAN_MAN' => "\u{1F469}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F468}", 'CHARACTER_COUPLE_WITH_HEART_MAN_MAN' => "\u{1F468}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F468}", 'CHARACTER_COUPLE_WITH_HEART_WOMAN_WOMAN' => "\u{1F469}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F469}", 'CHARACTER_FAMILY' => "\u{1F46A}", 'CHARACTER_FAMILY_MAN_WOMAN_BOY' => "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_WOMAN_GIRL' => "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_MAN_WOMAN_GIRL_BOY' => "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_WOMAN_BOY_BOY' => "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F466}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_WOMAN_GIRL_GIRL' => "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_MAN_MAN_BOY' => "\u{1F468}\u{200D}\u{1F468}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_MAN_GIRL' => "\u{1F468}\u{200D}\u{1F468}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_MAN_MAN_GIRL_BOY' => "\u{1F468}\u{200D}\u{1F468}\u{200D}\u{1F467}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_MAN_BOY_BOY' => "\u{1F468}\u{200D}\u{1F468}\u{200D}\u{1F466}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_MAN_GIRL_GIRL' => "\u{1F468}\u{200D}\u{1F468}\u{200D}\u{1F467}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_WOMAN_WOMAN_BOY' => "\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_WOMAN_GIRL' => "\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_WOMAN_WOMAN_GIRL_BOY' => "\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_WOMAN_BOY_BOY' => "\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F466}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_WOMAN_GIRL_GIRL' => "\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_MAN_BOY' => "\u{1F468}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_BOY_BOY' => "\u{1F468}\u{200D}\u{1F466}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_GIRL' => "\u{1F468}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_MAN_GIRL_BOY' => "\u{1F468}\u{200D}\u{1F467}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_MAN_GIRL_GIRL' => "\u{1F468}\u{200D}\u{1F467}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_WOMAN_BOY' => "\u{1F469}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_BOY_BOY' => "\u{1F469}\u{200D}\u{1F466}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_GIRL' => "\u{1F469}\u{200D}\u{1F467}", 'CHARACTER_FAMILY_WOMAN_GIRL_BOY' => "\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}", 'CHARACTER_FAMILY_WOMAN_GIRL_GIRL' => "\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F467}", 'CHARACTER_SELFIE' => "\u{1F933}", 'CHARACTER_SELFIE_LIGHT_SKIN_TONE' => "\u{1F933}\u{1F3FB}", 'CHARACTER_SELFIE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F933}\u{1F3FC}", 'CHARACTER_SELFIE_MEDIUM_SKIN_TONE' => "\u{1F933}\u{1F3FD}", 'CHARACTER_SELFIE_MEDIUM_DARK_SKIN_TONE' => "\u{1F933}\u{1F3FE}", 'CHARACTER_SELFIE_DARK_SKIN_TONE' => "\u{1F933}\u{1F3FF}", 'CHARACTER_FLEXED_BICEPS' => "\u{1F4AA}", 'CHARACTER_FLEXED_BICEPS_LIGHT_SKIN_TONE' => "\u{1F4AA}\u{1F3FB}", 'CHARACTER_FLEXED_BICEPS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F4AA}\u{1F3FC}", 'CHARACTER_FLEXED_BICEPS_MEDIUM_SKIN_TONE' => "\u{1F4AA}\u{1F3FD}", 'CHARACTER_FLEXED_BICEPS_MEDIUM_DARK_SKIN_TONE' => "\u{1F4AA}\u{1F3FE}", 'CHARACTER_FLEXED_BICEPS_DARK_SKIN_TONE' => "\u{1F4AA}\u{1F3FF}", 'CHARACTER_LEG' => "\u{1F9B5}", 'CHARACTER_LEG_LIGHT_SKIN_TONE' => "\u{1F9B5}\u{1F3FB}", 'CHARACTER_LEG_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B5}\u{1F3FC}", 'CHARACTER_LEG_MEDIUM_SKIN_TONE' => "\u{1F9B5}\u{1F3FD}", 'CHARACTER_LEG_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B5}\u{1F3FE}", 'CHARACTER_LEG_DARK_SKIN_TONE' => "\u{1F9B5}\u{1F3FF}", 'CHARACTER_FOOT' => "\u{1F9B6}", 'CHARACTER_FOOT_LIGHT_SKIN_TONE' => "\u{1F9B6}\u{1F3FB}", 'CHARACTER_FOOT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F9B6}\u{1F3FC}", 'CHARACTER_FOOT_MEDIUM_SKIN_TONE' => "\u{1F9B6}\u{1F3FD}", 'CHARACTER_FOOT_MEDIUM_DARK_SKIN_TONE' => "\u{1F9B6}\u{1F3FE}", 'CHARACTER_FOOT_DARK_SKIN_TONE' => "\u{1F9B6}\u{1F3FF}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT' => "\u{1F448}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT_LIGHT_SKIN_TONE' => "\u{1F448}\u{1F3FB}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F448}\u{1F3FC}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT_MEDIUM_SKIN_TONE' => "\u{1F448}\u{1F3FD}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT_MEDIUM_DARK_SKIN_TONE' => "\u{1F448}\u{1F3FE}", 'CHARACTER_BACKHAND_INDEX_POINTING_LEFT_DARK_SKIN_TONE' => "\u{1F448}\u{1F3FF}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT' => "\u{1F449}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT_LIGHT_SKIN_TONE' => "\u{1F449}\u{1F3FB}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F449}\u{1F3FC}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_SKIN_TONE' => "\u{1F449}\u{1F3FD}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_DARK_SKIN_TONE' => "\u{1F449}\u{1F3FE}", 'CHARACTER_BACKHAND_INDEX_POINTING_RIGHT_DARK_SKIN_TONE' => "\u{1F449}\u{1F3FF}", 'CHARACTER_INDEX_POINTING_UP' => "\u{261D}\u{FE0F}", 'CHARACTER_INDEX_POINTING_UP_LIGHT_SKIN_TONE' => "\u{261D}\u{1F3FB}", 'CHARACTER_INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE' => "\u{261D}\u{1F3FC}", 'CHARACTER_INDEX_POINTING_UP_MEDIUM_SKIN_TONE' => "\u{261D}\u{1F3FD}", 'CHARACTER_INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE' => "\u{261D}\u{1F3FE}", 'CHARACTER_INDEX_POINTING_UP_DARK_SKIN_TONE' => "\u{261D}\u{1F3FF}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP' => "\u{1F446}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP_LIGHT_SKIN_TONE' => "\u{1F446}\u{1F3FB}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F446}\u{1F3FC}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP_MEDIUM_SKIN_TONE' => "\u{1F446}\u{1F3FD}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE' => "\u{1F446}\u{1F3FE}", 'CHARACTER_BACKHAND_INDEX_POINTING_UP_DARK_SKIN_TONE' => "\u{1F446}\u{1F3FF}", 'CHARACTER_MIDDLE_FINGER' => "\u{1F595}", 'CHARACTER_MIDDLE_FINGER_LIGHT_SKIN_TONE' => "\u{1F595}\u{1F3FB}", 'CHARACTER_MIDDLE_FINGER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F595}\u{1F3FC}", 'CHARACTER_MIDDLE_FINGER_MEDIUM_SKIN_TONE' => "\u{1F595}\u{1F3FD}", 'CHARACTER_MIDDLE_FINGER_MEDIUM_DARK_SKIN_TONE' => "\u{1F595}\u{1F3FE}", 'CHARACTER_MIDDLE_FINGER_DARK_SKIN_TONE' => "\u{1F595}\u{1F3FF}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN' => "\u{1F447}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN_LIGHT_SKIN_TONE' => "\u{1F447}\u{1F3FB}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F447}\u{1F3FC}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN_MEDIUM_SKIN_TONE' => "\u{1F447}\u{1F3FD}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN_MEDIUM_DARK_SKIN_TONE' => "\u{1F447}\u{1F3FE}", 'CHARACTER_BACKHAND_INDEX_POINTING_DOWN_DARK_SKIN_TONE' => "\u{1F447}\u{1F3FF}", 'CHARACTER_VICTORY_HAND' => "\u{270C}\u{FE0F}", 'CHARACTER_VICTORY_HAND_LIGHT_SKIN_TONE' => "\u{270C}\u{1F3FB}", 'CHARACTER_VICTORY_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{270C}\u{1F3FC}", 'CHARACTER_VICTORY_HAND_MEDIUM_SKIN_TONE' => "\u{270C}\u{1F3FD}", 'CHARACTER_VICTORY_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{270C}\u{1F3FE}", 'CHARACTER_VICTORY_HAND_DARK_SKIN_TONE' => "\u{270C}\u{1F3FF}", 'CHARACTER_CROSSED_FINGERS' => "\u{1F91E}", 'CHARACTER_CROSSED_FINGERS_LIGHT_SKIN_TONE' => "\u{1F91E}\u{1F3FB}", 'CHARACTER_CROSSED_FINGERS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F91E}\u{1F3FC}", 'CHARACTER_CROSSED_FINGERS_MEDIUM_SKIN_TONE' => "\u{1F91E}\u{1F3FD}", 'CHARACTER_CROSSED_FINGERS_MEDIUM_DARK_SKIN_TONE' => "\u{1F91E}\u{1F3FE}", 'CHARACTER_CROSSED_FINGERS_DARK_SKIN_TONE' => "\u{1F91E}\u{1F3FF}", 'CHARACTER_VULCAN_SALUTE' => "\u{1F596}", 'CHARACTER_VULCAN_SALUTE_LIGHT_SKIN_TONE' => "\u{1F596}\u{1F3FB}", 'CHARACTER_VULCAN_SALUTE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F596}\u{1F3FC}", 'CHARACTER_VULCAN_SALUTE_MEDIUM_SKIN_TONE' => "\u{1F596}\u{1F3FD}", 'CHARACTER_VULCAN_SALUTE_MEDIUM_DARK_SKIN_TONE' => "\u{1F596}\u{1F3FE}", 'CHARACTER_VULCAN_SALUTE_DARK_SKIN_TONE' => "\u{1F596}\u{1F3FF}", 'CHARACTER_SIGN_OF_THE_HORNS' => "\u{1F918}", 'CHARACTER_SIGN_OF_THE_HORNS_LIGHT_SKIN_TONE' => "\u{1F918}\u{1F3FB}", 'CHARACTER_SIGN_OF_THE_HORNS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F918}\u{1F3FC}", 'CHARACTER_SIGN_OF_THE_HORNS_MEDIUM_SKIN_TONE' => "\u{1F918}\u{1F3FD}", 'CHARACTER_SIGN_OF_THE_HORNS_MEDIUM_DARK_SKIN_TONE' => "\u{1F918}\u{1F3FE}", 'CHARACTER_SIGN_OF_THE_HORNS_DARK_SKIN_TONE' => "\u{1F918}\u{1F3FF}", 'CHARACTER_CALL_ME_HAND' => "\u{1F919}", 'CHARACTER_CALL_ME_HAND_LIGHT_SKIN_TONE' => "\u{1F919}\u{1F3FB}", 'CHARACTER_CALL_ME_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F919}\u{1F3FC}", 'CHARACTER_CALL_ME_HAND_MEDIUM_SKIN_TONE' => "\u{1F919}\u{1F3FD}", 'CHARACTER_CALL_ME_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F919}\u{1F3FE}", 'CHARACTER_CALL_ME_HAND_DARK_SKIN_TONE' => "\u{1F919}\u{1F3FF}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED' => "\u{1F590}\u{FE0F}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED_LIGHT_SKIN_TONE' => "\u{1F590}\u{1F3FB}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F590}\u{1F3FC}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED_MEDIUM_SKIN_TONE' => "\u{1F590}\u{1F3FD}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED_MEDIUM_DARK_SKIN_TONE' => "\u{1F590}\u{1F3FE}", 'CHARACTER_HAND_WITH_FINGERS_SPLAYED_DARK_SKIN_TONE' => "\u{1F590}\u{1F3FF}", 'CHARACTER_RAISED_HAND' => "\u{270B}", 'CHARACTER_RAISED_HAND_LIGHT_SKIN_TONE' => "\u{270B}\u{1F3FB}", 'CHARACTER_RAISED_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{270B}\u{1F3FC}", 'CHARACTER_RAISED_HAND_MEDIUM_SKIN_TONE' => "\u{270B}\u{1F3FD}", 'CHARACTER_RAISED_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{270B}\u{1F3FE}", 'CHARACTER_RAISED_HAND_DARK_SKIN_TONE' => "\u{270B}\u{1F3FF}", 'CHARACTER_OK_HAND' => "\u{1F44C}", 'CHARACTER_OK_HAND_LIGHT_SKIN_TONE' => "\u{1F44C}\u{1F3FB}", 'CHARACTER_OK_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44C}\u{1F3FC}", 'CHARACTER_OK_HAND_MEDIUM_SKIN_TONE' => "\u{1F44C}\u{1F3FD}", 'CHARACTER_OK_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F44C}\u{1F3FE}", 'CHARACTER_OK_HAND_DARK_SKIN_TONE' => "\u{1F44C}\u{1F3FF}", 'CHARACTER_THUMBS_UP' => "\u{1F44D}", 'CHARACTER_THUMBS_UP_LIGHT_SKIN_TONE' => "\u{1F44D}\u{1F3FB}", 'CHARACTER_THUMBS_UP_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44D}\u{1F3FC}", 'CHARACTER_THUMBS_UP_MEDIUM_SKIN_TONE' => "\u{1F44D}\u{1F3FD}", 'CHARACTER_THUMBS_UP_MEDIUM_DARK_SKIN_TONE' => "\u{1F44D}\u{1F3FE}", 'CHARACTER_THUMBS_UP_DARK_SKIN_TONE' => "\u{1F44D}\u{1F3FF}", 'CHARACTER_THUMBS_DOWN' => "\u{1F44E}", 'CHARACTER_THUMBS_DOWN_LIGHT_SKIN_TONE' => "\u{1F44E}\u{1F3FB}", 'CHARACTER_THUMBS_DOWN_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44E}\u{1F3FC}", 'CHARACTER_THUMBS_DOWN_MEDIUM_SKIN_TONE' => "\u{1F44E}\u{1F3FD}", 'CHARACTER_THUMBS_DOWN_MEDIUM_DARK_SKIN_TONE' => "\u{1F44E}\u{1F3FE}", 'CHARACTER_THUMBS_DOWN_DARK_SKIN_TONE' => "\u{1F44E}\u{1F3FF}", 'CHARACTER_RAISED_FIST' => "\u{270A}", 'CHARACTER_RAISED_FIST_LIGHT_SKIN_TONE' => "\u{270A}\u{1F3FB}", 'CHARACTER_RAISED_FIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{270A}\u{1F3FC}", 'CHARACTER_RAISED_FIST_MEDIUM_SKIN_TONE' => "\u{270A}\u{1F3FD}", 'CHARACTER_RAISED_FIST_MEDIUM_DARK_SKIN_TONE' => "\u{270A}\u{1F3FE}", 'CHARACTER_RAISED_FIST_DARK_SKIN_TONE' => "\u{270A}\u{1F3FF}", 'CHARACTER_ONCOMING_FIST' => "\u{1F44A}", 'CHARACTER_ONCOMING_FIST_LIGHT_SKIN_TONE' => "\u{1F44A}\u{1F3FB}", 'CHARACTER_ONCOMING_FIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44A}\u{1F3FC}", 'CHARACTER_ONCOMING_FIST_MEDIUM_SKIN_TONE' => "\u{1F44A}\u{1F3FD}", 'CHARACTER_ONCOMING_FIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F44A}\u{1F3FE}", 'CHARACTER_ONCOMING_FIST_DARK_SKIN_TONE' => "\u{1F44A}\u{1F3FF}", 'CHARACTER_LEFT_FACING_FIST' => "\u{1F91B}", 'CHARACTER_LEFT_FACING_FIST_LIGHT_SKIN_TONE' => "\u{1F91B}\u{1F3FB}", 'CHARACTER_LEFT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F91B}\u{1F3FC}", 'CHARACTER_LEFT_FACING_FIST_MEDIUM_SKIN_TONE' => "\u{1F91B}\u{1F3FD}", 'CHARACTER_LEFT_FACING_FIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F91B}\u{1F3FE}", 'CHARACTER_LEFT_FACING_FIST_DARK_SKIN_TONE' => "\u{1F91B}\u{1F3FF}", 'CHARACTER_RIGHT_FACING_FIST' => "\u{1F91C}", 'CHARACTER_RIGHT_FACING_FIST_LIGHT_SKIN_TONE' => "\u{1F91C}\u{1F3FB}", 'CHARACTER_RIGHT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F91C}\u{1F3FC}", 'CHARACTER_RIGHT_FACING_FIST_MEDIUM_SKIN_TONE' => "\u{1F91C}\u{1F3FD}", 'CHARACTER_RIGHT_FACING_FIST_MEDIUM_DARK_SKIN_TONE' => "\u{1F91C}\u{1F3FE}", 'CHARACTER_RIGHT_FACING_FIST_DARK_SKIN_TONE' => "\u{1F91C}\u{1F3FF}", 'CHARACTER_RAISED_BACK_OF_HAND' => "\u{1F91A}", 'CHARACTER_RAISED_BACK_OF_HAND_LIGHT_SKIN_TONE' => "\u{1F91A}\u{1F3FB}", 'CHARACTER_RAISED_BACK_OF_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F91A}\u{1F3FC}", 'CHARACTER_RAISED_BACK_OF_HAND_MEDIUM_SKIN_TONE' => "\u{1F91A}\u{1F3FD}", 'CHARACTER_RAISED_BACK_OF_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F91A}\u{1F3FE}", 'CHARACTER_RAISED_BACK_OF_HAND_DARK_SKIN_TONE' => "\u{1F91A}\u{1F3FF}", 'CHARACTER_WAVING_HAND' => "\u{1F44B}", 'CHARACTER_WAVING_HAND_LIGHT_SKIN_TONE' => "\u{1F44B}\u{1F3FB}", 'CHARACTER_WAVING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44B}\u{1F3FC}", 'CHARACTER_WAVING_HAND_MEDIUM_SKIN_TONE' => "\u{1F44B}\u{1F3FD}", 'CHARACTER_WAVING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{1F44B}\u{1F3FE}", 'CHARACTER_WAVING_HAND_DARK_SKIN_TONE' => "\u{1F44B}\u{1F3FF}", 'CHARACTER_LOVE_YOU_GESTURE' => "\u{1F91F}", 'CHARACTER_LOVE_YOU_GESTURE_LIGHT_SKIN_TONE' => "\u{1F91F}\u{1F3FB}", 'CHARACTER_LOVE_YOU_GESTURE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F91F}\u{1F3FC}", 'CHARACTER_LOVE_YOU_GESTURE_MEDIUM_SKIN_TONE' => "\u{1F91F}\u{1F3FD}", 'CHARACTER_LOVE_YOU_GESTURE_MEDIUM_DARK_SKIN_TONE' => "\u{1F91F}\u{1F3FE}", 'CHARACTER_LOVE_YOU_GESTURE_DARK_SKIN_TONE' => "\u{1F91F}\u{1F3FF}", 'CHARACTER_WRITING_HAND' => "\u{270D}\u{FE0F}", 'CHARACTER_WRITING_HAND_LIGHT_SKIN_TONE' => "\u{270D}\u{1F3FB}", 'CHARACTER_WRITING_HAND_MEDIUM_LIGHT_SKIN_TONE' => "\u{270D}\u{1F3FC}", 'CHARACTER_WRITING_HAND_MEDIUM_SKIN_TONE' => "\u{270D}\u{1F3FD}", 'CHARACTER_WRITING_HAND_MEDIUM_DARK_SKIN_TONE' => "\u{270D}\u{1F3FE}", 'CHARACTER_WRITING_HAND_DARK_SKIN_TONE' => "\u{270D}\u{1F3FF}", 'CHARACTER_CLAPPING_HANDS' => "\u{1F44F}", 'CHARACTER_CLAPPING_HANDS_LIGHT_SKIN_TONE' => "\u{1F44F}\u{1F3FB}", 'CHARACTER_CLAPPING_HANDS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F44F}\u{1F3FC}", 'CHARACTER_CLAPPING_HANDS_MEDIUM_SKIN_TONE' => "\u{1F44F}\u{1F3FD}", 'CHARACTER_CLAPPING_HANDS_MEDIUM_DARK_SKIN_TONE' => "\u{1F44F}\u{1F3FE}", 'CHARACTER_CLAPPING_HANDS_DARK_SKIN_TONE' => "\u{1F44F}\u{1F3FF}", 'CHARACTER_OPEN_HANDS' => "\u{1F450}", 'CHARACTER_OPEN_HANDS_LIGHT_SKIN_TONE' => "\u{1F450}\u{1F3FB}", 'CHARACTER_OPEN_HANDS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F450}\u{1F3FC}", 'CHARACTER_OPEN_HANDS_MEDIUM_SKIN_TONE' => "\u{1F450}\u{1F3FD}", 'CHARACTER_OPEN_HANDS_MEDIUM_DARK_SKIN_TONE' => "\u{1F450}\u{1F3FE}", 'CHARACTER_OPEN_HANDS_DARK_SKIN_TONE' => "\u{1F450}\u{1F3FF}", 'CHARACTER_RAISING_HANDS' => "\u{1F64C}", 'CHARACTER_RAISING_HANDS_LIGHT_SKIN_TONE' => "\u{1F64C}\u{1F3FB}", 'CHARACTER_RAISING_HANDS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64C}\u{1F3FC}", 'CHARACTER_RAISING_HANDS_MEDIUM_SKIN_TONE' => "\u{1F64C}\u{1F3FD}", 'CHARACTER_RAISING_HANDS_MEDIUM_DARK_SKIN_TONE' => "\u{1F64C}\u{1F3FE}", 'CHARACTER_RAISING_HANDS_DARK_SKIN_TONE' => "\u{1F64C}\u{1F3FF}", 'CHARACTER_PALMS_UP_TOGETHER' => "\u{1F932}", 'CHARACTER_PALMS_UP_TOGETHER_LIGHT_SKIN_TONE' => "\u{1F932}\u{1F3FB}", 'CHARACTER_PALMS_UP_TOGETHER_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F932}\u{1F3FC}", 'CHARACTER_PALMS_UP_TOGETHER_MEDIUM_SKIN_TONE' => "\u{1F932}\u{1F3FD}", 'CHARACTER_PALMS_UP_TOGETHER_MEDIUM_DARK_SKIN_TONE' => "\u{1F932}\u{1F3FE}", 'CHARACTER_PALMS_UP_TOGETHER_DARK_SKIN_TONE' => "\u{1F932}\u{1F3FF}", 'CHARACTER_FOLDED_HANDS' => "\u{1F64F}", 'CHARACTER_FOLDED_HANDS_LIGHT_SKIN_TONE' => "\u{1F64F}\u{1F3FB}", 'CHARACTER_FOLDED_HANDS_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F64F}\u{1F3FC}", 'CHARACTER_FOLDED_HANDS_MEDIUM_SKIN_TONE' => "\u{1F64F}\u{1F3FD}", 'CHARACTER_FOLDED_HANDS_MEDIUM_DARK_SKIN_TONE' => "\u{1F64F}\u{1F3FE}", 'CHARACTER_FOLDED_HANDS_DARK_SKIN_TONE' => "\u{1F64F}\u{1F3FF}", 'CHARACTER_HANDSHAKE' => "\u{1F91D}", 'CHARACTER_NAIL_POLISH' => "\u{1F485}", 'CHARACTER_NAIL_POLISH_LIGHT_SKIN_TONE' => "\u{1F485}\u{1F3FB}", 'CHARACTER_NAIL_POLISH_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F485}\u{1F3FC}", 'CHARACTER_NAIL_POLISH_MEDIUM_SKIN_TONE' => "\u{1F485}\u{1F3FD}", 'CHARACTER_NAIL_POLISH_MEDIUM_DARK_SKIN_TONE' => "\u{1F485}\u{1F3FE}", 'CHARACTER_NAIL_POLISH_DARK_SKIN_TONE' => "\u{1F485}\u{1F3FF}", 'CHARACTER_EAR' => "\u{1F442}", 'CHARACTER_EAR_LIGHT_SKIN_TONE' => "\u{1F442}\u{1F3FB}", 'CHARACTER_EAR_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F442}\u{1F3FC}", 'CHARACTER_EAR_MEDIUM_SKIN_TONE' => "\u{1F442}\u{1F3FD}", 'CHARACTER_EAR_MEDIUM_DARK_SKIN_TONE' => "\u{1F442}\u{1F3FE}", 'CHARACTER_EAR_DARK_SKIN_TONE' => "\u{1F442}\u{1F3FF}", 'CHARACTER_NOSE' => "\u{1F443}", 'CHARACTER_NOSE_LIGHT_SKIN_TONE' => "\u{1F443}\u{1F3FB}", 'CHARACTER_NOSE_MEDIUM_LIGHT_SKIN_TONE' => "\u{1F443}\u{1F3FC}", 'CHARACTER_NOSE_MEDIUM_SKIN_TONE' => "\u{1F443}\u{1F3FD}", 'CHARACTER_NOSE_MEDIUM_DARK_SKIN_TONE' => "\u{1F443}\u{1F3FE}", 'CHARACTER_NOSE_DARK_SKIN_TONE' => "\u{1F443}\u{1F3FF}", 'CHARACTER_RED_HAIRED' => "\u{1F9B0}", 'CHARACTER_CURLY_HAIRED' => "\u{1F9B1}", 'CHARACTER_BALD' => "\u{1F9B2}", 'CHARACTER_WHITE_HAIRED' => "\u{1F9B3}", 'CHARACTER_FOOTPRINTS' => "\u{1F463}", 'CHARACTER_EYES' => "\u{1F440}", 'CHARACTER_EYE' => "\u{1F441}\u{FE0F}", 'CHARACTER_EYE_IN_SPEECH_BUBBLE' => "\u{1F441}\u{FE0F}\u{200D}\u{1F5E8}\u{FE0F}", 'CHARACTER_BRAIN' => "\u{1F9E0}", 'CHARACTER_BONE' => "\u{1F9B4}", 'CHARACTER_TOOTH' => "\u{1F9B7}", 'CHARACTER_TONGUE' => "\u{1F445}", 'CHARACTER_MOUTH' => "\u{1F444}", 'CHARACTER_KISS_MARK' => "\u{1F48B}", 'CHARACTER_HEART_WITH_ARROW' => "\u{1F498}", 'CHARACTER_RED_HEART' => "\u{2764}\u{FE0F}", 'CHARACTER_BEATING_HEART' => "\u{1F493}", 'CHARACTER_BROKEN_HEART' => "\u{1F494}", 'CHARACTER_TWO_HEARTS' => "\u{1F495}", 'CHARACTER_SPARKLING_HEART' => "\u{1F496}", 'CHARACTER_GROWING_HEART' => "\u{1F497}", 'CHARACTER_BLUE_HEART' => "\u{1F499}", 'CHARACTER_GREEN_HEART' => "\u{1F49A}", 'CHARACTER_YELLOW_HEART' => "\u{1F49B}", 'CHARACTER_ORANGE_HEART' => "\u{1F9E1}", 'CHARACTER_PURPLE_HEART' => "\u{1F49C}", 'CHARACTER_BLACK_HEART' => "\u{1F5A4}", 'CHARACTER_HEART_WITH_RIBBON' => "\u{1F49D}", 'CHARACTER_REVOLVING_HEARTS' => "\u{1F49E}", 'CHARACTER_HEART_DECORATION' => "\u{1F49F}", 'CHARACTER_HEAVY_HEART_EXCLAMATION' => "\u{2763}\u{FE0F}", 'CHARACTER_LOVE_LETTER' => "\u{1F48C}", 'CHARACTER_ZZZ' => "\u{1F4A4}", 'CHARACTER_ANGER_SYMBOL' => "\u{1F4A2}", 'CHARACTER_BOMB' => "\u{1F4A3}", 'CHARACTER_COLLISION' => "\u{1F4A5}", 'CHARACTER_SWEAT_DROPLETS' => "\u{1F4A6}", 'CHARACTER_DASHING_AWAY' => "\u{1F4A8}", 'CHARACTER_DIZZY' => "\u{1F4AB}", 'CHARACTER_SPEECH_BALLOON' => "\u{1F4AC}", 'CHARACTER_LEFT_SPEECH_BUBBLE' => "\u{1F5E8}\u{FE0F}", 'CHARACTER_RIGHT_ANGER_BUBBLE' => "\u{1F5EF}\u{FE0F}", 'CHARACTER_THOUGHT_BALLOON' => "\u{1F4AD}", 'CHARACTER_HOLE' => "\u{1F573}\u{FE0F}", 'CHARACTER_GLASSES' => "\u{1F453}", 'CHARACTER_SUNGLASSES' => "\u{1F576}\u{FE0F}", 'CHARACTER_GOGGLES' => "\u{1F97D}", 'CHARACTER_LAB_COAT' => "\u{1F97C}", 'CHARACTER_NECKTIE' => "\u{1F454}", 'CHARACTER_T_SHIRT' => "\u{1F455}", 'CHARACTER_JEANS' => "\u{1F456}", 'CHARACTER_SCARF' => "\u{1F9E3}", 'CHARACTER_GLOVES' => "\u{1F9E4}", 'CHARACTER_COAT' => "\u{1F9E5}", 'CHARACTER_SOCKS' => "\u{1F9E6}", 'CHARACTER_DRESS' => "\u{1F457}", 'CHARACTER_KIMONO' => "\u{1F458}", 'CHARACTER_BIKINI' => "\u{1F459}", 'CHARACTER_WOMAN_S_CLOTHES' => "\u{1F45A}", 'CHARACTER_PURSE' => "\u{1F45B}", 'CHARACTER_HANDBAG' => "\u{1F45C}", 'CHARACTER_CLUTCH_BAG' => "\u{1F45D}", 'CHARACTER_SHOPPING_BAGS' => "\u{1F6CD}\u{FE0F}", 'CHARACTER_SCHOOL_BACKPACK' => "\u{1F392}", 'CHARACTER_MAN_S_SHOE' => "\u{1F45E}", 'CHARACTER_RUNNING_SHOE' => "\u{1F45F}", 'CHARACTER_HIKING_BOOT' => "\u{1F97E}", 'CHARACTER_WOMAN_S_FLAT_SHOE' => "\u{1F97F}", 'CHARACTER_HIGH_HEELED_SHOE' => "\u{1F460}", 'CHARACTER_WOMAN_S_SANDAL' => "\u{1F461}", 'CHARACTER_WOMAN_S_BOOT' => "\u{1F462}", 'CHARACTER_CROWN' => "\u{1F451}", 'CHARACTER_WOMAN_S_HAT' => "\u{1F452}", 'CHARACTER_TOP_HAT' => "\u{1F3A9}", 'CHARACTER_GRADUATION_CAP' => "\u{1F393}", 'CHARACTER_BILLED_CAP' => "\u{1F9E2}", 'CHARACTER_RESCUE_WORKER_S_HELMET' => "\u{26D1}\u{FE0F}", 'CHARACTER_PRAYER_BEADS' => "\u{1F4FF}", 'CHARACTER_LIPSTICK' => "\u{1F484}", 'CHARACTER_RING' => "\u{1F48D}", 'CHARACTER_GEM_STONE' => "\u{1F48E}", 'CHARACTER_MONKEY_FACE' => "\u{1F435}", 'CHARACTER_MONKEY' => "\u{1F412}", 'CHARACTER_GORILLA' => "\u{1F98D}", 'CHARACTER_DOG_FACE' => "\u{1F436}", 'CHARACTER_DOG' => "\u{1F415}", 'CHARACTER_POODLE' => "\u{1F429}", 'CHARACTER_WOLF_FACE' => "\u{1F43A}", 'CHARACTER_FOX_FACE' => "\u{1F98A}", 'CHARACTER_RACCOON' => "\u{1F99D}", 'CHARACTER_CAT_FACE' => "\u{1F431}", 'CHARACTER_CAT' => "\u{1F408}", 'CHARACTER_LION_FACE' => "\u{1F981}", 'CHARACTER_TIGER_FACE' => "\u{1F42F}", 'CHARACTER_TIGER' => "\u{1F405}", 'CHARACTER_LEOPARD' => "\u{1F406}", 'CHARACTER_HORSE_FACE' => "\u{1F434}", 'CHARACTER_HORSE' => "\u{1F40E}", 'CHARACTER_UNICORN_FACE' => "\u{1F984}", 'CHARACTER_ZEBRA' => "\u{1F993}", 'CHARACTER_DEER' => "\u{1F98C}", 'CHARACTER_COW_FACE' => "\u{1F42E}", 'CHARACTER_OX' => "\u{1F402}", 'CHARACTER_WATER_BUFFALO' => "\u{1F403}", 'CHARACTER_COW' => "\u{1F404}", 'CHARACTER_PIG_FACE' => "\u{1F437}", 'CHARACTER_PIG' => "\u{1F416}", 'CHARACTER_BOAR' => "\u{1F417}", 'CHARACTER_PIG_NOSE' => "\u{1F43D}", 'CHARACTER_RAM' => "\u{1F40F}", 'CHARACTER_EWE' => "\u{1F411}", 'CHARACTER_GOAT' => "\u{1F410}", 'CHARACTER_CAMEL' => "\u{1F42A}", 'CHARACTER_TWO_HUMP_CAMEL' => "\u{1F42B}", 'CHARACTER_LLAMA' => "\u{1F999}", 'CHARACTER_GIRAFFE' => "\u{1F992}", 'CHARACTER_ELEPHANT' => "\u{1F418}", 'CHARACTER_RHINOCEROS' => "\u{1F98F}", 'CHARACTER_HIPPOPOTAMUS' => "\u{1F99B}", 'CHARACTER_MOUSE_FACE' => "\u{1F42D}", 'CHARACTER_MOUSE' => "\u{1F401}", 'CHARACTER_RAT' => "\u{1F400}", 'CHARACTER_HAMSTER_FACE' => "\u{1F439}", 'CHARACTER_RABBIT_FACE' => "\u{1F430}", 'CHARACTER_RABBIT' => "\u{1F407}", 'CHARACTER_CHIPMUNK' => "\u{1F43F}\u{FE0F}", 'CHARACTER_HEDGEHOG' => "\u{1F994}", 'CHARACTER_BAT' => "\u{1F987}", 'CHARACTER_BEAR_FACE' => "\u{1F43B}", 'CHARACTER_KOALA' => "\u{1F428}", 'CHARACTER_PANDA_FACE' => "\u{1F43C}", 'CHARACTER_KANGAROO' => "\u{1F998}", 'CHARACTER_BADGER' => "\u{1F9A1}", 'CHARACTER_PAW_PRINTS' => "\u{1F43E}", 'CHARACTER_TURKEY' => "\u{1F983}", 'CHARACTER_CHICKEN' => "\u{1F414}", 'CHARACTER_ROOSTER' => "\u{1F413}", 'CHARACTER_HATCHING_CHICK' => "\u{1F423}", 'CHARACTER_BABY_CHICK' => "\u{1F424}", 'CHARACTER_FRONT_FACING_BABY_CHICK' => "\u{1F425}", 'CHARACTER_BIRD' => "\u{1F426}", 'CHARACTER_PENGUIN' => "\u{1F427}", 'CHARACTER_DOVE' => "\u{1F54A}\u{FE0F}", 'CHARACTER_EAGLE' => "\u{1F985}", 'CHARACTER_DUCK' => "\u{1F986}", 'CHARACTER_SWAN' => "\u{1F9A2}", 'CHARACTER_OWL' => "\u{1F989}", 'CHARACTER_PEACOCK' => "\u{1F99A}", 'CHARACTER_PARROT' => "\u{1F99C}", 'CHARACTER_FROG_FACE' => "\u{1F438}", 'CHARACTER_CROCODILE' => "\u{1F40A}", 'CHARACTER_TURTLE' => "\u{1F422}", 'CHARACTER_LIZARD' => "\u{1F98E}", 'CHARACTER_SNAKE' => "\u{1F40D}", 'CHARACTER_DRAGON_FACE' => "\u{1F432}", 'CHARACTER_DRAGON' => "\u{1F409}", 'CHARACTER_SAUROPOD' => "\u{1F995}", 'CHARACTER_T_REX' => "\u{1F996}", 'CHARACTER_SPOUTING_WHALE' => "\u{1F433}", 'CHARACTER_WHALE' => "\u{1F40B}", 'CHARACTER_DOLPHIN' => "\u{1F42C}", 'CHARACTER_FISH' => "\u{1F41F}", 'CHARACTER_TROPICAL_FISH' => "\u{1F420}", 'CHARACTER_BLOWFISH' => "\u{1F421}", 'CHARACTER_SHARK' => "\u{1F988}", 'CHARACTER_OCTOPUS' => "\u{1F419}", 'CHARACTER_SPIRAL_SHELL' => "\u{1F41A}", 'CHARACTER_CRAB' => "\u{1F980}", 'CHARACTER_LOBSTER' => "\u{1F99E}", 'CHARACTER_SHRIMP' => "\u{1F990}", 'CHARACTER_SQUID' => "\u{1F991}", 'CHARACTER_SNAIL' => "\u{1F40C}", 'CHARACTER_BUTTERFLY' => "\u{1F98B}", 'CHARACTER_BUG' => "\u{1F41B}", 'CHARACTER_ANT' => "\u{1F41C}", 'CHARACTER_HONEYBEE' => "\u{1F41D}", 'CHARACTER_LADY_BEETLE' => "\u{1F41E}", 'CHARACTER_CRICKET' => "\u{1F997}", 'CHARACTER_SPIDER' => "\u{1F577}\u{FE0F}", 'CHARACTER_SPIDER_WEB' => "\u{1F578}\u{FE0F}", 'CHARACTER_SCORPION' => "\u{1F982}", 'CHARACTER_MOSQUITO' => "\u{1F99F}", 'CHARACTER_MICROBE' => "\u{1F9A0}", 'CHARACTER_BOUQUET' => "\u{1F490}", 'CHARACTER_CHERRY_BLOSSOM' => "\u{1F338}", 'CHARACTER_WHITE_FLOWER' => "\u{1F4AE}", 'CHARACTER_ROSETTE' => "\u{1F3F5}\u{FE0F}", 'CHARACTER_ROSE' => "\u{1F339}", 'CHARACTER_WILTED_FLOWER' => "\u{1F940}", 'CHARACTER_HIBISCUS' => "\u{1F33A}", 'CHARACTER_SUNFLOWER' => "\u{1F33B}", 'CHARACTER_BLOSSOM' => "\u{1F33C}", 'CHARACTER_TULIP' => "\u{1F337}", 'CHARACTER_SEEDLING' => "\u{1F331}", 'CHARACTER_EVERGREEN_TREE' => "\u{1F332}", 'CHARACTER_DECIDUOUS_TREE' => "\u{1F333}", 'CHARACTER_PALM_TREE' => "\u{1F334}", 'CHARACTER_CACTUS' => "\u{1F335}", 'CHARACTER_SHEAF_OF_RICE' => "\u{1F33E}", 'CHARACTER_HERB' => "\u{1F33F}", 'CHARACTER_SHAMROCK' => "\u{2618}\u{FE0F}", 'CHARACTER_FOUR_LEAF_CLOVER' => "\u{1F340}", 'CHARACTER_MAPLE_LEAF' => "\u{1F341}", 'CHARACTER_FALLEN_LEAF' => "\u{1F342}", 'CHARACTER_LEAF_FLUTTERING_IN_WIND' => "\u{1F343}", 'CHARACTER_GRAPES' => "\u{1F347}", 'CHARACTER_MELON' => "\u{1F348}", 'CHARACTER_WATERMELON' => "\u{1F349}", 'CHARACTER_TANGERINE' => "\u{1F34A}", 'CHARACTER_LEMON' => "\u{1F34B}", 'CHARACTER_BANANA' => "\u{1F34C}", 'CHARACTER_PINEAPPLE' => "\u{1F34D}", 'CHARACTER_MANGO' => "\u{1F96D}", 'CHARACTER_RED_APPLE' => "\u{1F34E}", 'CHARACTER_GREEN_APPLE' => "\u{1F34F}", 'CHARACTER_PEAR' => "\u{1F350}", 'CHARACTER_PEACH' => "\u{1F351}", 'CHARACTER_CHERRIES' => "\u{1F352}", 'CHARACTER_STRAWBERRY' => "\u{1F353}", 'CHARACTER_KIWI_FRUIT' => "\u{1F95D}", 'CHARACTER_TOMATO' => "\u{1F345}", 'CHARACTER_COCONUT' => "\u{1F965}", 'CHARACTER_AVOCADO' => "\u{1F951}", 'CHARACTER_EGGPLANT' => "\u{1F346}", 'CHARACTER_POTATO' => "\u{1F954}", 'CHARACTER_CARROT' => "\u{1F955}", 'CHARACTER_EAR_OF_CORN' => "\u{1F33D}", 'CHARACTER_HOT_PEPPER' => "\u{1F336}\u{FE0F}", 'CHARACTER_CUCUMBER' => "\u{1F952}", 'CHARACTER_LEAFY_GREEN' => "\u{1F96C}", 'CHARACTER_BROCCOLI' => "\u{1F966}", 'CHARACTER_MUSHROOM' => "\u{1F344}", 'CHARACTER_PEANUTS' => "\u{1F95C}", 'CHARACTER_CHESTNUT' => "\u{1F330}", 'CHARACTER_BREAD' => "\u{1F35E}", 'CHARACTER_CROISSANT' => "\u{1F950}", 'CHARACTER_BAGUETTE_BREAD' => "\u{1F956}", 'CHARACTER_PRETZEL' => "\u{1F968}", 'CHARACTER_BAGEL' => "\u{1F96F}", 'CHARACTER_PANCAKES' => "\u{1F95E}", 'CHARACTER_CHEESE_WEDGE' => "\u{1F9C0}", 'CHARACTER_MEAT_ON_BONE' => "\u{1F356}", 'CHARACTER_POULTRY_LEG' => "\u{1F357}", 'CHARACTER_CUT_OF_MEAT' => "\u{1F969}", 'CHARACTER_BACON' => "\u{1F953}", 'CHARACTER_HAMBURGER' => "\u{1F354}", 'CHARACTER_FRENCH_FRIES' => "\u{1F35F}", 'CHARACTER_PIZZA' => "\u{1F355}", 'CHARACTER_HOT_DOG' => "\u{1F32D}", 'CHARACTER_SANDWICH' => "\u{1F96A}", 'CHARACTER_TACO' => "\u{1F32E}", 'CHARACTER_BURRITO' => "\u{1F32F}", 'CHARACTER_STUFFED_FLATBREAD' => "\u{1F959}", 'CHARACTER_EGG' => "\u{1F95A}", 'CHARACTER_COOKING' => "\u{1F373}", 'CHARACTER_SHALLOW_PAN_OF_FOOD' => "\u{1F958}", 'CHARACTER_POT_OF_FOOD' => "\u{1F372}", 'CHARACTER_BOWL_WITH_SPOON' => "\u{1F963}", 'CHARACTER_GREEN_SALAD' => "\u{1F957}", 'CHARACTER_POPCORN' => "\u{1F37F}", 'CHARACTER_SALT' => "\u{1F9C2}", 'CHARACTER_CANNED_FOOD' => "\u{1F96B}", 'CHARACTER_BENTO_BOX' => "\u{1F371}", 'CHARACTER_RICE_CRACKER' => "\u{1F358}", 'CHARACTER_RICE_BALL' => "\u{1F359}", 'CHARACTER_COOKED_RICE' => "\u{1F35A}", 'CHARACTER_CURRY_RICE' => "\u{1F35B}", 'CHARACTER_STEAMING_BOWL' => "\u{1F35C}", 'CHARACTER_SPAGHETTI' => "\u{1F35D}", 'CHARACTER_ROASTED_SWEET_POTATO' => "\u{1F360}", 'CHARACTER_ODEN' => "\u{1F362}", 'CHARACTER_SUSHI' => "\u{1F363}", 'CHARACTER_FRIED_SHRIMP' => "\u{1F364}", 'CHARACTER_FISH_CAKE_WITH_SWIRL' => "\u{1F365}", 'CHARACTER_MOON_CAKE' => "\u{1F96E}", 'CHARACTER_DANGO' => "\u{1F361}", 'CHARACTER_DUMPLING' => "\u{1F95F}", 'CHARACTER_FORTUNE_COOKIE' => "\u{1F960}", 'CHARACTER_TAKEOUT_BOX' => "\u{1F961}", 'CHARACTER_SOFT_ICE_CREAM' => "\u{1F366}", 'CHARACTER_SHAVED_ICE' => "\u{1F367}", 'CHARACTER_ICE_CREAM' => "\u{1F368}", 'CHARACTER_DOUGHNUT' => "\u{1F369}", 'CHARACTER_COOKIE' => "\u{1F36A}", 'CHARACTER_BIRTHDAY_CAKE' => "\u{1F382}", 'CHARACTER_SHORTCAKE' => "\u{1F370}", 'CHARACTER_CUPCAKE' => "\u{1F9C1}", 'CHARACTER_PIE' => "\u{1F967}", 'CHARACTER_CHOCOLATE_BAR' => "\u{1F36B}", 'CHARACTER_CANDY' => "\u{1F36C}", 'CHARACTER_LOLLIPOP' => "\u{1F36D}", 'CHARACTER_CUSTARD' => "\u{1F36E}", 'CHARACTER_HONEY_POT' => "\u{1F36F}", 'CHARACTER_BABY_BOTTLE' => "\u{1F37C}", 'CHARACTER_GLASS_OF_MILK' => "\u{1F95B}", 'CHARACTER_HOT_BEVERAGE' => "\u{2615}", 'CHARACTER_TEACUP_WITHOUT_HANDLE' => "\u{1F375}", 'CHARACTER_SAKE' => "\u{1F376}", 'CHARACTER_BOTTLE_WITH_POPPING_CORK' => "\u{1F37E}", 'CHARACTER_WINE_GLASS' => "\u{1F377}", 'CHARACTER_COCKTAIL_GLASS' => "\u{1F378}", 'CHARACTER_TROPICAL_DRINK' => "\u{1F379}", 'CHARACTER_BEER_MUG' => "\u{1F37A}", 'CHARACTER_CLINKING_BEER_MUGS' => "\u{1F37B}", 'CHARACTER_CLINKING_GLASSES' => "\u{1F942}", 'CHARACTER_TUMBLER_GLASS' => "\u{1F943}", 'CHARACTER_CUP_WITH_STRAW' => "\u{1F964}", 'CHARACTER_CHOPSTICKS' => "\u{1F962}", 'CHARACTER_FORK_AND_KNIFE_WITH_PLATE' => "\u{1F37D}\u{FE0F}", 'CHARACTER_FORK_AND_KNIFE' => "\u{1F374}", 'CHARACTER_SPOON' => "\u{1F944}", 'CHARACTER_KITCHEN_KNIFE' => "\u{1F52A}", 'CHARACTER_AMPHORA' => "\u{1F3FA}", 'CHARACTER_GLOBE_SHOWING_EUROPE_AFRICA' => "\u{1F30D}", 'CHARACTER_GLOBE_SHOWING_AMERICAS' => "\u{1F30E}", 'CHARACTER_GLOBE_SHOWING_ASIA_AUSTRALIA' => "\u{1F30F}", 'CHARACTER_GLOBE_WITH_MERIDIANS' => "\u{1F310}", 'CHARACTER_WORLD_MAP' => "\u{1F5FA}\u{FE0F}", 'CHARACTER_MAP_OF_JAPAN' => "\u{1F5FE}", 'CHARACTER_COMPASS' => "\u{1F9ED}", 'CHARACTER_SNOW_CAPPED_MOUNTAIN' => "\u{1F3D4}\u{FE0F}", 'CHARACTER_MOUNTAIN' => "\u{26F0}\u{FE0F}", 'CHARACTER_VOLCANO' => "\u{1F30B}", 'CHARACTER_MOUNT_FUJI' => "\u{1F5FB}", 'CHARACTER_CAMPING' => "\u{1F3D5}\u{FE0F}", 'CHARACTER_BEACH_WITH_UMBRELLA' => "\u{1F3D6}\u{FE0F}", 'CHARACTER_DESERT' => "\u{1F3DC}\u{FE0F}", 'CHARACTER_DESERT_ISLAND' => "\u{1F3DD}\u{FE0F}", 'CHARACTER_NATIONAL_PARK' => "\u{1F3DE}\u{FE0F}", 'CHARACTER_STADIUM' => "\u{1F3DF}\u{FE0F}", 'CHARACTER_CLASSICAL_BUILDING' => "\u{1F3DB}\u{FE0F}", 'CHARACTER_BUILDING_CONSTRUCTION' => "\u{1F3D7}\u{FE0F}", 'CHARACTER_BRICKS' => "\u{1F9F1}", 'CHARACTER_HOUSES' => "\u{1F3D8}\u{FE0F}", 'CHARACTER_DERELICT_HOUSE' => "\u{1F3DA}\u{FE0F}", 'CHARACTER_HOUSE' => "\u{1F3E0}", 'CHARACTER_HOUSE_WITH_GARDEN' => "\u{1F3E1}", 'CHARACTER_OFFICE_BUILDING' => "\u{1F3E2}", 'CHARACTER_JAPANESE_POST_OFFICE' => "\u{1F3E3}", 'CHARACTER_POST_OFFICE' => "\u{1F3E4}", 'CHARACTER_HOSPITAL' => "\u{1F3E5}", 'CHARACTER_BANK' => "\u{1F3E6}", 'CHARACTER_HOTEL' => "\u{1F3E8}", 'CHARACTER_LOVE_HOTEL' => "\u{1F3E9}", 'CHARACTER_CONVENIENCE_STORE' => "\u{1F3EA}", 'CHARACTER_SCHOOL' => "\u{1F3EB}", 'CHARACTER_DEPARTMENT_STORE' => "\u{1F3EC}", 'CHARACTER_FACTORY' => "\u{1F3ED}", 'CHARACTER_JAPANESE_CASTLE' => "\u{1F3EF}", 'CHARACTER_CASTLE' => "\u{1F3F0}", 'CHARACTER_WEDDING' => "\u{1F492}", 'CHARACTER_TOKYO_TOWER' => "\u{1F5FC}", 'CHARACTER_STATUE_OF_LIBERTY' => "\u{1F5FD}", 'CHARACTER_CHURCH' => "\u{26EA}", 'CHARACTER_MOSQUE' => "\u{1F54C}", 'CHARACTER_SYNAGOGUE' => "\u{1F54D}", 'CHARACTER_SHINTO_SHRINE' => "\u{26E9}\u{FE0F}", 'CHARACTER_KAABA' => "\u{1F54B}", 'CHARACTER_FOUNTAIN' => "\u{26F2}", 'CHARACTER_TENT' => "\u{26FA}", 'CHARACTER_FOGGY' => "\u{1F301}", 'CHARACTER_NIGHT_WITH_STARS' => "\u{1F303}", 'CHARACTER_CITYSCAPE' => "\u{1F3D9}\u{FE0F}", 'CHARACTER_SUNRISE_OVER_MOUNTAINS' => "\u{1F304}", 'CHARACTER_SUNRISE' => "\u{1F305}", 'CHARACTER_CITYSCAPE_AT_DUSK' => "\u{1F306}", 'CHARACTER_SUNSET' => "\u{1F307}", 'CHARACTER_BRIDGE_AT_NIGHT' => "\u{1F309}", 'CHARACTER_HOT_SPRINGS' => "\u{2668}\u{FE0F}", 'CHARACTER_MILKY_WAY' => "\u{1F30C}", 'CHARACTER_CAROUSEL_HORSE' => "\u{1F3A0}", 'CHARACTER_FERRIS_WHEEL' => "\u{1F3A1}", 'CHARACTER_ROLLER_COASTER' => "\u{1F3A2}", 'CHARACTER_BARBER_POLE' => "\u{1F488}", 'CHARACTER_CIRCUS_TENT' => "\u{1F3AA}", 'CHARACTER_LOCOMOTIVE' => "\u{1F682}", 'CHARACTER_RAILWAY_CAR' => "\u{1F683}", 'CHARACTER_HIGH_SPEED_TRAIN' => "\u{1F684}", 'CHARACTER_BULLET_TRAIN' => "\u{1F685}", 'CHARACTER_TRAIN' => "\u{1F686}", 'CHARACTER_METRO' => "\u{1F687}", 'CHARACTER_LIGHT_RAIL' => "\u{1F688}", 'CHARACTER_STATION' => "\u{1F689}", 'CHARACTER_TRAM' => "\u{1F68A}", 'CHARACTER_MONORAIL' => "\u{1F69D}", 'CHARACTER_MOUNTAIN_RAILWAY' => "\u{1F69E}", 'CHARACTER_TRAM_CAR' => "\u{1F68B}", 'CHARACTER_BUS' => "\u{1F68C}", 'CHARACTER_ONCOMING_BUS' => "\u{1F68D}", 'CHARACTER_TROLLEYBUS' => "\u{1F68E}", 'CHARACTER_MINIBUS' => "\u{1F690}", 'CHARACTER_AMBULANCE' => "\u{1F691}", 'CHARACTER_FIRE_ENGINE' => "\u{1F692}", 'CHARACTER_POLICE_CAR' => "\u{1F693}", 'CHARACTER_ONCOMING_POLICE_CAR' => "\u{1F694}", 'CHARACTER_TAXI' => "\u{1F695}", 'CHARACTER_ONCOMING_TAXI' => "\u{1F696}", 'CHARACTER_AUTOMOBILE' => "\u{1F697}", 'CHARACTER_ONCOMING_AUTOMOBILE' => "\u{1F698}", 'CHARACTER_SPORT_UTILITY_VEHICLE' => "\u{1F699}", 'CHARACTER_DELIVERY_TRUCK' => "\u{1F69A}", 'CHARACTER_ARTICULATED_LORRY' => "\u{1F69B}", 'CHARACTER_TRACTOR' => "\u{1F69C}", 'CHARACTER_BICYCLE' => "\u{1F6B2}", 'CHARACTER_KICK_SCOOTER' => "\u{1F6F4}", 'CHARACTER_SKATEBOARD' => "\u{1F6F9}", 'CHARACTER_MOTOR_SCOOTER' => "\u{1F6F5}", 'CHARACTER_BUS_STOP' => "\u{1F68F}", 'CHARACTER_MOTORWAY' => "\u{1F6E3}\u{FE0F}", 'CHARACTER_RAILWAY_TRACK' => "\u{1F6E4}\u{FE0F}", 'CHARACTER_OIL_DRUM' => "\u{1F6E2}\u{FE0F}", 'CHARACTER_FUEL_PUMP' => "\u{26FD}", 'CHARACTER_POLICE_CAR_LIGHT' => "\u{1F6A8}", 'CHARACTER_HORIZONTAL_TRAFFIC_LIGHT' => "\u{1F6A5}", 'CHARACTER_VERTICAL_TRAFFIC_LIGHT' => "\u{1F6A6}", 'CHARACTER_STOP_SIGN' => "\u{1F6D1}", 'CHARACTER_CONSTRUCTION' => "\u{1F6A7}", 'CHARACTER_ANCHOR' => "\u{2693}", 'CHARACTER_SAILBOAT' => "\u{26F5}", 'CHARACTER_CANOE' => "\u{1F6F6}", 'CHARACTER_SPEEDBOAT' => "\u{1F6A4}", 'CHARACTER_PASSENGER_SHIP' => "\u{1F6F3}\u{FE0F}", 'CHARACTER_FERRY' => "\u{26F4}\u{FE0F}", 'CHARACTER_MOTOR_BOAT' => "\u{1F6E5}\u{FE0F}", 'CHARACTER_SHIP' => "\u{1F6A2}", 'CHARACTER_AIRPLANE' => "\u{2708}\u{FE0F}", 'CHARACTER_SMALL_AIRPLANE' => "\u{1F6E9}\u{FE0F}", 'CHARACTER_AIRPLANE_DEPARTURE' => "\u{1F6EB}", 'CHARACTER_AIRPLANE_ARRIVAL' => "\u{1F6EC}", 'CHARACTER_SEAT' => "\u{1F4BA}", 'CHARACTER_HELICOPTER' => "\u{1F681}", 'CHARACTER_SUSPENSION_RAILWAY' => "\u{1F69F}", 'CHARACTER_MOUNTAIN_CABLEWAY' => "\u{1F6A0}", 'CHARACTER_AERIAL_TRAMWAY' => "\u{1F6A1}", 'CHARACTER_SATELLITE' => "\u{1F6F0}\u{FE0F}", 'CHARACTER_ROCKET' => "\u{1F680}", 'CHARACTER_FLYING_SAUCER' => "\u{1F6F8}", 'CHARACTER_BELLHOP_BELL' => "\u{1F6CE}\u{FE0F}", 'CHARACTER_LUGGAGE' => "\u{1F9F3}", 'CHARACTER_HOURGLASS_DONE' => "\u{231B}", 'CHARACTER_HOURGLASS_NOT_DONE' => "\u{23F3}", 'CHARACTER_WATCH' => "\u{231A}", 'CHARACTER_ALARM_CLOCK' => "\u{23F0}", 'CHARACTER_STOPWATCH' => "\u{23F1}\u{FE0F}", 'CHARACTER_TIMER_CLOCK' => "\u{23F2}\u{FE0F}", 'CHARACTER_MANTELPIECE_CLOCK' => "\u{1F570}\u{FE0F}", 'CHARACTER_TWELVE_O_CLOCK' => "\u{1F55B}", 'CHARACTER_TWELVE_THIRTY' => "\u{1F567}", 'CHARACTER_ONE_O_CLOCK' => "\u{1F550}", 'CHARACTER_ONE_THIRTY' => "\u{1F55C}", 'CHARACTER_TWO_O_CLOCK' => "\u{1F551}", 'CHARACTER_TWO_THIRTY' => "\u{1F55D}", 'CHARACTER_THREE_O_CLOCK' => "\u{1F552}", 'CHARACTER_THREE_THIRTY' => "\u{1F55E}", 'CHARACTER_FOUR_O_CLOCK' => "\u{1F553}", 'CHARACTER_FOUR_THIRTY' => "\u{1F55F}", 'CHARACTER_FIVE_O_CLOCK' => "\u{1F554}", 'CHARACTER_FIVE_THIRTY' => "\u{1F560}", 'CHARACTER_SIX_O_CLOCK' => "\u{1F555}", 'CHARACTER_SIX_THIRTY' => "\u{1F561}", 'CHARACTER_SEVEN_O_CLOCK' => "\u{1F556}", 'CHARACTER_SEVEN_THIRTY' => "\u{1F562}", 'CHARACTER_EIGHT_O_CLOCK' => "\u{1F557}", 'CHARACTER_EIGHT_THIRTY' => "\u{1F563}", 'CHARACTER_NINE_O_CLOCK' => "\u{1F558}", 'CHARACTER_NINE_THIRTY' => "\u{1F564}", 'CHARACTER_TEN_O_CLOCK' => "\u{1F559}", 'CHARACTER_TEN_THIRTY' => "\u{1F565}", 'CHARACTER_ELEVEN_O_CLOCK' => "\u{1F55A}", 'CHARACTER_ELEVEN_THIRTY' => "\u{1F566}", 'CHARACTER_NEW_MOON' => "\u{1F311}", 'CHARACTER_WAXING_CRESCENT_MOON' => "\u{1F312}", 'CHARACTER_FIRST_QUARTER_MOON' => "\u{1F313}", 'CHARACTER_WAXING_GIBBOUS_MOON' => "\u{1F314}", 'CHARACTER_FULL_MOON' => "\u{1F315}", 'CHARACTER_WANING_GIBBOUS_MOON' => "\u{1F316}", 'CHARACTER_LAST_QUARTER_MOON' => "\u{1F317}", 'CHARACTER_WANING_CRESCENT_MOON' => "\u{1F318}", 'CHARACTER_CRESCENT_MOON' => "\u{1F319}", 'CHARACTER_NEW_MOON_FACE' => "\u{1F31A}", 'CHARACTER_FIRST_QUARTER_MOON_FACE' => "\u{1F31B}", 'CHARACTER_LAST_QUARTER_MOON_FACE' => "\u{1F31C}", 'CHARACTER_THERMOMETER' => "\u{1F321}\u{FE0F}", 'CHARACTER_SUN' => "\u{2600}\u{FE0F}", 'CHARACTER_FULL_MOON_FACE' => "\u{1F31D}", 'CHARACTER_SUN_WITH_FACE' => "\u{1F31E}", 'CHARACTER_STAR' => "\u{2B50}", 'CHARACTER_GLOWING_STAR' => "\u{1F31F}", 'CHARACTER_SHOOTING_STAR' => "\u{1F320}", 'CHARACTER_CLOUD' => "\u{2601}\u{FE0F}", 'CHARACTER_SUN_BEHIND_CLOUD' => "\u{26C5}", 'CHARACTER_CLOUD_WITH_LIGHTNING_AND_RAIN' => "\u{26C8}\u{FE0F}", 'CHARACTER_SUN_BEHIND_SMALL_CLOUD' => "\u{1F324}\u{FE0F}", 'CHARACTER_SUN_BEHIND_LARGE_CLOUD' => "\u{1F325}\u{FE0F}", 'CHARACTER_SUN_BEHIND_RAIN_CLOUD' => "\u{1F326}\u{FE0F}", 'CHARACTER_CLOUD_WITH_RAIN' => "\u{1F327}\u{FE0F}", 'CHARACTER_CLOUD_WITH_SNOW' => "\u{1F328}\u{FE0F}", 'CHARACTER_CLOUD_WITH_LIGHTNING' => "\u{1F329}\u{FE0F}", 'CHARACTER_TORNADO' => "\u{1F32A}\u{FE0F}", 'CHARACTER_FOG' => "\u{1F32B}\u{FE0F}", 'CHARACTER_WIND_FACE' => "\u{1F32C}\u{FE0F}", 'CHARACTER_CYCLONE' => "\u{1F300}", 'CHARACTER_RAINBOW' => "\u{1F308}", 'CHARACTER_CLOSED_UMBRELLA' => "\u{1F302}", 'CHARACTER_UMBRELLA' => "\u{2602}\u{FE0F}", 'CHARACTER_UMBRELLA_WITH_RAIN_DROPS' => "\u{2614}", 'CHARACTER_UMBRELLA_ON_GROUND' => "\u{26F1}\u{FE0F}", 'CHARACTER_HIGH_VOLTAGE' => "\u{26A1}", 'CHARACTER_SNOWFLAKE' => "\u{2744}\u{FE0F}", 'CHARACTER_SNOWMAN' => "\u{2603}\u{FE0F}", 'CHARACTER_SNOWMAN_WITHOUT_SNOW' => "\u{26C4}", 'CHARACTER_COMET' => "\u{2604}\u{FE0F}", 'CHARACTER_FIRE' => "\u{1F525}", 'CHARACTER_DROPLET' => "\u{1F4A7}", 'CHARACTER_WATER_WAVE' => "\u{1F30A}", 'CHARACTER_JACK_O_LANTERN' => "\u{1F383}", 'CHARACTER_CHRISTMAS_TREE' => "\u{1F384}", 'CHARACTER_FIREWORKS' => "\u{1F386}", 'CHARACTER_SPARKLER' => "\u{1F387}", 'CHARACTER_FIRECRACKER' => "\u{1F9E8}", 'CHARACTER_SPARKLES' => "\u{2728}", 'CHARACTER_BALLOON' => "\u{1F388}", 'CHARACTER_PARTY_POPPER' => "\u{1F389}", 'CHARACTER_CONFETTI_BALL' => "\u{1F38A}", 'CHARACTER_TANABATA_TREE' => "\u{1F38B}", 'CHARACTER_PINE_DECORATION' => "\u{1F38D}", 'CHARACTER_JAPANESE_DOLLS' => "\u{1F38E}", 'CHARACTER_CARP_STREAMER' => "\u{1F38F}", 'CHARACTER_WIND_CHIME' => "\u{1F390}", 'CHARACTER_MOON_VIEWING_CEREMONY' => "\u{1F391}", 'CHARACTER_RED_ENVELOPE' => "\u{1F9E7}", 'CHARACTER_RIBBON' => "\u{1F380}", 'CHARACTER_WRAPPED_GIFT' => "\u{1F381}", 'CHARACTER_REMINDER_RIBBON' => "\u{1F397}\u{FE0F}", 'CHARACTER_ADMISSION_TICKETS' => "\u{1F39F}\u{FE0F}", 'CHARACTER_TICKET' => "\u{1F3AB}", 'CHARACTER_MILITARY_MEDAL' => "\u{1F396}\u{FE0F}", 'CHARACTER_TROPHY' => "\u{1F3C6}", 'CHARACTER_SPORTS_MEDAL' => "\u{1F3C5}", 'CHARACTER_1ST_PLACE_MEDAL' => "\u{1F947}", 'CHARACTER_2ND_PLACE_MEDAL' => "\u{1F948}", 'CHARACTER_3RD_PLACE_MEDAL' => "\u{1F949}", 'CHARACTER_SOCCER_BALL' => "\u{26BD}", 'CHARACTER_BASEBALL' => "\u{26BE}", 'CHARACTER_SOFTBALL' => "\u{1F94E}", 'CHARACTER_BASKETBALL' => "\u{1F3C0}", 'CHARACTER_VOLLEYBALL' => "\u{1F3D0}", 'CHARACTER_AMERICAN_FOOTBALL' => "\u{1F3C8}", 'CHARACTER_RUGBY_FOOTBALL' => "\u{1F3C9}", 'CHARACTER_TENNIS' => "\u{1F3BE}", 'CHARACTER_FLYING_DISC' => "\u{1F94F}", 'CHARACTER_BOWLING' => "\u{1F3B3}", 'CHARACTER_CRICKET_GAME' => "\u{1F3CF}", 'CHARACTER_FIELD_HOCKEY' => "\u{1F3D1}", 'CHARACTER_ICE_HOCKEY' => "\u{1F3D2}", 'CHARACTER_LACROSSE' => "\u{1F94D}", 'CHARACTER_PING_PONG' => "\u{1F3D3}", 'CHARACTER_BADMINTON' => "\u{1F3F8}", 'CHARACTER_BOXING_GLOVE' => "\u{1F94A}", 'CHARACTER_MARTIAL_ARTS_UNIFORM' => "\u{1F94B}", 'CHARACTER_GOAL_NET' => "\u{1F945}", 'CHARACTER_FLAG_IN_HOLE' => "\u{26F3}", 'CHARACTER_ICE_SKATE' => "\u{26F8}\u{FE0F}", 'CHARACTER_FISHING_POLE' => "\u{1F3A3}", 'CHARACTER_RUNNING_SHIRT' => "\u{1F3BD}", 'CHARACTER_SKIS' => "\u{1F3BF}", 'CHARACTER_SLED' => "\u{1F6F7}", 'CHARACTER_CURLING_STONE' => "\u{1F94C}", 'CHARACTER_DIRECT_HIT' => "\u{1F3AF}", 'CHARACTER_POOL_8_BALL' => "\u{1F3B1}", 'CHARACTER_CRYSTAL_BALL' => "\u{1F52E}", 'CHARACTER_NAZAR_AMULET' => "\u{1F9FF}", 'CHARACTER_VIDEO_GAME' => "\u{1F3AE}", 'CHARACTER_JOYSTICK' => "\u{1F579}\u{FE0F}", 'CHARACTER_SLOT_MACHINE' => "\u{1F3B0}", 'CHARACTER_GAME_DIE' => "\u{1F3B2}", 'CHARACTER_JIGSAW' => "\u{1F9E9}", 'CHARACTER_TEDDY_BEAR' => "\u{1F9F8}", 'CHARACTER_SPADE_SUIT' => "\u{2660}\u{FE0F}", 'CHARACTER_HEART_SUIT' => "\u{2665}\u{FE0F}", 'CHARACTER_DIAMOND_SUIT' => "\u{2666}\u{FE0F}", 'CHARACTER_CLUB_SUIT' => "\u{2663}\u{FE0F}", 'CHARACTER_CHESS_PAWN' => "\u{265F}\u{FE0F}", 'CHARACTER_JOKER' => "\u{1F0CF}", 'CHARACTER_MAHJONG_RED_DRAGON' => "\u{1F004}", 'CHARACTER_FLOWER_PLAYING_CARDS' => "\u{1F3B4}", 'CHARACTER_PERFORMING_ARTS' => "\u{1F3AD}", 'CHARACTER_FRAMED_PICTURE' => "\u{1F5BC}\u{FE0F}", 'CHARACTER_ARTIST_PALETTE' => "\u{1F3A8}", 'CHARACTER_THREAD' => "\u{1F9F5}", 'CHARACTER_YARN' => "\u{1F9F6}", 'CHARACTER_MUTED_SPEAKER' => "\u{1F507}", 'CHARACTER_SPEAKER_LOW_VOLUME' => "\u{1F508}", 'CHARACTER_SPEAKER_MEDIUM_VOLUME' => "\u{1F509}", 'CHARACTER_SPEAKER_HIGH_VOLUME' => "\u{1F50A}", 'CHARACTER_LOUDSPEAKER' => "\u{1F4E2}", 'CHARACTER_MEGAPHONE' => "\u{1F4E3}", 'CHARACTER_POSTAL_HORN' => "\u{1F4EF}", 'CHARACTER_BELL' => "\u{1F514}", 'CHARACTER_BELL_WITH_SLASH' => "\u{1F515}", 'CHARACTER_MUSICAL_SCORE' => "\u{1F3BC}", 'CHARACTER_MUSICAL_NOTE' => "\u{1F3B5}", 'CHARACTER_MUSICAL_NOTES' => "\u{1F3B6}", 'CHARACTER_STUDIO_MICROPHONE' => "\u{1F399}\u{FE0F}", 'CHARACTER_LEVEL_SLIDER' => "\u{1F39A}\u{FE0F}", 'CHARACTER_CONTROL_KNOBS' => "\u{1F39B}\u{FE0F}", 'CHARACTER_MICROPHONE' => "\u{1F3A4}", 'CHARACTER_HEADPHONE' => "\u{1F3A7}", 'CHARACTER_RADIO' => "\u{1F4FB}", 'CHARACTER_SAXOPHONE' => "\u{1F3B7}", 'CHARACTER_GUITAR' => "\u{1F3B8}", 'CHARACTER_MUSICAL_KEYBOARD' => "\u{1F3B9}", 'CHARACTER_TRUMPET' => "\u{1F3BA}", 'CHARACTER_VIOLIN' => "\u{1F3BB}", 'CHARACTER_DRUM' => "\u{1F941}", 'CHARACTER_MOBILE_PHONE' => "\u{1F4F1}", 'CHARACTER_MOBILE_PHONE_WITH_ARROW' => "\u{1F4F2}", 'CHARACTER_TELEPHONE' => "\u{260E}\u{FE0F}", 'CHARACTER_TELEPHONE_RECEIVER' => "\u{1F4DE}", 'CHARACTER_PAGER' => "\u{1F4DF}", 'CHARACTER_FAX_MACHINE' => "\u{1F4E0}", 'CHARACTER_BATTERY' => "\u{1F50B}", 'CHARACTER_ELECTRIC_PLUG' => "\u{1F50C}", 'CHARACTER_LAPTOP_COMPUTER' => "\u{1F4BB}", 'CHARACTER_DESKTOP_COMPUTER' => "\u{1F5A5}\u{FE0F}", 'CHARACTER_PRINTER' => "\u{1F5A8}\u{FE0F}", 'CHARACTER_KEYBOARD' => "\u{2328}\u{FE0F}", 'CHARACTER_COMPUTER_MOUSE' => "\u{1F5B1}\u{FE0F}", 'CHARACTER_TRACKBALL' => "\u{1F5B2}\u{FE0F}", 'CHARACTER_COMPUTER_DISK' => "\u{1F4BD}", 'CHARACTER_FLOPPY_DISK' => "\u{1F4BE}", 'CHARACTER_OPTICAL_DISK' => "\u{1F4BF}", 'CHARACTER_DVD' => "\u{1F4C0}", 'CHARACTER_ABACUS' => "\u{1F9EE}", 'CHARACTER_MOVIE_CAMERA' => "\u{1F3A5}", 'CHARACTER_FILM_FRAMES' => "\u{1F39E}\u{FE0F}", 'CHARACTER_FILM_PROJECTOR' => "\u{1F4FD}\u{FE0F}", 'CHARACTER_CLAPPER_BOARD' => "\u{1F3AC}", 'CHARACTER_TELEVISION' => "\u{1F4FA}", 'CHARACTER_CAMERA' => "\u{1F4F7}", 'CHARACTER_CAMERA_WITH_FLASH' => "\u{1F4F8}", 'CHARACTER_VIDEO_CAMERA' => "\u{1F4F9}", 'CHARACTER_VIDEOCASSETTE' => "\u{1F4FC}", 'CHARACTER_MAGNIFYING_GLASS_TILTED_LEFT' => "\u{1F50D}", 'CHARACTER_MAGNIFYING_GLASS_TILTED_RIGHT' => "\u{1F50E}", 'CHARACTER_CANDLE' => "\u{1F56F}\u{FE0F}", 'CHARACTER_LIGHT_BULB' => "\u{1F4A1}", 'CHARACTER_FLASHLIGHT' => "\u{1F526}", 'CHARACTER_RED_PAPER_LANTERN' => "\u{1F3EE}", 'CHARACTER_NOTEBOOK_WITH_DECORATIVE_COVER' => "\u{1F4D4}", 'CHARACTER_CLOSED_BOOK' => "\u{1F4D5}", 'CHARACTER_OPEN_BOOK' => "\u{1F4D6}", 'CHARACTER_GREEN_BOOK' => "\u{1F4D7}", 'CHARACTER_BLUE_BOOK' => "\u{1F4D8}", 'CHARACTER_ORANGE_BOOK' => "\u{1F4D9}", 'CHARACTER_BOOKS' => "\u{1F4DA}", 'CHARACTER_NOTEBOOK' => "\u{1F4D3}", 'CHARACTER_LEDGER' => "\u{1F4D2}", 'CHARACTER_PAGE_WITH_CURL' => "\u{1F4C3}", 'CHARACTER_SCROLL' => "\u{1F4DC}", 'CHARACTER_PAGE_FACING_UP' => "\u{1F4C4}", 'CHARACTER_NEWSPAPER' => "\u{1F4F0}", 'CHARACTER_ROLLED_UP_NEWSPAPER' => "\u{1F5DE}\u{FE0F}", 'CHARACTER_BOOKMARK_TABS' => "\u{1F4D1}", 'CHARACTER_BOOKMARK' => "\u{1F516}", 'CHARACTER_LABEL' => "\u{1F3F7}\u{FE0F}", 'CHARACTER_MONEY_BAG' => "\u{1F4B0}", 'CHARACTER_YEN_BANKNOTE' => "\u{1F4B4}", 'CHARACTER_DOLLAR_BANKNOTE' => "\u{1F4B5}", 'CHARACTER_EURO_BANKNOTE' => "\u{1F4B6}", 'CHARACTER_POUND_BANKNOTE' => "\u{1F4B7}", 'CHARACTER_MONEY_WITH_WINGS' => "\u{1F4B8}", 'CHARACTER_CREDIT_CARD' => "\u{1F4B3}", 'CHARACTER_RECEIPT' => "\u{1F9FE}", 'CHARACTER_CHART_INCREASING_WITH_YEN' => "\u{1F4B9}", 'CHARACTER_CURRENCY_EXCHANGE' => "\u{1F4B1}", 'CHARACTER_HEAVY_DOLLAR_SIGN' => "\u{1F4B2}", 'CHARACTER_ENVELOPE' => "\u{2709}\u{FE0F}", 'CHARACTER_E_MAIL' => "\u{1F4E7}", 'CHARACTER_INCOMING_ENVELOPE' => "\u{1F4E8}", 'CHARACTER_ENVELOPE_WITH_ARROW' => "\u{1F4E9}", 'CHARACTER_OUTBOX_TRAY' => "\u{1F4E4}", 'CHARACTER_INBOX_TRAY' => "\u{1F4E5}", 'CHARACTER_PACKAGE' => "\u{1F4E6}", 'CHARACTER_CLOSED_MAILBOX_WITH_RAISED_FLAG' => "\u{1F4EB}", 'CHARACTER_CLOSED_MAILBOX_WITH_LOWERED_FLAG' => "\u{1F4EA}", 'CHARACTER_OPEN_MAILBOX_WITH_RAISED_FLAG' => "\u{1F4EC}", 'CHARACTER_OPEN_MAILBOX_WITH_LOWERED_FLAG' => "\u{1F4ED}", 'CHARACTER_POSTBOX' => "\u{1F4EE}", 'CHARACTER_BALLOT_BOX_WITH_BALLOT' => "\u{1F5F3}\u{FE0F}", 'CHARACTER_PENCIL' => "\u{270F}\u{FE0F}", 'CHARACTER_BLACK_NIB' => "\u{2712}\u{FE0F}", 'CHARACTER_FOUNTAIN_PEN' => "\u{1F58B}\u{FE0F}", 'CHARACTER_PEN' => "\u{1F58A}\u{FE0F}", 'CHARACTER_PAINTBRUSH' => "\u{1F58C}\u{FE0F}", 'CHARACTER_CRAYON' => "\u{1F58D}\u{FE0F}", 'CHARACTER_MEMO' => "\u{1F4DD}", 'CHARACTER_BRIEFCASE' => "\u{1F4BC}", 'CHARACTER_FILE_FOLDER' => "\u{1F4C1}", 'CHARACTER_OPEN_FILE_FOLDER' => "\u{1F4C2}", 'CHARACTER_CARD_INDEX_DIVIDERS' => "\u{1F5C2}\u{FE0F}", 'CHARACTER_CALENDAR' => "\u{1F4C5}", 'CHARACTER_TEAR_OFF_CALENDAR' => "\u{1F4C6}", 'CHARACTER_SPIRAL_NOTEPAD' => "\u{1F5D2}\u{FE0F}", 'CHARACTER_SPIRAL_CALENDAR' => "\u{1F5D3}\u{FE0F}", 'CHARACTER_CARD_INDEX' => "\u{1F4C7}", 'CHARACTER_CHART_INCREASING' => "\u{1F4C8}", 'CHARACTER_CHART_DECREASING' => "\u{1F4C9}", 'CHARACTER_BAR_CHART' => "\u{1F4CA}", 'CHARACTER_CLIPBOARD' => "\u{1F4CB}", 'CHARACTER_PUSHPIN' => "\u{1F4CC}", 'CHARACTER_ROUND_PUSHPIN' => "\u{1F4CD}", 'CHARACTER_PAPERCLIP' => "\u{1F4CE}", 'CHARACTER_LINKED_PAPERCLIPS' => "\u{1F587}\u{FE0F}", 'CHARACTER_STRAIGHT_RULER' => "\u{1F4CF}", 'CHARACTER_TRIANGULAR_RULER' => "\u{1F4D0}", 'CHARACTER_SCISSORS' => "\u{2702}\u{FE0F}", 'CHARACTER_CARD_FILE_BOX' => "\u{1F5C3}\u{FE0F}", 'CHARACTER_FILE_CABINET' => "\u{1F5C4}\u{FE0F}", 'CHARACTER_WASTEBASKET' => "\u{1F5D1}\u{FE0F}", 'CHARACTER_LOCKED' => "\u{1F512}", 'CHARACTER_UNLOCKED' => "\u{1F513}", 'CHARACTER_LOCKED_WITH_PEN' => "\u{1F50F}", 'CHARACTER_LOCKED_WITH_KEY' => "\u{1F510}", 'CHARACTER_KEY' => "\u{1F511}", 'CHARACTER_OLD_KEY' => "\u{1F5DD}\u{FE0F}", 'CHARACTER_HAMMER' => "\u{1F528}", 'CHARACTER_PICK' => "\u{26CF}\u{FE0F}", 'CHARACTER_HAMMER_AND_PICK' => "\u{2692}\u{FE0F}", 'CHARACTER_HAMMER_AND_WRENCH' => "\u{1F6E0}\u{FE0F}", 'CHARACTER_DAGGER' => "\u{1F5E1}\u{FE0F}", 'CHARACTER_CROSSED_SWORDS' => "\u{2694}\u{FE0F}", 'CHARACTER_PISTOL' => "\u{1F52B}", 'CHARACTER_BOW_AND_ARROW' => "\u{1F3F9}", 'CHARACTER_SHIELD' => "\u{1F6E1}\u{FE0F}", 'CHARACTER_WRENCH' => "\u{1F527}", 'CHARACTER_NUT_AND_BOLT' => "\u{1F529}", 'CHARACTER_GEAR' => "\u{2699}\u{FE0F}", 'CHARACTER_CLAMP' => "\u{1F5DC}\u{FE0F}", 'CHARACTER_BALANCE_SCALE' => "\u{2696}\u{FE0F}", 'CHARACTER_LINK' => "\u{1F517}", 'CHARACTER_CHAINS' => "\u{26D3}\u{FE0F}", 'CHARACTER_TOOLBOX' => "\u{1F9F0}", 'CHARACTER_MAGNET' => "\u{1F9F2}", 'CHARACTER_ALEMBIC' => "\u{2697}\u{FE0F}", 'CHARACTER_TEST_TUBE' => "\u{1F9EA}", 'CHARACTER_PETRI_DISH' => "\u{1F9EB}", 'CHARACTER_DNA' => "\u{1F9EC}", 'CHARACTER_MICROSCOPE' => "\u{1F52C}", 'CHARACTER_TELESCOPE' => "\u{1F52D}", 'CHARACTER_SATELLITE_ANTENNA' => "\u{1F4E1}", 'CHARACTER_SYRINGE' => "\u{1F489}", 'CHARACTER_PILL' => "\u{1F48A}", 'CHARACTER_DOOR' => "\u{1F6AA}", 'CHARACTER_BED' => "\u{1F6CF}\u{FE0F}", 'CHARACTER_COUCH_AND_LAMP' => "\u{1F6CB}\u{FE0F}", 'CHARACTER_TOILET' => "\u{1F6BD}", 'CHARACTER_SHOWER' => "\u{1F6BF}", 'CHARACTER_BATHTUB' => "\u{1F6C1}", 'CHARACTER_LOTION_BOTTLE' => "\u{1F9F4}", 'CHARACTER_SAFETY_PIN' => "\u{1F9F7}", 'CHARACTER_BROOM' => "\u{1F9F9}", 'CHARACTER_BASKET' => "\u{1F9FA}", 'CHARACTER_ROLL_OF_PAPER' => "\u{1F9FB}", 'CHARACTER_SOAP' => "\u{1F9FC}", 'CHARACTER_SPONGE' => "\u{1F9FD}", 'CHARACTER_FIRE_EXTINGUISHER' => "\u{1F9EF}", 'CHARACTER_SHOPPING_CART' => "\u{1F6D2}", 'CHARACTER_CIGARETTE' => "\u{1F6AC}", 'CHARACTER_COFFIN' => "\u{26B0}\u{FE0F}", 'CHARACTER_FUNERAL_URN' => "\u{26B1}\u{FE0F}", 'CHARACTER_MOAI' => "\u{1F5FF}", 'CHARACTER_ATM_SIGN' => "\u{1F3E7}", 'CHARACTER_LITTER_IN_BIN_SIGN' => "\u{1F6AE}", 'CHARACTER_POTABLE_WATER' => "\u{1F6B0}", 'CHARACTER_WHEELCHAIR_SYMBOL' => "\u{267F}", 'CHARACTER_MEN_S_ROOM' => "\u{1F6B9}", 'CHARACTER_WOMEN_S_ROOM' => "\u{1F6BA}", 'CHARACTER_RESTROOM' => "\u{1F6BB}", 'CHARACTER_BABY_SYMBOL' => "\u{1F6BC}", 'CHARACTER_WATER_CLOSET' => "\u{1F6BE}", 'CHARACTER_PASSPORT_CONTROL' => "\u{1F6C2}", 'CHARACTER_CUSTOMS' => "\u{1F6C3}", 'CHARACTER_BAGGAGE_CLAIM' => "\u{1F6C4}", 'CHARACTER_LEFT_LUGGAGE' => "\u{1F6C5}", 'CHARACTER_WARNING' => "\u{26A0}\u{FE0F}", 'CHARACTER_CHILDREN_CROSSING' => "\u{1F6B8}", 'CHARACTER_NO_ENTRY' => "\u{26D4}", 'CHARACTER_PROHIBITED' => "\u{1F6AB}", 'CHARACTER_NO_BICYCLES' => "\u{1F6B3}", 'CHARACTER_NO_SMOKING' => "\u{1F6AD}", 'CHARACTER_NO_LITTERING' => "\u{1F6AF}", 'CHARACTER_NON_POTABLE_WATER' => "\u{1F6B1}", 'CHARACTER_NO_PEDESTRIANS' => "\u{1F6B7}", 'CHARACTER_NO_MOBILE_PHONES' => "\u{1F4F5}", 'CHARACTER_NO_ONE_UNDER_EIGHTEEN' => "\u{1F51E}", 'CHARACTER_RADIOACTIVE' => "\u{2622}\u{FE0F}", 'CHARACTER_BIOHAZARD' => "\u{2623}\u{FE0F}", 'CHARACTER_UP_ARROW' => "\u{2B06}\u{FE0F}", 'CHARACTER_UP_RIGHT_ARROW' => "\u{2197}\u{FE0F}", 'CHARACTER_RIGHT_ARROW' => "\u{27A1}\u{FE0F}", 'CHARACTER_DOWN_RIGHT_ARROW' => "\u{2198}\u{FE0F}", 'CHARACTER_DOWN_ARROW' => "\u{2B07}\u{FE0F}", 'CHARACTER_DOWN_LEFT_ARROW' => "\u{2199}\u{FE0F}", 'CHARACTER_LEFT_ARROW' => "\u{2B05}\u{FE0F}", 'CHARACTER_UP_LEFT_ARROW' => "\u{2196}\u{FE0F}", 'CHARACTER_UP_DOWN_ARROW' => "\u{2195}\u{FE0F}", 'CHARACTER_LEFT_RIGHT_ARROW' => "\u{2194}\u{FE0F}", 'CHARACTER_RIGHT_ARROW_CURVING_LEFT' => "\u{21A9}\u{FE0F}", 'CHARACTER_LEFT_ARROW_CURVING_RIGHT' => "\u{21AA}\u{FE0F}", 'CHARACTER_RIGHT_ARROW_CURVING_UP' => "\u{2934}\u{FE0F}", 'CHARACTER_RIGHT_ARROW_CURVING_DOWN' => "\u{2935}\u{FE0F}", 'CHARACTER_CLOCKWISE_VERTICAL_ARROWS' => "\u{1F503}", 'CHARACTER_COUNTERCLOCKWISE_ARROWS_BUTTON' => "\u{1F504}", 'CHARACTER_BACK_ARROW' => "\u{1F519}", 'CHARACTER_END_ARROW' => "\u{1F51A}", 'CHARACTER_ON_ARROW' => "\u{1F51B}", 'CHARACTER_SOON_ARROW' => "\u{1F51C}", 'CHARACTER_TOP_ARROW' => "\u{1F51D}", 'CHARACTER_PLACE_OF_WORSHIP' => "\u{1F6D0}", 'CHARACTER_ATOM_SYMBOL' => "\u{269B}\u{FE0F}", 'CHARACTER_OM' => "\u{1F549}\u{FE0F}", 'CHARACTER_STAR_OF_DAVID' => "\u{2721}\u{FE0F}", 'CHARACTER_WHEEL_OF_DHARMA' => "\u{2638}\u{FE0F}", 'CHARACTER_YIN_YANG' => "\u{262F}\u{FE0F}", 'CHARACTER_LATIN_CROSS' => "\u{271D}\u{FE0F}", 'CHARACTER_ORTHODOX_CROSS' => "\u{2626}\u{FE0F}", 'CHARACTER_STAR_AND_CRESCENT' => "\u{262A}\u{FE0F}", 'CHARACTER_PEACE_SYMBOL' => "\u{262E}\u{FE0F}", 'CHARACTER_MENORAH' => "\u{1F54E}", 'CHARACTER_DOTTED_SIX_POINTED_STAR' => "\u{1F52F}", 'CHARACTER_ARIES' => "\u{2648}", 'CHARACTER_TAURUS' => "\u{2649}", 'CHARACTER_GEMINI' => "\u{264A}", 'CHARACTER_CANCER' => "\u{264B}", 'CHARACTER_LEO' => "\u{264C}", 'CHARACTER_VIRGO' => "\u{264D}", 'CHARACTER_LIBRA' => "\u{264E}", 'CHARACTER_SCORPIO' => "\u{264F}", 'CHARACTER_SAGITTARIUS' => "\u{2650}", 'CHARACTER_CAPRICORN' => "\u{2651}", 'CHARACTER_AQUARIUS' => "\u{2652}", 'CHARACTER_PISCES' => "\u{2653}", 'CHARACTER_OPHIUCHUS' => "\u{26CE}", 'CHARACTER_SHUFFLE_TRACKS_BUTTON' => "\u{1F500}", 'CHARACTER_REPEAT_BUTTON' => "\u{1F501}", 'CHARACTER_REPEAT_SINGLE_BUTTON' => "\u{1F502}", 'CHARACTER_PLAY_BUTTON' => "\u{25B6}\u{FE0F}", 'CHARACTER_FAST_FORWARD_BUTTON' => "\u{23E9}", 'CHARACTER_NEXT_TRACK_BUTTON' => "\u{23ED}\u{FE0F}", 'CHARACTER_PLAY_OR_PAUSE_BUTTON' => "\u{23EF}\u{FE0F}", 'CHARACTER_REVERSE_BUTTON' => "\u{25C0}\u{FE0F}", 'CHARACTER_FAST_REVERSE_BUTTON' => "\u{23EA}", 'CHARACTER_LAST_TRACK_BUTTON' => "\u{23EE}\u{FE0F}", 'CHARACTER_UPWARDS_BUTTON' => "\u{1F53C}", 'CHARACTER_FAST_UP_BUTTON' => "\u{23EB}", 'CHARACTER_DOWNWARDS_BUTTON' => "\u{1F53D}", 'CHARACTER_FAST_DOWN_BUTTON' => "\u{23EC}", 'CHARACTER_PAUSE_BUTTON' => "\u{23F8}\u{FE0F}", 'CHARACTER_STOP_BUTTON' => "\u{23F9}\u{FE0F}", 'CHARACTER_RECORD_BUTTON' => "\u{23FA}\u{FE0F}", 'CHARACTER_EJECT_BUTTON' => "\u{23CF}\u{FE0F}", 'CHARACTER_CINEMA' => "\u{1F3A6}", 'CHARACTER_DIM_BUTTON' => "\u{1F505}", 'CHARACTER_BRIGHT_BUTTON' => "\u{1F506}", 'CHARACTER_ANTENNA_BARS' => "\u{1F4F6}", 'CHARACTER_VIBRATION_MODE' => "\u{1F4F3}", 'CHARACTER_MOBILE_PHONE_OFF' => "\u{1F4F4}", 'CHARACTER_FEMALE_SIGN' => "\u{2640}\u{FE0F}", 'CHARACTER_MALE_SIGN' => "\u{2642}\u{FE0F}", 'CHARACTER_MEDICAL_SYMBOL' => "\u{2695}\u{FE0F}", 'CHARACTER_INFINITY' => "\u{267E}\u{FE0F}", 'CHARACTER_RECYCLING_SYMBOL' => "\u{267B}\u{FE0F}", 'CHARACTER_FLEUR_DE_LIS' => "\u{269C}\u{FE0F}", 'CHARACTER_TRIDENT_EMBLEM' => "\u{1F531}", 'CHARACTER_NAME_BADGE' => "\u{1F4DB}", 'CHARACTER_JAPANESE_SYMBOL_FOR_BEGINNER' => "\u{1F530}", 'CHARACTER_HEAVY_LARGE_CIRCLE' => "\u{2B55}", 'CHARACTER_WHITE_HEAVY_CHECK_MARK' => "\u{2705}", 'CHARACTER_BALLOT_BOX_WITH_CHECK' => "\u{2611}\u{FE0F}", 'CHARACTER_HEAVY_CHECK_MARK' => "\u{2714}\u{FE0F}", 'CHARACTER_HEAVY_MULTIPLICATION_X' => "\u{2716}\u{FE0F}", 'CHARACTER_CROSS_MARK' => "\u{274C}", 'CHARACTER_CROSS_MARK_BUTTON' => "\u{274E}", 'CHARACTER_HEAVY_PLUS_SIGN' => "\u{2795}", 'CHARACTER_HEAVY_MINUS_SIGN' => "\u{2796}", 'CHARACTER_HEAVY_DIVISION_SIGN' => "\u{2797}", 'CHARACTER_CURLY_LOOP' => "\u{27B0}", 'CHARACTER_DOUBLE_CURLY_LOOP' => "\u{27BF}", 'CHARACTER_PART_ALTERNATION_MARK' => "\u{303D}\u{FE0F}", 'CHARACTER_EIGHT_SPOKED_ASTERISK' => "\u{2733}\u{FE0F}", 'CHARACTER_EIGHT_POINTED_STAR' => "\u{2734}\u{FE0F}", 'CHARACTER_SPARKLE' => "\u{2747}\u{FE0F}", 'CHARACTER_DOUBLE_EXCLAMATION_MARK' => "\u{203C}\u{FE0F}", 'CHARACTER_EXCLAMATION_QUESTION_MARK' => "\u{2049}\u{FE0F}", 'CHARACTER_QUESTION_MARK' => "\u{2753}", 'CHARACTER_WHITE_QUESTION_MARK' => "\u{2754}", 'CHARACTER_WHITE_EXCLAMATION_MARK' => "\u{2755}", 'CHARACTER_EXCLAMATION_MARK' => "\u{2757}", 'CHARACTER_WAVY_DASH' => "\u{3030}\u{FE0F}", 'CHARACTER_COPYRIGHT' => "\u{00A9}\u{FE0F}", 'CHARACTER_REGISTERED' => "\u{00AE}\u{FE0F}", 'CHARACTER_TRADE_MARK' => "\u{2122}\u{FE0F}", 'CHARACTER_KEYCAP_HASH' => "\u{0023}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_ASTERISK' => "\u{002A}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_0' => "\u{0030}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_1' => "\u{0031}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_2' => "\u{0032}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_3' => "\u{0033}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_4' => "\u{0034}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_5' => "\u{0035}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_6' => "\u{0036}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_7' => "\u{0037}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_8' => "\u{0038}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_9' => "\u{0039}\u{FE0F}\u{20E3}", 'CHARACTER_KEYCAP_10' => "\u{1F51F}", 'CHARACTER_HUNDRED_POINTS' => "\u{1F4AF}", 'CHARACTER_INPUT_LATIN_UPPERCASE' => "\u{1F520}", 'CHARACTER_INPUT_LATIN_LOWERCASE' => "\u{1F521}", 'CHARACTER_INPUT_NUMBERS' => "\u{1F522}", 'CHARACTER_INPUT_SYMBOLS' => "\u{1F523}", 'CHARACTER_INPUT_LATIN_LETTERS' => "\u{1F524}", 'CHARACTER_A_BUTTON_BLOOD_TYPE' => "\u{1F170}\u{FE0F}", 'CHARACTER_AB_BUTTON_BLOOD_TYPE' => "\u{1F18E}", 'CHARACTER_B_BUTTON_BLOOD_TYPE' => "\u{1F171}\u{FE0F}", 'CHARACTER_CL_BUTTON' => "\u{1F191}", 'CHARACTER_COOL_BUTTON' => "\u{1F192}", 'CHARACTER_FREE_BUTTON' => "\u{1F193}", 'CHARACTER_INFORMATION' => "\u{2139}\u{FE0F}", 'CHARACTER_ID_BUTTON' => "\u{1F194}", 'CHARACTER_CIRCLED_M' => "\u{24C2}\u{FE0F}", 'CHARACTER_NEW_BUTTON' => "\u{1F195}", 'CHARACTER_NG_BUTTON' => "\u{1F196}", 'CHARACTER_O_BUTTON_BLOOD_TYPE' => "\u{1F17E}\u{FE0F}", 'CHARACTER_OK_BUTTON' => "\u{1F197}", 'CHARACTER_P_BUTTON' => "\u{1F17F}\u{FE0F}", 'CHARACTER_SOS_BUTTON' => "\u{1F198}", 'CHARACTER_UP_BUTTON' => "\u{1F199}", 'CHARACTER_VS_BUTTON' => "\u{1F19A}", 'CHARACTER_JAPANESE_HERE_BUTTON' => "\u{1F201}", 'CHARACTER_JAPANESE_SERVICE_CHARGE_BUTTON' => "\u{1F202}\u{FE0F}", 'CHARACTER_JAPANESE_MONTHLY_AMOUNT_BUTTON' => "\u{1F237}\u{FE0F}", 'CHARACTER_JAPANESE_NOT_FREE_OF_CHARGE_BUTTON' => "\u{1F236}", 'CHARACTER_JAPANESE_RESERVED_BUTTON' => "\u{1F22F}", 'CHARACTER_JAPANESE_BARGAIN_BUTTON' => "\u{1F250}", 'CHARACTER_JAPANESE_DISCOUNT_BUTTON' => "\u{1F239}", 'CHARACTER_JAPANESE_FREE_OF_CHARGE_BUTTON' => "\u{1F21A}", 'CHARACTER_JAPANESE_PROHIBITED_BUTTON' => "\u{1F232}", 'CHARACTER_JAPANESE_ACCEPTABLE_BUTTON' => "\u{1F251}", 'CHARACTER_JAPANESE_APPLICATION_BUTTON' => "\u{1F238}", 'CHARACTER_JAPANESE_PASSING_GRADE_BUTTON' => "\u{1F234}", 'CHARACTER_JAPANESE_VACANCY_BUTTON' => "\u{1F233}", 'CHARACTER_JAPANESE_CONGRATULATIONS_BUTTON' => "\u{3297}\u{FE0F}", 'CHARACTER_JAPANESE_SECRET_BUTTON' => "\u{3299}\u{FE0F}", 'CHARACTER_JAPANESE_OPEN_FOR_BUSINESS_BUTTON' => "\u{1F23A}", 'CHARACTER_JAPANESE_NO_VACANCY_BUTTON' => "\u{1F235}", 'CHARACTER_BLACK_SMALL_SQUARE' => "\u{25AA}\u{FE0F}", 'CHARACTER_WHITE_SMALL_SQUARE' => "\u{25AB}\u{FE0F}", 'CHARACTER_WHITE_MEDIUM_SQUARE' => "\u{25FB}\u{FE0F}", 'CHARACTER_BLACK_MEDIUM_SQUARE' => "\u{25FC}\u{FE0F}", 'CHARACTER_WHITE_MEDIUM_SMALL_SQUARE' => "\u{25FD}", 'CHARACTER_BLACK_MEDIUM_SMALL_SQUARE' => "\u{25FE}", 'CHARACTER_BLACK_LARGE_SQUARE' => "\u{2B1B}", 'CHARACTER_WHITE_LARGE_SQUARE' => "\u{2B1C}", 'CHARACTER_LARGE_ORANGE_DIAMOND' => "\u{1F536}", 'CHARACTER_LARGE_BLUE_DIAMOND' => "\u{1F537}", 'CHARACTER_SMALL_ORANGE_DIAMOND' => "\u{1F538}", 'CHARACTER_SMALL_BLUE_DIAMOND' => "\u{1F539}", 'CHARACTER_RED_TRIANGLE_POINTED_UP' => "\u{1F53A}", 'CHARACTER_RED_TRIANGLE_POINTED_DOWN' => "\u{1F53B}", 'CHARACTER_DIAMOND_WITH_A_DOT' => "\u{1F4A0}", 'CHARACTER_RADIO_BUTTON' => "\u{1F518}", 'CHARACTER_BLACK_SQUARE_BUTTON' => "\u{1F532}", 'CHARACTER_WHITE_SQUARE_BUTTON' => "\u{1F533}", 'CHARACTER_WHITE_CIRCLE' => "\u{26AA}", 'CHARACTER_BLACK_CIRCLE' => "\u{26AB}", 'CHARACTER_RED_CIRCLE' => "\u{1F534}", 'CHARACTER_BLUE_CIRCLE' => "\u{1F535}", 'CHARACTER_CHEQUERED_FLAG' => "\u{1F3C1}", 'CHARACTER_TRIANGULAR_FLAG' => "\u{1F6A9}", 'CHARACTER_CROSSED_FLAGS' => "\u{1F38C}", 'CHARACTER_BLACK_FLAG' => "\u{1F3F4}", 'CHARACTER_WHITE_FLAG' => "\u{1F3F3}\u{FE0F}", 'CHARACTER_RAINBOW_FLAG' => "\u{1F3F3}\u{FE0F}\u{200D}\u{1F308}", 'CHARACTER_PIRATE_FLAG' => "\u{1F3F4}\u{200D}\u{2620}\u{FE0F}", 'CHARACTER_FLAGS_FOR_ASCENSION_ISLAND' => "\u{1F1E6}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_ANDORRA' => "\u{1F1E6}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_UNITED_ARAB_EMIRATES' => "\u{1F1E6}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_AFGHANISTAN' => "\u{1F1E6}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_ANTIGUA_AND_BARBUDA' => "\u{1F1E6}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_ANGUILLA' => "\u{1F1E6}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_ALBANIA' => "\u{1F1E6}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_ARMENIA' => "\u{1F1E6}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_ANGOLA' => "\u{1F1E6}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_ANTARCTICA' => "\u{1F1E6}\u{1F1F6}", 'CHARACTER_FLAGS_FOR_ARGENTINA' => "\u{1F1E6}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_AMERICAN_SAMOA' => "\u{1F1E6}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_AUSTRIA' => "\u{1F1E6}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_AUSTRALIA' => "\u{1F1E6}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_ARUBA' => "\u{1F1E6}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_ALAND_ISLANDS' => "\u{1F1E6}\u{1F1FD}", 'CHARACTER_FLAGS_FOR_AZERBAIJAN' => "\u{1F1E6}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_BOSNIA_AND_HERZEGOVINA' => "\u{1F1E7}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_BARBADOS' => "\u{1F1E7}\u{1F1E7}", 'CHARACTER_FLAGS_FOR_BANGLADESH' => "\u{1F1E7}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_BELGIUM' => "\u{1F1E7}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_BURKINA_FASO' => "\u{1F1E7}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_BULGARIA' => "\u{1F1E7}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_BAHRAIN' => "\u{1F1E7}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_BURUNDI' => "\u{1F1E7}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_BENIN' => "\u{1F1E7}\u{1F1EF}", 'CHARACTER_FLAGS_FOR_ST_BARTHELEMY' => "\u{1F1E7}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_BERMUDA' => "\u{1F1E7}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_BRUNEI' => "\u{1F1E7}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_BOLIVIA' => "\u{1F1E7}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_CARIBBEAN_NETHERLANDS' => "\u{1F1E7}\u{1F1F6}", 'CHARACTER_FLAGS_FOR_BRAZIL' => "\u{1F1E7}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_BAHAMAS' => "\u{1F1E7}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_BHUTAN' => "\u{1F1E7}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_BOUVET_ISLAND' => "\u{1F1E7}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_BOTSWANA' => "\u{1F1E7}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_BELARUS' => "\u{1F1E7}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_BELIZE' => "\u{1F1E7}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_CANADA' => "\u{1F1E8}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_COCOS_KEELING_ISLANDS' => "\u{1F1E8}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_CONGO_KINSHASA' => "\u{1F1E8}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_CENTRAL_AFRICAN_REPUBLIC' => "\u{1F1E8}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_CONGO_BRAZZAVILLE' => "\u{1F1E8}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_SWITZERLAND' => "\u{1F1E8}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_COTE_D_IVOIRE' => "\u{1F1E8}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_COOK_ISLANDS' => "\u{1F1E8}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_CHILE' => "\u{1F1E8}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_CAMEROON' => "\u{1F1E8}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_CHINA' => "\u{1F1E8}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_COLOMBIA' => "\u{1F1E8}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_CLIPPERTON_ISLAND' => "\u{1F1E8}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_COSTA_RICA' => "\u{1F1E8}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_CUBA' => "\u{1F1E8}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_CAPE_VERDE' => "\u{1F1E8}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_CURACAO' => "\u{1F1E8}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_CHRISTMAS_ISLAND' => "\u{1F1E8}\u{1F1FD}", 'CHARACTER_FLAGS_FOR_CYPRUS' => "\u{1F1E8}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_CZECHIA' => "\u{1F1E8}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_GERMANY' => "\u{1F1E9}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_DIEGO_GARCIA' => "\u{1F1E9}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_DJIBOUTI' => "\u{1F1E9}\u{1F1EF}", 'CHARACTER_FLAGS_FOR_DENMARK' => "\u{1F1E9}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_DOMINICA' => "\u{1F1E9}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_DOMINICAN_REPUBLIC' => "\u{1F1E9}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_ALGERIA' => "\u{1F1E9}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_CEUTA_AND_MELILLA' => "\u{1F1EA}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_ECUADOR' => "\u{1F1EA}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_ESTONIA' => "\u{1F1EA}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_EGYPT' => "\u{1F1EA}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_WESTERN_SAHARA' => "\u{1F1EA}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_ERITREA' => "\u{1F1EA}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_SPAIN' => "\u{1F1EA}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_ETHIOPIA' => "\u{1F1EA}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_EUROPEAN_UNION' => "\u{1F1EA}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_FINLAND' => "\u{1F1EB}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_FIJI' => "\u{1F1EB}\u{1F1EF}", 'CHARACTER_FLAGS_FOR_FALKLAND_ISLANDS' => "\u{1F1EB}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_MICRONESIA' => "\u{1F1EB}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_FAROE_ISLANDS' => "\u{1F1EB}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_FRANCE' => "\u{1F1EB}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_GABON' => "\u{1F1EC}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_UNITED_KINGDOM' => "\u{1F1EC}\u{1F1E7}", 'CHARACTER_FLAGS_FOR_GRENADA' => "\u{1F1EC}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_GEORGIA' => "\u{1F1EC}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_FRENCH_GUIANA' => "\u{1F1EC}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_GUERNSEY' => "\u{1F1EC}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_GHANA' => "\u{1F1EC}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_GIBRALTAR' => "\u{1F1EC}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_GREENLAND' => "\u{1F1EC}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_GAMBIA' => "\u{1F1EC}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_GUINEA' => "\u{1F1EC}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_GUADELOUPE' => "\u{1F1EC}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_EQUATORIAL_GUINEA' => "\u{1F1EC}\u{1F1F6}", 'CHARACTER_FLAGS_FOR_GREECE' => "\u{1F1EC}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_SOUTH_GEORGIA_AND_SOUTH_SANDWICH_ISLANDS' => "\u{1F1EC}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_GUATEMALA' => "\u{1F1EC}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_GUAM' => "\u{1F1EC}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_GUINEA_BISSAU' => "\u{1F1EC}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_GUYANA' => "\u{1F1EC}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_HONG_KONG_SAR_CHINA' => "\u{1F1ED}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_HEARD_AND_MCDONALD_ISLANDS' => "\u{1F1ED}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_HONDURAS' => "\u{1F1ED}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_CROATIA' => "\u{1F1ED}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_HAITI' => "\u{1F1ED}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_HUNGARY' => "\u{1F1ED}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_CANARY_ISLANDS' => "\u{1F1EE}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_INDONESIA' => "\u{1F1EE}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_IRELAND' => "\u{1F1EE}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_ISRAEL' => "\u{1F1EE}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_ISLE_OF_MAN' => "\u{1F1EE}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_INDIA' => "\u{1F1EE}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_BRITISH_INDIAN_OCEAN_TERRITORY' => "\u{1F1EE}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_IRAQ' => "\u{1F1EE}\u{1F1F6}", 'CHARACTER_FLAGS_FOR_IRAN' => "\u{1F1EE}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_ICELAND' => "\u{1F1EE}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_ITALY' => "\u{1F1EE}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_JERSEY' => "\u{1F1EF}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_JAMAICA' => "\u{1F1EF}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_JORDAN' => "\u{1F1EF}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_JAPAN' => "\u{1F1EF}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_KENYA' => "\u{1F1F0}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_KYRGYZSTAN' => "\u{1F1F0}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_CAMBODIA' => "\u{1F1F0}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_KIRIBATI' => "\u{1F1F0}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_COMOROS' => "\u{1F1F0}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_ST_KITTS_AND_NEVIS' => "\u{1F1F0}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_NORTH_KOREA' => "\u{1F1F0}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_SOUTH_KOREA' => "\u{1F1F0}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_KUWAIT' => "\u{1F1F0}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_CAYMAN_ISLANDS' => "\u{1F1F0}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_KAZAKHSTAN' => "\u{1F1F0}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_LAOS' => "\u{1F1F1}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_LEBANON' => "\u{1F1F1}\u{1F1E7}", 'CHARACTER_FLAGS_FOR_ST_LUCIA' => "\u{1F1F1}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_LIECHTENSTEIN' => "\u{1F1F1}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_SRI_LANKA' => "\u{1F1F1}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_LIBERIA' => "\u{1F1F1}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_LESOTHO' => "\u{1F1F1}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_LITHUANIA' => "\u{1F1F1}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_LUXEMBOURG' => "\u{1F1F1}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_LATVIA' => "\u{1F1F1}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_LIBYA' => "\u{1F1F1}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_MOROCCO' => "\u{1F1F2}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_MONACO' => "\u{1F1F2}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_MOLDOVA' => "\u{1F1F2}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_MONTENEGRO' => "\u{1F1F2}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_ST_MARTIN' => "\u{1F1F2}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_MADAGASCAR' => "\u{1F1F2}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_MARSHALL_ISLANDS' => "\u{1F1F2}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_MACEDONIA' => "\u{1F1F2}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_MALI' => "\u{1F1F2}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_MYANMAR_BURMA' => "\u{1F1F2}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_MONGOLIA' => "\u{1F1F2}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_MACAU_SAR_CHINA' => "\u{1F1F2}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_NORTHERN_MARIANA_ISLANDS' => "\u{1F1F2}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_MARTINIQUE' => "\u{1F1F2}\u{1F1F6}", 'CHARACTER_FLAGS_FOR_MAURITANIA' => "\u{1F1F2}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_MONTSERRAT' => "\u{1F1F2}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_MALTA' => "\u{1F1F2}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_MAURITIUS' => "\u{1F1F2}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_MALDIVES' => "\u{1F1F2}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_MALAWI' => "\u{1F1F2}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_MEXICO' => "\u{1F1F2}\u{1F1FD}", 'CHARACTER_FLAGS_FOR_MALAYSIA' => "\u{1F1F2}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_MOZAMBIQUE' => "\u{1F1F2}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_NAMIBIA' => "\u{1F1F3}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_NEW_CALEDONIA' => "\u{1F1F3}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_NIGER' => "\u{1F1F3}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_NORFOLK_ISLAND' => "\u{1F1F3}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_NIGERIA' => "\u{1F1F3}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_NICARAGUA' => "\u{1F1F3}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_NETHERLANDS' => "\u{1F1F3}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_NORWAY' => "\u{1F1F3}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_NEPAL' => "\u{1F1F3}\u{1F1F5}", 'CHARACTER_FLAGS_FOR_NAURU' => "\u{1F1F3}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_NIUE' => "\u{1F1F3}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_NEW_ZEALAND' => "\u{1F1F3}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_OMAN' => "\u{1F1F4}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_PANAMA' => "\u{1F1F5}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_PERU' => "\u{1F1F5}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_FRENCH_POLYNESIA' => "\u{1F1F5}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_PAPUA_NEW_GUINEA' => "\u{1F1F5}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_PHILIPPINES' => "\u{1F1F5}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_PAKISTAN' => "\u{1F1F5}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_POLAND' => "\u{1F1F5}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_ST_PIERRE_AND_MIQUELON' => "\u{1F1F5}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_PITCAIRN_ISLANDS' => "\u{1F1F5}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_PUERTO_RICO' => "\u{1F1F5}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_PALESTINIAN_TERRITORIES' => "\u{1F1F5}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_PORTUGAL' => "\u{1F1F5}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_PALAU' => "\u{1F1F5}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_PARAGUAY' => "\u{1F1F5}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_QATAR' => "\u{1F1F6}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_REUNION' => "\u{1F1F7}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_ROMANIA' => "\u{1F1F7}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_SERBIA' => "\u{1F1F7}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_RUSSIA' => "\u{1F1F7}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_RWANDA' => "\u{1F1F7}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_SAUDI_ARABIA' => "\u{1F1F8}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_SOLOMON_ISLANDS' => "\u{1F1F8}\u{1F1E7}", 'CHARACTER_FLAGS_FOR_SEYCHELLES' => "\u{1F1F8}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_SUDAN' => "\u{1F1F8}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_SWEDEN' => "\u{1F1F8}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_SINGAPORE' => "\u{1F1F8}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_ST_HELENA' => "\u{1F1F8}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_SLOVENIA' => "\u{1F1F8}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_SVALBARD_AND_JAN_MAYEN' => "\u{1F1F8}\u{1F1EF}", 'CHARACTER_FLAGS_FOR_SLOVAKIA' => "\u{1F1F8}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_SIERRA_LEONE' => "\u{1F1F8}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_SAN_MARINO' => "\u{1F1F8}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_SENEGAL' => "\u{1F1F8}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_SOMALIA' => "\u{1F1F8}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_SURINAME' => "\u{1F1F8}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_SOUTH_SUDAN' => "\u{1F1F8}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_SAO_TOME_AND_PRINCIPE' => "\u{1F1F8}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_EL_SALVADOR' => "\u{1F1F8}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_SINT_MAARTEN' => "\u{1F1F8}\u{1F1FD}", 'CHARACTER_FLAGS_FOR_SYRIA' => "\u{1F1F8}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_SWAZILAND' => "\u{1F1F8}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_TRISTAN_DA_CUNHA' => "\u{1F1F9}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_TURKS_AND_CAICOS_ISLANDS' => "\u{1F1F9}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_CHAD' => "\u{1F1F9}\u{1F1E9}", 'CHARACTER_FLAGS_FOR_FRENCH_SOUTHERN_TERRITORIES' => "\u{1F1F9}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_TOGO' => "\u{1F1F9}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_THAILAND' => "\u{1F1F9}\u{1F1ED}", 'CHARACTER_FLAGS_FOR_TAJIKISTAN' => "\u{1F1F9}\u{1F1EF}", 'CHARACTER_FLAGS_FOR_TOKELAU' => "\u{1F1F9}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_TIMOR_LESTE' => "\u{1F1F9}\u{1F1F1}", 'CHARACTER_FLAGS_FOR_TURKMENISTAN' => "\u{1F1F9}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_TUNISIA' => "\u{1F1F9}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_TONGA' => "\u{1F1F9}\u{1F1F4}", 'CHARACTER_FLAGS_FOR_TURKEY' => "\u{1F1F9}\u{1F1F7}", 'CHARACTER_FLAGS_FOR_TRINIDAD_AND_TOBAGO' => "\u{1F1F9}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_TUVALU' => "\u{1F1F9}\u{1F1FB}", 'CHARACTER_FLAGS_FOR_TAIWAN' => "\u{1F1F9}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_TANZANIA' => "\u{1F1F9}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_UKRAINE' => "\u{1F1FA}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_UGANDA' => "\u{1F1FA}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_US_OUTLYING_ISLANDS' => "\u{1F1FA}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_UNITED_NATIONS' => "\u{1F1FA}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_UNITED_STATES' => "\u{1F1FA}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_URUGUAY' => "\u{1F1FA}\u{1F1FE}", 'CHARACTER_FLAGS_FOR_UZBEKISTAN' => "\u{1F1FA}\u{1F1FF}", 'CHARACTER_FLAGS_FOR_VATICAN_CITY' => "\u{1F1FB}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_ST_VINCENT_AND_GRENADINES' => "\u{1F1FB}\u{1F1E8}", 'CHARACTER_FLAGS_FOR_VENEZUELA' => "\u{1F1FB}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_BRITISH_VIRGIN_ISLANDS' => "\u{1F1FB}\u{1F1EC}", 'CHARACTER_FLAGS_FOR_US_VIRGIN_ISLANDS' => "\u{1F1FB}\u{1F1EE}", 'CHARACTER_FLAGS_FOR_VIETNAM' => "\u{1F1FB}\u{1F1F3}", 'CHARACTER_FLAGS_FOR_VANUATU' => "\u{1F1FB}\u{1F1FA}", 'CHARACTER_FLAGS_FOR_WALLIS_AND_FUTUNA' => "\u{1F1FC}\u{1F1EB}", 'CHARACTER_FLAGS_FOR_SAMOA' => "\u{1F1FC}\u{1F1F8}", 'CHARACTER_FLAGS_FOR_KOSOVO' => "\u{1F1FD}\u{1F1F0}", 'CHARACTER_FLAGS_FOR_YEMEN' => "\u{1F1FE}\u{1F1EA}", 'CHARACTER_FLAGS_FOR_MAYOTTE' => "\u{1F1FE}\u{1F1F9}", 'CHARACTER_FLAGS_FOR_SOUTH_AFRICA' => "\u{1F1FF}\u{1F1E6}", 'CHARACTER_FLAGS_FOR_ZAMBIA' => "\u{1F1FF}\u{1F1F2}", 'CHARACTER_FLAGS_FOR_ZIMBABWE' => "\u{1F1FF}\u{1F1FC}", 'CHARACTER_FLAGS_FOR_ENGLAND' => "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}", 'CHARACTER_FLAGS_FOR_SCOTLAND' => "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}", 'CHARACTER_FLAGS_FOR_WALES' => "\u{1F3F4}\u{E0067}\u{E0062}\u{E0077}\u{E006C}\u{E0073}\u{E007F}"];
<?php return ['ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', 'WINDOWS-1251', 'WINDOWS-1252', 'WINDOWS-1254', 'CP932', 'CP936', 'CP950', 'CP866', 'CP850', 'CP51932', 'CP50220', 'CP50221', 'CP50222', 'ISO-2022-JP', 'ISO-2022-KR', 'JIS', 'JIS-ms', 'EUC-CN', 'EUC-JP', 'ANSI_X3.4-1968', 'ANSI_X3.4-1986', 'ASCII', 'CP367', 'IBM367', 'ISO-IR-6', 'ISO646-US', 'ISO_646.IRV:1991', 'US', 'US-ASCII', 'CSASCII', 'UTF-8', 'ISO-10646-UCS-2', 'UCS-2', 'CSUNICODE', 'UCS-2BE', 'UNICODE-1-1', 'UNICODEBIG', 'CSUNICODE11', 'UCS-2LE', 'UNICODELITTLE', 'ISO-10646-UCS-4', 'UCS-4', 'CSUCS4', 'UCS-4BE', 'UCS-4LE', 'UTF-16', 'UTF-16BE', 'UTF-16LE', 'UTF-32', 'UTF-32BE', 'UTF-32LE', 'UNICODE-1-1-UTF-7', 'UTF-7', 'CSUNICODE11UTF7', 'UCS-2-INTERNAL', 'UCS-2-SWAPPED', 'UCS-4-INTERNAL', 'UCS-4-SWAPPED', 'C99', 'JAVA', 'CP819', 'IBM819', 'ISO-IR-100', 'ISO8859-1', 'ISO_8859-1', 'ISO_8859-1:1987', 'L1', 'LATIN1', 'CSISOLATIN1', 'ISO-IR-101', 'ISO8859-2', 'ISO_8859-2', 'ISO_8859-2:1987', 'L2', 'LATIN2', 'CSISOLATIN2', 'ISO-IR-109', 'ISO8859-3', 'ISO_8859-3', 'ISO_8859-3:1988', 'L3', 'LATIN3', 'CSISOLATIN3', 'ISO-IR-110', 'ISO8859-4', 'ISO_8859-4', 'ISO_8859-4:1988', 'L4', 'LATIN4', 'CSISOLATIN4', 'CYRILLIC', 'ISO-IR-144', 'ISO8859-5', 'ISO_8859-5', 'ISO_8859-5:1988', 'CSISOLATINCYRILLIC', 'ARABIC', 'ASMO-708', 'ECMA-114', 'ISO-IR-127', 'ISO8859-6', 'ISO_8859-6', 'ISO_8859-6:1987', 'CSISOLATINARABIC', 'ECMA-118', 'ELOT_928', 'GREEK', 'GREEK8', 'ISO-IR-126', 'ISO8859-7', 'ISO_8859-7', 'ISO_8859-7:1987', 'ISO_8859-7:2003', 'CSISOLATINGREEK', 'HEBREW', 'ISO-IR-138', 'ISO8859-8', 'ISO_8859-8', 'ISO_8859-8:1988', 'CSISOLATINHEBREW', 'ISO-IR-148', 'ISO8859-9', 'ISO_8859-9', 'ISO_8859-9:1989', 'L5', 'LATIN5', 'CSISOLATIN5', 'ISO-IR-157', 'ISO8859-10', 'ISO_8859-10', 'ISO_8859-10:1992', 'L6', 'LATIN6', 'CSISOLATIN6', 'ISO-8859-11', 'ISO8859-11', 'ISO_8859-11', 'ISO-IR-179', 'ISO8859-13', 'ISO_8859-13', 'L7', 'LATIN7', 'ISO-CELTIC', 'ISO-IR-199', 'ISO8859-14', 'ISO_8859-14', 'ISO_8859-14:1998', 'L8', 'LATIN8', 'ISO-IR-203', 'ISO8859-15', 'ISO_8859-15', 'ISO_8859-15:1998', 'LATIN-9', 'ISO-IR-226', 'ISO8859-16', 'ISO_8859-16', 'ISO_8859-16:2001', 'L10', 'LATIN10', 'KOI8-R', 'CSKOI8R', 'KOI8-U', 'KOI8-RU', 'CP1250', 'MS-EE', 'WINDOWS-1250', 'CP1251', 'MS-CYRL', 'CP1252', 'MS-ANSI', 'CP1253', 'MS-GREEK', 'WINDOWS-1253', 'CP1254', 'MS-TURK', 'CP1255', 'MS-HEBR', 'WINDOWS-1255', 'CP1256', 'MS-ARAB', 'WINDOWS-1256', 'CP1257', 'WINBALTRIM', 'WINDOWS-1257', 'CP1258', 'WINDOWS-1258', '850', 'IBM850', 'CSPC850MULTILINGUAL', '862', 'CP862', 'IBM862', 'CSPC862LATINHEBREW', '866', 'IBM866', 'CSIBM866', 'MAC', 'MACINTOSH', 'MACROMAN', 'CSMACINTOSH', 'MACCENTRALEUROPE', 'MACICELAND', 'MACCROATIAN', 'MACROMANIA', 'MACCYRILLIC', 'MACUKRAINE', 'MACGREEK', 'MACTURKISH', 'MACHEBREW', 'MACARABIC', 'MACTHAI', 'HP-ROMAN8', 'R8', 'ROMAN8', 'CSHPROMAN8', 'NEXTSTEP', 'ARMSCII-8', 'GEORGIAN-ACADEMY', 'GEORGIAN-PS', 'KOI8-T', 'CP154', 'CYRILLIC-ASIAN', 'PT154', 'PTCP154', 'CSPTCP154', 'KZ-1048', 'RK1048', 'STRK1048-2002', 'CSKZ1048', 'MULELAO-1', 'CP1133', 'IBM-CP1133', 'ISO-IR-166', 'TIS-620', 'TIS620', 'TIS620-0', 'TIS620.2529-1', 'TIS620.2533-0', 'TIS620.2533-1', 'CP874', 'WINDOWS-874', 'VISCII', 'VISCII1.1-1', 'CSVISCII', 'TCVN', 'TCVN-5712', 'TCVN5712-1', 'TCVN5712-1:1993', 'ISO-IR-14', 'ISO646-JP', 'JIS_C6220-1969-RO', 'JP', 'CSISO14JISC6220RO', 'JISX0201-1976', 'JIS_X0201', 'X0201', 'CSHALFWIDTHKATAKANA', 'ISO-IR-87', 'JIS0208', 'JIS_C6226-1983', 'JIS_X0208', 'JIS_X0208-1983', 'JIS_X0208-1990', 'X0208', 'CSISO87JISX0208', 'ISO-IR-159', 'JIS_X0212', 'JIS_X0212-1990', 'JIS_X0212.1990-0', 'X0212', 'CSISO159JISX02121990', 'CN', 'GB_1988-80', 'ISO-IR-57', 'ISO646-CN', 'CSISO57GB1988', 'CHINESE', 'GB_2312-80', 'ISO-IR-58', 'CSISO58GB231280', 'CN-GB-ISOIR165', 'ISO-IR-165', 'ISO-IR-149', 'KOREAN', 'KSC_5601', 'KS_C_5601-1987', 'KS_C_5601-1989', 'CSKSC56011987', 'EUCJP', 'EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE', 'CSEUCPKDFMTJAPANESE', 'MS_KANJI', 'SHIFT-JIS', 'SHIFT_JIS', 'SJIS', 'CSSHIFTJIS', 'CSISO2022JP', 'ISO-2022-JP-1', 'ISO-2022-JP-2', 'CSISO2022JP2', 'CN-GB', 'EUCCN', 'GB2312', 'CSGB2312', 'GBK', 'MS936', 'WINDOWS-936', 'GB18030', 'ISO-2022-CN', 'CSISO2022CN', 'ISO-2022-CN-EXT', 'HZ', 'HZ-GB-2312', 'EUC-TW', 'EUCTW', 'CSEUCTW', 'BIG-5', 'BIG-FIVE', 'BIG5', 'BIGFIVE', 'CN-BIG5', 'CSBIG5', 'BIG5-HKSCS:1999', 'BIG5-HKSCS:2001', 'BIG5-HKSCS', 'BIG5-HKSCS:2004', 'BIG5HKSCS', 'EUC-KR', 'EUCKR', 'CSEUCKR', 'CP949', 'UHC', 'CP1361', 'JOHAB', 'CSISO2022KR', 'CP856', 'CP922', 'CP943', 'CP1046', 'CP1124', 'CP1129', 'CP1161', 'IBM-1161', 'IBM1161', 'CSIBM1161', 'CP1162', 'IBM-1162', 'IBM1162', 'CSIBM1162', 'CP1163', 'IBM-1163', 'IBM1163', 'CSIBM1163', 'DEC-KANJI', 'DEC-HANYU', '437', 'CP437', 'IBM437', 'CSPC8CODEPAGE437', 'CP737', 'CP775', 'IBM775', 'CSPC775BALTIC', '852', 'CP852', 'IBM852', 'CSPCP852', 'CP853', '855', 'CP855', 'IBM855', 'CSIBM855', '857', 'CP857', 'IBM857', 'CSIBM857', 'CP858', '860', 'CP860', 'IBM860', 'CSIBM860', '861', 'CP-IS', 'CP861', 'IBM861', 'CSIBM861', '863', 'CP863', 'IBM863', 'CSIBM863', 'CP864', 'IBM864', 'CSIBM864', '865', 'CP865', 'IBM865', 'CSIBM865', '869', 'CP-GR', 'CP869', 'IBM869', 'CSIBM869', 'CP1125', 'EUC-JISX0213', 'SHIFT_JISX0213', 'ISO-2022-JP-3', 'BIG5-2003', 'ISO-IR-230', 'TDS565', 'ATARI', 'ATARIST', 'RISCOS-LATIN1'];
<?php return ['' => 0, "\x00" => 0, "\x01" => 1, "\x02" => 2, "\x03" => 3, "\x04" => 4, "\x05" => 5, "\x06" => 6, "\x07" => 7, "\x08" => 8, "\x09" => 9, "\x0A" => 10, "\x0B" => 11, "\x0C" => 12, "\x0D" => 13, "\x0E" => 14, "\x0F" => 15, "\x10" => 16, "\x11" => 17, "\x12" => 18, "\x13" => 19, "\x14" => 20, "\x15" => 21, "\x16" => 22, "\x17" => 23, "\x18" => 24, "\x19" => 25, "\x1A" => 26, "\x1B" => 27, "\x1C" => 28, "\x1D" => 29, "\x1E" => 30, "\x1F" => 31, "\x20" => 32, "\x21" => 33, "\x22" => 34, "\x23" => 35, "\x24" => 36, "\x25" => 37, "\x26" => 38, "\x27" => 39, "\x28" => 40, "\x29" => 41, "\x2A" => 42, "\x2B" => 43, "\x2C" => 44, "\x2D" => 45, "\x2E" => 46, "\x2F" => 47, "\x30" => 48, "\x31" => 49, "\x32" => 50, "\x33" => 51, "\x34" => 52, "\x35" => 53, "\x36" => 54, "\x37" => 55, "\x38" => 56, "\x39" => 57, "\x3A" => 58, "\x3B" => 59, "\x3C" => 60, "\x3D" => 61, "\x3E" => 62, "\x3F" => 63, "\x40" => 64, "\x41" => 65, "\x42" => 66,  "\x43" => 67,  "\x44" => 68,  "\x45" => 69,  "\x46" => 70,  "\x47" => 71,  "\x48" => 72,  "\x49" => 73,  "\x4A" => 74,  "\x4B" => 75,  "\x4C" => 76,  "\x4D" => 77,  "\x4E" => 78,  "\x4F" => 79,  "\x50" => 80,  "\x51" => 81,  "\x52" => 82,  "\x53" => 83,  "\x54" => 84,  "\x55" => 85,  "\x56" => 86,  "\x57" => 87,  "\x58" => 88,  "\x59" => 89,  "\x5A" => 90,  "\x5B" => 91,  "\x5C" => 92,  "\x5D" => 93,  "\x5E" => 94,  "\x5F" => 95,  "\x60" => 96,  "\x61" => 97,  "\x62" => 98,  "\x63" => 99,  "\x64" => 100,  "\x65" => 101,  "\x66" => 102,  "\x67" => 103,  "\x68" => 104,  "\x69" => 105,  "\x6A" => 106,  "\x6B" => 107,  "\x6C" => 108,  "\x6D" => 109,  "\x6E" => 110,  "\x6F" => 111,  "\x70" => 112,  "\x71" => 113,  "\x72" => 114,  "\x73" => 115,  "\x74" => 116,  "\x75" => 117,  "\x76" => 118,  "\x77" => 119,  "\x78" => 120,  "\x79" => 121,  "\x7A" => 122,  "\x7B" => 123,  "\x7C" => 124,  "\x7D" => 125,  "\x7E" => 126,  "\x7F" => 127,  "\x80" => 128,  "\x81" => 129,  "\x82" => 130,  "\x83" => 131,  "\x84" => 132,  "\x85" => 133,  "\x86" => 134,  "\x87" => 135,  "\x88" => 136,  "\x89" => 137,  "\x8A" => 138,  "\x8B" => 139,  "\x8C" => 140,  "\x8D" => 141,  "\x8E" => 142,  "\x8F" => 143,  "\x90" => 144,  "\x91" => 145,  "\x92" => 146,  "\x93" => 147,  "\x94" => 148,  "\x95" => 149,  "\x96" => 150,  "\x97" => 151,  "\x98" => 152,  "\x99" => 153,  "\x9A" => 154,  "\x9B" => 155,  "\x9C" => 156,  "\x9D" => 157,  "\x9E" => 158,  "\x9F" => 159,  "\xA0" => 160,  "\xA1" => 161,  "\xA2" => 162,  "\xA3" => 163,  "\xA4" => 164,  "\xA5" => 165,  "\xA6" => 166,  "\xA7" => 167,  "\xA8" => 168,  "\xA9" => 169,  "\xAA" => 170,  "\xAB" => 171,  "\xAC" => 172,  "\xAD" => 173,  "\xAE" => 174,  "\xAF" => 175,  "\xB0" => 176,  "\xB1" => 177,  "\xB2" => 178,  "\xB3" => 179,  "\xB4" => 180,  "\xB5" => 181,  "\xB6" => 182,  "\xB7" => 183,  "\xB8" => 184,  "\xB9" => 185,  "\xBA" => 186,  "\xBB" => 187,  "\xBC" => 188,  "\xBD" => 189,  "\xBE" => 190,  "\xBF" => 191,  "\xC0" => 192,  "\xC1" => 193,  "\xC2" => 194,  "\xC3" => 195,  "\xC4" => 196,  "\xC5" => 197,  "\xC6" => 198,  "\xC7" => 199,  "\xC8" => 200,  "\xC9" => 201,  "\xCA" => 202,  "\xCB" => 203,  "\xCC" => 204,  "\xCD" => 205,  "\xCE" => 206,  "\xCF" => 207,  "\xD0" => 208,  "\xD1" => 209,  "\xD2" => 210,  "\xD3" => 211,  "\xD4" => 212,  "\xD5" => 213,  "\xD6" => 214,  "\xD7" => 215,  "\xD8" => 216,  "\xD9" => 217,  "\xDA" => 218,  "\xDB" => 219,  "\xDC" => 220,  "\xDD" => 221,  "\xDE" => 222,  "\xDF" => 223,  "\xE0" => 224,  "\xE1" => 225,  "\xE2" => 226,  "\xE3" => 227,  "\xE4" => 228,  "\xE5" => 229,  "\xE6" => 230,  "\xE7" => 231,  "\xE8" => 232,  "\xE9" => 233,  "\xEA" => 234,  "\xEB" => 235,  "\xEC" => 236,  "\xED" => 237,  "\xEE" => 238,  "\xEF" => 239,  "\xF0" => 240,  "\xF1" => 241,  "\xF2" => 242,  "\xF3" => 243,  "\xF4" => 244,  "\xF5" => 245,  "\xF6" => 246,  "\xF7" => 247,  "\xF8" => 248,  "\xF9" => 249,  "\xFA" => 250,  "\xFB" => 251,  "\xFC" => 252,  "\xFD" => 253,  "\xFE" => 254,  "\xFF" => 255];
<?php return [0 => 'ASCII-Latin', 1 => 'Accents-Any', 2 => 'Amharic-Latin/BGN', 3 => 'Any-Accents', 4 => 'Any-Publishing', 5 => 'Arab-Latn', 6 => 'Arabic-Latin', 7 => 'Arabic-Latin/BGN', 8 => 'Armenian-Latin', 9 => 'Armenian-Latin/BGN', 10 => 'Armn-Latn', 11 => 'Azerbaijani-Latin/BGN', 12 => 'Belarusian-Latin/BGN', 13 => 'Beng-Arab', 14 => 'Beng-Deva', 15 => 'Beng-Gujr', 16 => 'Beng-Guru', 17 => 'Beng-Knda', 18 => 'Beng-Latn', 19 => 'Beng-Mlym', 20 => 'Beng-Orya', 21 => 'Beng-Taml', 22 => 'Beng-Telu', 23 => 'Beng-ur', 24 => 'Bengali-Arabic', 25 => 'Bengali-Devanagari', 26 => 'Bengali-Gujarati', 27 => 'Bengali-Gurmukhi', 28 => 'Bengali-Kannada', 29 => 'Bengali-Latin', 30 => 'Bengali-Malayalam', 31 => 'Bengali-Oriya', 32 => 'Bengali-Tamil', 33 => 'Bengali-Telugu', 34 => 'Bopo-Latn', 35 => 'Bopomofo-Latin', 36 => 'Bulgarian-Latin/BGN', 37 => 'Cyrillic-Latin', 38 => 'Cyrl-Latn', 39 => 'Deva-Arab', 40 => 'Deva-Beng', 41 => 'Deva-Gujr', 42 => 'Deva-Guru', 43 => 'Deva-Knda', 44 => 'Deva-Latn', 45 => 'Deva-Mlym', 46 => 'Deva-Orya', 47 => 'Deva-Taml', 48 => 'Deva-Telu', 49 => 'Deva-ur', 50 => 'Devanagari-Arabic', 51 => 'Devanagari-Bengali', 52 => 'Devanagari-Gujarati', 53 => 'Devanagari-Gurmukhi', 54 => 'Devanagari-Kannada', 55 => 'Devanagari-Latin', 56 => 'Devanagari-Malayalam', 57 => 'Devanagari-Oriya', 58 => 'Devanagari-Tamil', 59 => 'Devanagari-Telugu', 60 => 'Digit-Tone', 61 => 'Fullwidth-Halfwidth', 62 => 'Geor-Latn', 63 => 'Georgian-Latin', 64 => 'Georgian-Latin/BGN', 65 => 'Greek-Latin', 66 => 'Greek-Latin/BGN', 67 => 'Greek-Latin/UNGEGN', 68 => 'Grek-Latn', 69 => 'Grek-Latn/UNGEGN', 70 => 'Gujarati-Arabic', 71 => 'Gujarati-Bengali', 72 => 'Gujarati-Devanagari', 73 => 'Gujarati-Gurmukhi', 74 => 'Gujarati-Kannada', 75 => 'Gujarati-Latin', 76 => 'Gujarati-Malayalam', 77 => 'Gujarati-Oriya', 78 => 'Gujarati-Tamil', 79 => 'Gujarati-Telugu', 80 => 'Gujr-Arab', 81 => 'Gujr-Beng', 82 => 'Gujr-Deva', 83 => 'Gujr-Guru', 84 => 'Gujr-Knda', 85 => 'Gujr-Latn', 86 => 'Gujr-Mlym', 87 => 'Gujr-Orya', 88 => 'Gujr-Taml', 89 => 'Gujr-Telu', 90 => 'Gujr-ur', 91 => 'Gurmukhi-Arabic', 92 => 'Gurmukhi-Bengali', 93 => 'Gurmukhi-Devanagari', 94 => 'Gurmukhi-Gujarati', 95 => 'Gurmukhi-Kannada', 96 => 'Gurmukhi-Latin', 97 => 'Gurmukhi-Malayalam', 98 => 'Gurmukhi-Oriya', 99 => 'Gurmukhi-Tamil', 100 => 'Gurmukhi-Telugu', 101 => 'Guru-Arab', 102 => 'Guru-Beng', 103 => 'Guru-Deva', 104 => 'Guru-Gujr', 105 => 'Guru-Knda', 106 => 'Guru-Latn', 107 => 'Guru-Mlym', 108 => 'Guru-Orya', 109 => 'Guru-Taml', 110 => 'Guru-Telu', 111 => 'Guru-ur', 112 => 'Halfwidth-Fullwidth', 113 => 'Han-Latin', 114 => 'Han-Latin/Names', 115 => 'Hang-Latn', 116 => 'Hangul-Latin', 117 => 'Hani-Latn', 118 => 'Hans-Hant', 119 => 'Hant-Hans', 120 => 'Hebr-Latn', 121 => 'Hebrew-Latin', 122 => 'Hebrew-Latin/BGN', 123 => 'Hira-Kana', 124 => 'Hira-Latn', 125 => 'Hiragana-Katakana', 126 => 'Hiragana-Latin', 127 => 'IPA-XSampa', 128 => 'Jamo-Latin', 129 => 'Jamo-Latn', 130 => 'Kana-Hira', 131 => 'Kana-Latn', 132 => 'Kannada-Arabic', 133 => 'Kannada-Bengali', 134 => 'Kannada-Devanagari', 135 => 'Kannada-Gujarati', 136 => 'Kannada-Gurmukhi', 137 => 'Kannada-Latin', 138 => 'Kannada-Malayalam', 139 => 'Kannada-Oriya', 140 => 'Kannada-Tamil', 141 => 'Kannada-Telugu', 142 => 'Katakana-Hiragana', 143 => 'Katakana-Latin', 144 => 'Katakana-Latin/BGN', 145 => 'Kazakh-Latin/BGN', 146 => 'Kirghiz-Latin/BGN', 147 => 'Knda-Arab', 148 => 'Knda-Beng', 149 => 'Knda-Deva', 150 => 'Knda-Gujr', 151 => 'Knda-Guru', 152 => 'Knda-Latn', 153 => 'Knda-Mlym', 154 => 'Knda-Orya', 155 => 'Knda-Taml', 156 => 'Knda-Telu', 157 => 'Knda-ur', 158 => 'Korean-Latin/BGN', 159 => 'Latin-ASCII', 160 => 'Latin-Arabic', 161 => 'Latin-Armenian', 162 => 'Latin-Bengali', 163 => 'Latin-Bopomofo', 164 => 'Latin-Cyrillic', 165 => 'Latin-Devanagari', 166 => 'Latin-Georgian', 167 => 'Latin-Greek', 168 => 'Latin-Greek/UNGEGN', 169 => 'Latin-Gujarati', 170 => 'Latin-Gurmukhi', 171 => 'Latin-Hangul', 172 => 'Latin-Hebrew', 173 => 'Latin-Hiragana', 174 => 'Latin-Jamo', 175 => 'Latin-Kannada', 176 => 'Latin-Katakana', 177 => 'Latin-Malayalam', 178 => 'Latin-NumericPinyin', 179 => 'Latin-Oriya', 180 => 'Latin-Russian/BGN', 181 => 'Latin-Syriac', 182 => 'Latin-Tamil', 183 => 'Latin-Telugu', 184 => 'Latin-Thaana', 185 => 'Latin-Thai', 186 => 'Latn-Arab', 187 => 'Latn-Armn', 188 => 'Latn-Beng', 189 => 'Latn-Bopo', 190 => 'Latn-Cyrl', 191 => 'Latn-Deva', 192 => 'Latn-Geor', 193 => 'Latn-Grek', 194 => 'Latn-Grek/UNGEGN', 195 => 'Latn-Gujr', 196 => 'Latn-Guru', 197 => 'Latn-Hang', 198 => 'Latn-Hebr', 199 => 'Latn-Hira', 200 => 'Latn-Jamo', 201 => 'Latn-Kana', 202 => 'Latn-Knda', 203 => 'Latn-Mlym', 204 => 'Latn-Orya', 205 => 'Latn-Syrc', 206 => 'Latn-Taml', 207 => 'Latn-Telu', 208 => 'Latn-Thaa', 209 => 'Latn-Thai', 210 => 'Macedonian-Latin/BGN', 211 => 'Malayalam-Arabic', 212 => 'Malayalam-Bengali', 213 => 'Malayalam-Devanagari', 214 => 'Malayalam-Gujarati', 215 => 'Malayalam-Gurmukhi', 216 => 'Malayalam-Kannada', 217 => 'Malayalam-Latin', 218 => 'Malayalam-Oriya', 219 => 'Malayalam-Tamil', 220 => 'Malayalam-Telugu', 221 => 'Maldivian-Latin/BGN', 222 => 'Mlym-Arab', 223 => 'Mlym-Beng', 224 => 'Mlym-Deva', 225 => 'Mlym-Gujr', 226 => 'Mlym-Guru', 227 => 'Mlym-Knda', 228 => 'Mlym-Latn', 229 => 'Mlym-Orya', 230 => 'Mlym-Taml', 231 => 'Mlym-Telu', 232 => 'Mlym-ur', 233 => 'Mongolian-Latin/BGN', 234 => 'NumericPinyin-Latin', 235 => 'NumericPinyin-Pinyin', 236 => 'Oriya-Arabic', 237 => 'Oriya-Bengali', 238 => 'Oriya-Devanagari', 239 => 'Oriya-Gujarati', 240 => 'Oriya-Gurmukhi', 241 => 'Oriya-Kannada', 242 => 'Oriya-Latin', 243 => 'Oriya-Malayalam', 244 => 'Oriya-Tamil', 245 => 'Oriya-Telugu', 246 => 'Orya-Arab', 247 => 'Orya-Beng', 248 => 'Orya-Deva', 249 => 'Orya-Gujr', 250 => 'Orya-Guru', 251 => 'Orya-Knda', 252 => 'Orya-Latn', 253 => 'Orya-Mlym', 254 => 'Orya-Taml', 255 => 'Orya-Telu', 256 => 'Orya-ur', 257 => 'Pashto-Latin/BGN', 258 => 'Persian-Latin/BGN', 259 => 'Pinyin-NumericPinyin', 260 => 'Publishing-Any', 261 => 'Russian-Latin/BGN', 262 => 'Serbian-Latin/BGN', 263 => 'Simplified-Traditional', 264 => 'Syrc-Latn', 265 => 'Syriac-Latin', 266 => 'Tamil-Arabic', 267 => 'Tamil-Bengali', 268 => 'Tamil-Devanagari', 269 => 'Tamil-Gujarati', 270 => 'Tamil-Gurmukhi', 271 => 'Tamil-Kannada', 272 => 'Tamil-Latin', 273 => 'Tamil-Malayalam', 274 => 'Tamil-Oriya', 275 => 'Tamil-Telugu', 276 => 'Taml-Arab', 277 => 'Taml-Beng', 278 => 'Taml-Deva', 279 => 'Taml-Gujr', 280 => 'Taml-Guru', 281 => 'Taml-Knda', 282 => 'Taml-Latn', 283 => 'Taml-Mlym', 284 => 'Taml-Orya', 285 => 'Taml-Telu', 286 => 'Taml-ur', 287 => 'Telu-Arab', 288 => 'Telu-Beng', 289 => 'Telu-Deva', 290 => 'Telu-Gujr', 291 => 'Telu-Guru', 292 => 'Telu-Knda', 293 => 'Telu-Latn', 294 => 'Telu-Mlym', 295 => 'Telu-Orya', 296 => 'Telu-Taml', 297 => 'Telu-ur', 298 => 'Telugu-Arabic', 299 => 'Telugu-Bengali', 300 => 'Telugu-Devanagari', 301 => 'Telugu-Gujarati', 302 => 'Telugu-Gurmukhi', 303 => 'Telugu-Kannada', 304 => 'Telugu-Latin', 305 => 'Telugu-Malayalam', 306 => 'Telugu-Oriya', 307 => 'Telugu-Tamil', 308 => 'Thaa-Latn', 309 => 'Thaana-Latin', 310 => 'Thai-Latin', 311 => 'Thai-Latn', 312 => 'Tone-Digit', 313 => 'Traditional-Simplified', 314 => 'Turkmen-Latin/BGN', 315 => 'Ukrainian-Latin/BGN', 316 => 'Uzbek-Latin/BGN', 317 => 'XSampa-IPA', 318 => 'Zawgyi-my', 319 => 'am-am_FONIPA', 320 => 'am-am_Latn/BGN', 321 => 'am-ar', 322 => 'am-chr', 323 => 'am-fa', 324 => 'am_FONIPA-am', 325 => 'ar-ar_Latn/BGN', 326 => 'az-Lower', 327 => 'az-Title', 328 => 'az-Upper', 329 => 'az_Cyrl-az/BGN', 330 => 'be-be_Latn/BGN', 331 => 'bg-bg_Latn/BGN', 332 => 'blt-blt_FONIPA', 333 => 'ch-am', 334 => 'ch-ar', 335 => 'ch-ch_FONIPA', 336 => 'ch-chr', 337 => 'ch-fa', 338 => 'chr-chr_FONIPA', 339 => 'cs-am', 340 => 'cs-ar', 341 => 'cs-chr', 342 => 'cs-cs_FONIPA', 343 => 'cs-fa', 344 => 'cs-ja', 345 => 'cs-ko', 346 => 'cs_FONIPA-ja', 347 => 'cs_FONIPA-ko', 348 => 'cy-cy_FONIPA', 349 => 'de-ASCII', 350 => 'dsb-dsb_FONIPA', 351 => 'dv-dv_Latn/BGN', 352 => 'el-Lower', 353 => 'el-Title', 354 => 'el-Upper', 355 => 'el-el_Latn/BGN', 356 => 'eo-am', 357 => 'eo-ar', 358 => 'eo-chr', 359 => 'eo-eo_FONIPA', 360 => 'eo-fa', 361 => 'es-am', 362 => 'es-ar', 363 => 'es-chr', 364 => 'es-es_FONIPA', 365 => 'es-fa', 366 => 'es-ja', 367 => 'es-zh', 368 => 'es_419-am', 369 => 'es_419-ar', 370 => 'es_419-chr', 371 => 'es_419-fa', 372 => 'es_419-ja', 373 => 'es_419-zh', 374 => 'es_FONIPA-am', 375 => 'es_FONIPA-es_419_FONIPA', 376 => 'es_FONIPA-ja', 377 => 'es_FONIPA-zh', 378 => 'fa-fa_FONIPA', 379 => 'fa-fa_Latn/BGN', 380 => 'ha-ha_NE', 381 => 'he-he_Latn/BGN', 382 => 'hy-am', 383 => 'hy-ar', 384 => 'hy-chr', 385 => 'hy-fa', 386 => 'hy-hy_FONIPA', 387 => 'hy-hy_Latn/BGN', 388 => 'hy_AREVMDA-am', 389 => 'hy_AREVMDA-ar', 390 => 'hy_AREVMDA-chr', 391 => 'hy_AREVMDA-fa', 392 => 'hy_AREVMDA-hy_AREVMDA_FONIPA', 393 => 'ia-am', 394 => 'ia-ar', 395 => 'ia-chr', 396 => 'ia-fa', 397 => 'ia-ia_FONIPA', 398 => 'it-am', 399 => 'it-ja', 400 => 'ja_Hrkt-ja_Latn/BGN', 401 => 'ja_Latn-ko', 402 => 'ja_Latn-ru', 403 => 'ka-ka_Latn/BGN', 404 => 'ka-ka_Latn/BGN_1981', 405 => 'kk-am', 406 => 'kk-ar', 407 => 'kk-chr', 408 => 'kk-fa', 409 => 'kk-kk_FONIPA', 410 => 'kk-kk_Latn/BGN', 411 => 'ko-ko_Latn/BGN', 412 => 'ky-am', 413 => 'ky-ar', 414 => 'ky-chr', 415 => 'ky-fa', 416 => 'ky-ky_FONIPA', 417 => 'ky-ky_Latn/BGN', 418 => 'la-la_FONIPA', 419 => 'lt-Lower', 420 => 'lt-Title', 421 => 'lt-Upper', 422 => 'mk-mk_Latn/BGN', 423 => 'mn-mn_Latn/BGN', 424 => 'mn-mn_Latn/MNS', 425 => 'my-Zawgyi', 426 => 'my-am', 427 => 'my-ar', 428 => 'my-chr', 429 => 'my-fa', 430 => 'my-my_FONIPA', 431 => 'nl-Title', 432 => 'nv-nv_FONIPA', 433 => 'pl-am', 434 => 'pl-ar', 435 => 'pl-chr', 436 => 'pl-fa', 437 => 'pl-ja', 438 => 'pl-pl_FONIPA', 439 => 'pl_FONIPA-ja', 440 => 'ps-ps_Latn/BGN', 441 => 'rm_SURSILV-am', 442 => 'rm_SURSILV-ar', 443 => 'rm_SURSILV-chr', 444 => 'rm_SURSILV-fa', 445 => 'rm_SURSILV-rm_FONIPA_SURSILV', 446 => 'ro-am', 447 => 'ro-ar', 448 => 'ro-chr', 449 => 'ro-fa', 450 => 'ro-ja', 451 => 'ro-ro_FONIPA', 452 => 'ro_FONIPA-ja', 453 => 'ru-ja', 454 => 'ru-ru_Latn/BGN', 455 => 'ru-zh', 456 => 'ru_Latn-ru/BGN', 457 => 'sat-am', 458 => 'sat-ar', 459 => 'sat-chr', 460 => 'sat-fa', 461 => 'sat_Olck-sat_FONIPA', 462 => 'si-am', 463 => 'si-ar', 464 => 'si-chr', 465 => 'si-fa', 466 => 'si-si_FONIPA', 467 => 'si-si_Latn', 468 => 'sk-am', 469 => 'sk-ar', 470 => 'sk-chr', 471 => 'sk-fa', 472 => 'sk-ja', 473 => 'sk-sk_FONIPA', 474 => 'sk_FONIPA-ja', 475 => 'sr-sr_Latn/BGN', 476 => 'ta-ta_FONIPA', 477 => 'tk_Cyrl-tk/BGN', 478 => 'tlh-am', 479 => 'tlh-ar', 480 => 'tlh-chr', 481 => 'tlh-fa', 482 => 'tlh-tlh_FONIPA', 483 => 'tr-Lower', 484 => 'tr-Title', 485 => 'tr-Upper', 486 => 'ug-ug_FONIPA', 487 => 'uk-uk_Latn/BGN', 488 => 'und_FONIPA-ar', 489 => 'und_FONIPA-chr', 490 => 'und_FONIPA-fa', 491 => 'und_FONIPA-und_FONXSAMP', 492 => 'und_FONXSAMP-und_FONIPA', 493 => 'uz_Cyrl-uz/BGN', 494 => 'uz_Cyrl-uz_Latn', 495 => 'uz_Latn-uz_Cyrl', 496 => 'vec-vec_FONIPA', 497 => 'xh-am', 498 => 'xh-ar', 499 => 'xh-chr', 500 => 'xh-fa', 501 => 'xh-xh_FONIPA', 502 => 'yo-yo_BJ', 503 => 'zh_Latn_PINYIN-ru', 504 => 'zu-am', 505 => 'zu-ar', 506 => 'zu-chr', 507 => 'zu-fa', 508 => 'zu-zu_FONIPA', 509 => 'Any-Null', 510 => 'Any-Lower', 511 => 'Any-Upper', 512 => 'Any-Title', 513 => 'Any-Name', 514 => 'Name-Any', 515 => 'Any-Remove', 516 => 'Any-Hex/Unicode', 517 => 'Any-Hex/Java', 518 => 'Any-Hex/C', 519 => 'Any-Hex/XML', 520 => 'Any-Hex/XML10', 521 => 'Any-Hex/Perl', 522 => 'Any-Hex', 523 => 'Hex-Any/Unicode', 524 => 'Hex-Any/Java', 525 => 'Hex-Any/C', 526 => 'Hex-Any/XML', 527 => 'Hex-Any/XML10', 528 => 'Hex-Any/Perl', 529 => 'Hex-Any', 530 => 'Any-NFC', 531 => 'Any-NFKC', 532 => 'Any-NFD', 533 => 'Any-NFKD', 534 => 'Any-FCD', 535 => 'Any-FCC', 536 => 'Any-fa', 537 => 'Any-ar', 538 => 'Any-chr', 539 => 'Any-rm_FONIPA_SURSILV', 540 => 'Any-am', 541 => 'Any-Latn', 542 => 'Any-dv_Latn/BGN', 543 => 'Any-ro_FONIPA', 544 => 'Any-dsb_FONIPA', 545 => 'Any-Latin', 546 => 'Any-he_Latn/BGN', 547 => 'Any-el_Latn/BGN', 548 => 'Any-eo_FONIPA', 549 => 'Any-si_Latn', 550 => 'Any-si_FONIPA', 551 => 'Any-zh', 552 => 'Any-es_FONIPA', 553 => 'Any-sk_FONIPA', 554 => 'Any-und_FONIPA', 555 => 'Any-und_FONXSAMP', 556 => 'Any-az/BGN', 557 => 'Any-Deva', 558 => 'Any-Arab', 559 => 'Any-Telu', 560 => 'Any-Beng', 561 => 'Any-ur', 562 => 'Any-Orya', 563 => 'Any-Guru', 564 => 'Any-Taml', 565 => 'Any-Gujr', 566 => 'Any-Knda', 567 => 'Any-Armenian', 568 => 'Any-Thaana', 569 => 'Any-Hiragana', 570 => 'Any-Syriac', 571 => 'Any-Jamo', 572 => 'Any-Hangul', 573 => 'Any-Kannada', 574 => 'Any-Georgian', 575 => 'Any-Telugu', 576 => 'Any-Cyrillic', 577 => 'Any-Thai', 578 => 'Any-Oriya', 579 => 'Any-Bopomofo', 580 => 'Any-Malayalam', 581 => 'Any-Gurmukhi', 582 => 'Any-Gujarati', 583 => 'Any-Tamil', 584 => 'Any-Katakana', 585 => 'Any-Hebrew', 586 => 'Any-Bengali', 587 => 'Any-Arabic', 588 => 'Any-Greek', 589 => 'Any-Greek/UNGEGN', 590 => 'Any-Devanagari', 591 => 'Any-fa_FONIPA', 592 => 'Any-fa_Latn/BGN', 593 => 'Any-ta_FONIPA', 594 => 'Any-Mlym', 595 => 'Any-Any', 596 => 'Any-Hant', 597 => 'Any-Hans', 598 => 'Any-uz_Cyrl', 599 => 'Any-blt_FONIPA', 600 => 'Any-ug_FONIPA', 601 => 'Any-uk_Latn/BGN', 602 => 'Any-ha_NE', 603 => 'Any-hy_AREVMDA_FONIPA', 604 => 'Any-hy_FONIPA', 605 => 'Any-hy_Latn/BGN', 606 => 'Any-ia_FONIPA', 607 => 'Any-uz/BGN', 608 => 'Any-uz_Latn', 609 => 'Any-vec_FONIPA', 610 => 'Any-xh_FONIPA', 611 => 'Any-ka_Latn/BGN', 612 => 'Any-ka_Latn/BGN_1981', 613 => 'Any-kk_FONIPA', 614 => 'Any-kk_Latn/BGN', 615 => 'Any-yo_BJ', 616 => 'Any-ky_FONIPA', 617 => 'Any-ky_Latn/BGN', 618 => 'Any-la_FONIPA', 619 => 'Any-ru_Latn/BGN', 620 => 'Any-chr_FONIPA', 621 => 'Any-zu_FONIPA', 622 => 'Any-ru', 623 => 'Any-Geor', 624 => 'Any-Cyrl', 625 => 'Any-Armn', 626 => 'Any-Thaa', 627 => 'Any-Hebr', 628 => 'Any-Grek', 629 => 'Any-Grek/UNGEGN', 630 => 'Any-Syrc', 631 => 'Any-Hira', 632 => 'Any-Hang', 633 => 'Any-Kana', 634 => 'Any-Bopo', 635 => 'Any-mn_Latn/BGN', 636 => 'Any-mn_Latn/MNS', 637 => 'Any-my_FONIPA', 638 => 'Any-sr_Latn/BGN', 639 => 'Any-nv_FONIPA', 640 => 'Any-sat_FONIPA', 641 => 'Any-my', 642 => 'Any-am_FONIPA', 643 => 'Any-am_Latn/BGN', 644 => 'Any-ar_Latn/BGN', 645 => 'Any-mk_Latn/BGN', 646 => 'Any-be_Latn/BGN', 647 => 'Any-bg_Latn/BGN', 648 => 'Any-es_419_FONIPA', 649 => 'Any-pl_FONIPA', 650 => 'Any-ps_Latn/BGN', 651 => 'Any-tk/BGN', 652 => 'Any-ch_FONIPA', 653 => 'Any-cs_FONIPA', 654 => 'Any-cy_FONIPA'];
<?php

// code source:  https://github.com/devgeniem/wp-sanitize-accented-uploads/blob/master/plugin.php#L152
// table source: http://www.i18nqa.com/debug/utf8-debug.html

return [
    // 3 char errors
    'â€š' => '‚',
    'â€ž' => '„',
    'â€¦' => '…',
    'â€¡' => '‡',
    'â€°' => '‰',
    'â€¹' => '‹',
    'â€˜' => '‘',
    'â€™' => '’',
    'â€œ' => '“',
    'â€¢' => '•',
    'â€“' => '–',
    'â€”' => '—',
    'â„¢' => '™',
    'â€º' => '›',
    'â‚¬' => '€',
    // 2 char errors
    "\xc2\x80" => "\xe2\x82\xac", // EURO SIGN
    "\xc2\x82" => "\xe2\x80\x9a", // SINGLE LOW-9 QUOTATION MARK
    "\xc2\x83" => "\xc6\x92", // LATIN SMALL LETTER F WITH HOOK
    "\xc2\x84" => "\xe2\x80\x9e", // DOUBLE LOW-9 QUOTATION MARK
    "\xc2\x85" => "\xe2\x80\xa6", // HORIZONTAL ELLIPSIS
    "\xc2\x86" => "\xe2\x80\xa0", // DAGGER
    "\xc2\x87" => "\xe2\x80\xa1", // DOUBLE DAGGER
    "\xc2\x88" => "\xcb\x86", // MODIFIER LETTER CIRCUMFLEX ACCENT
    "\xc2\x89" => "\xe2\x80\xb0", // PER MILLE SIGN
    "\xc2\x8a" => "\xc5\xa0", // LATIN CAPITAL LETTER S WITH CARON
    "\xc2\x8b" => "\xe2\x80\xb9", // SINGLE LEFT-POINTING ANGLE QUOTE
    "\xc2\x8c" => "\xc5\x92", // LATIN CAPITAL LIGATURE OE
    "\xc2\x8e" => "\xc5\xbd", // LATIN CAPITAL LETTER Z WITH CARON
    "\xc2\x91" => "\xe2\x80\x98", // LEFT SINGLE QUOTATION MARK
    "\xc2\x92" => "\xe2\x80\x99", // RIGHT SINGLE QUOTATION MARK
    "\xc2\x93" => "\xe2\x80\x9c", // LEFT DOUBLE QUOTATION MARK
    "\xc2\x94" => "\xe2\x80\x9d", // RIGHT DOUBLE QUOTATION MARK
    "\xc2\x95" => "\xe2\x80\xa2", // BULLET
    "\xc2\x96" => "\xe2\x80\x93", // EN DASH
    "\xc2\x97" => "\xe2\x80\x94", // EM DASH
    "\xc2\x98" => "\xcb\x9c", // SMALL TILDE
    'Ã‚'       => 'Â',
    'Æ’'       => 'ƒ',
    'Ãƒ'       => 'Ã',
    'Ã„'       => 'Ä',
    'Ã…'       => 'Å',
    //'â€'       => '†', // duplicate key
    'Ã†' => 'Æ',
    'Ã‡' => 'Ç',
    'Ë†' => 'ˆ',
    'Ãˆ' => 'È',
    'Ã‰' => 'É',
    'ÃŠ' => 'Ê',
    'Ã‹' => 'Ë',
    'Å’' => 'Œ',
    'ÃŒ' => 'Ì',
    'Å½' => 'Ž',
    'ÃŽ' => 'Î',
    'Ã‘' => 'Ñ',
    'Ã’' => 'Ò',
    'Ã“' => 'Ó',
    'â€' => '”',
    'Ã”' => 'Ô',
    'Ã•' => 'Õ',
    'Ã–' => 'Ö',
    'Ã—' => '×',
    'Ëœ' => '˜',
    'Ã˜' => 'Ø',
    'Ã™' => 'Ù',
    'Å¡' => 'š',
    'Ãš' => 'Ú',
    'Ã›' => 'Û',
    'Å“' => 'œ',
    'Ãœ' => 'Ü',
    'Å¾' => 'ž',
    'Ãž' => 'Þ',
    'Å¸' => 'Ÿ',
    'ÃŸ' => 'ß',
    'Â¡' => '¡',
    'Ã¡' => 'á',
    'Â¢' => '¢',
    'Ã¢' => 'â',
    'Â£' => '£',
    'Ã£' => 'ã',
    'Â¤' => '¤',
    'Ã¤' => 'ä',
    'Â¥' => '¥',
    'Ã¥' => 'å',
    'Â¦' => '¦',
    'Ã¦' => 'æ',
    'Â§' => '§',
    'Ã§' => 'ç',
    'Â¨' => '¨',
    'Ã¨' => 'è',
    'Â©' => '©',
    'Ã©' => 'é',
    'Âª' => 'ª',
    'Ãª' => 'ê',
    'Â«' => '«',
    'Ã«' => 'ë',
    'Â¬' => '¬',
    'Ã¬' => 'ì',
    'Â®' => '®',
    'Ã®' => 'î',
    'Â¯' => '¯',
    'Ã¯' => 'ï',
    'Â°' => '°',
    'Ã°' => 'ð',
    'Â±' => '±',
    'Ã±' => 'ñ',
    'Â²' => '²',
    'Ã²' => 'ò',
    'Â³' => '³',
    'Ã³' => 'ó',
    'Â´' => '´',
    'Ã´' => 'ô',
    'Âµ' => 'µ',
    'Ãµ' => 'õ',
    'Â¶' => '¶',
    'Ã¶' => 'ö',
    'Â·' => '·',
    'Ã·' => '÷',
    'Â¸' => '¸',
    'Ã¸' => 'ø',
    'Â¹' => '¹',
    'Ã¹' => 'ù',
    'Âº' => 'º',
    'Ãº' => 'ú',
    'Â»' => '»',
    'Ã»' => 'û',
    'Â¼' => '¼',
    'Ã¼' => 'ü',
    'Â½' => '½',
    'Ã½' => 'ý',
    'Â¾' => '¾',
    'Ã¾' => 'þ',
    'Â¿' => '¿',
    'Ã¿' => 'ÿ',
    'Ã€' => 'À',
    // 1 char errors last (don't use them, because of false-positives)
    //'Ã'        => 'Á',
    //'Å'        => 'Š',
    //'Ã'        => 'Í',
    //'Ã'        => 'Ï',
    //'Ã'        => 'Ð',
    //'Ã'        => 'Ý',
    //'Ã'        => 'à',
    //'Ã'        => 'í',
];
<?php

return [
    0x80 => "\xe2\x82\xac", // €
    0x82 => "\xe2\x80\x9a", // ‚
    0x83 => "\xc6\x92",     // ƒ
    0x84 => "\xe2\x80\x9e", // „
    0x85 => "\xe2\x80\xa6", // …
    0x86 => "\xe2\x80\xa0", // †
    0x87 => "\xe2\x80\xa1", // ‡
    0x88 => "\xcb\x86",     // ˆ
    0x89 => "\xe2\x80\xb0", // ‰
    0x8a => "\xc5\xa0",     // Š
    0x8b => "\xe2\x80\xb9", // ‹
    0x8c => "\xc5\x92",     // Œ
    0x8e => "\xc5\xbd",     // Ž
    0x91 => "\xe2\x80\x98", // ‘
    0x92 => "\xe2\x80\x99", // ’
    0x93 => "\xe2\x80\x9c", // “
    0x94 => "\xe2\x80\x9d", // ”
    0x95 => "\xe2\x80\xa2", // •
    0x96 => "\xe2\x80\x93", // –
    0x97 => "\xe2\x80\x94", // —
    0x98 => "\xcb\x9c",     // ˜
    0x99 => "\xe2\x84\xa2", // ™
    0x9a => "\xc5\xa1",     // š
    0x9b => "\xe2\x80\xba", // ›
    0x9c => "\xc5\x93",     // œ
    0x9e => "\xc5\xbe",     // ž
    0x9f => "\xc5\xb8",     // Ÿ
    0xa0 => "\xc2\xa0",
    0xa1 => "\xc2\xa1",     // ¡
    0xa2 => "\xc2\xa2",     // ¢
    0xa3 => "\xc2\xa3",     // £
    0xa4 => "\xc2\xa4",     // ¤
    0xa5 => "\xc2\xa5",     // ¥
    0xa6 => "\xc2\xa6",     // ¦
    0xa7 => "\xc2\xa7",     // §
    0xa8 => "\xc2\xa8",     // ¨
    0xa9 => "\xc2\xa9",     // ©
    0xaa => "\xc2\xaa",     // ª
    0xab => "\xc2\xab",     // «
    0xac => "\xc2\xac",     // ¬
    0xad => "\xc2\xad",     // ­
    0xae => "\xc2\xae",     // ®
    0xaf => "\xc2\xaf",     // ¯
    0xb0 => "\xc2\xb0",     // °
    0xb1 => "\xc2\xb1",     // ±
    0xb2 => "\xc2\xb2",     // ²
    0xb3 => "\xc2\xb3",     // ³
    0xb4 => "\xc2\xb4",     // ´
    0xb5 => "\xc2\xb5",     // µ
    0xb6 => "\xc2\xb6",     // ¶
    0xb7 => "\xc2\xb7",     // ·
    0xb8 => "\xc2\xb8",     // ¸
    0xb9 => "\xc2\xb9",     // ¹
    0xba => "\xc2\xba",     // º
    0xbb => "\xc2\xbb",     // »
    0xbc => "\xc2\xbc",     // ¼
    0xbd => "\xc2\xbd",     // ½
    0xbe => "\xc2\xbe",     // ¾
    0xbf => "\xc2\xbf",     // ¿
    0xc0 => "\xc3\x80",     // À
    0xc1 => "\xc3\x81",     // Á
    0xc2 => "\xc3\x82",     // Â
    0xc3 => "\xc3\x83",     // Ã
    0xc4 => "\xc3\x84",     // Ä
    0xc5 => "\xc3\x85",     // Å
    0xc6 => "\xc3\x86",     // Æ
    0xc7 => "\xc3\x87",     // Ç
    0xc8 => "\xc3\x88",     // È
    0xc9 => "\xc3\x89",     // É
    0xca => "\xc3\x8a",     // Ê
    0xcb => "\xc3\x8b",     // Ë
    0xcc => "\xc3\x8c",     // Ì
    0xcd => "\xc3\x8d",     // Í
    0xce => "\xc3\x8e",     // Î
    0xcf => "\xc3\x8f",     // Ï
    0xd0 => "\xc3\x90",     // Ð
    0xd1 => "\xc3\x91",     // Ñ
    0xd2 => "\xc3\x92",     // Ò
    0xd3 => "\xc3\x93",     // Ó
    0xd4 => "\xc3\x94",     // Ô
    0xd5 => "\xc3\x95",     // Õ
    0xd6 => "\xc3\x96",     // Ö
    0xd7 => "\xc3\x97",     // ×
    0xd8 => "\xc3\x98",     // Ø
    0xd9 => "\xc3\x99",     // Ù
    0xda => "\xc3\x9a",     // Ú
    0xdb => "\xc3\x9b",     // Û
    0xdc => "\xc3\x9c",     // Ü
    0xdd => "\xc3\x9d",     // Ý
    0xde => "\xc3\x9e",     // Þ
    0xdf => "\xc3\x9f",     // ß
    0xe0 => "\xc3\xa0",     // à
    0xe1 => "\xc3\xa1",     // á
    0xe2 => "\xc3\xa2",     // â
    0xe3 => "\xc3\xa3",     // ã
    0xe4 => "\xc3\xa4",     // ä
    0xe5 => "\xc3\xa5",     // å
    0xe6 => "\xc3\xa6",     // æ
    0xe7 => "\xc3\xa7",     // ç
    0xe8 => "\xc3\xa8",     // è
    0xe9 => "\xc3\xa9",     // é
    0xea => "\xc3\xaa",     // ê
    0xeb => "\xc3\xab",     // ë
    0xec => "\xc3\xac",     // ì
    0xed => "\xc3\xad",     // í
    0xee => "\xc3\xae",     // î
    0xef => "\xc3\xaf",     // ï
    0xf0 => "\xc3\xb0",     // ð
    0xf1 => "\xc3\xb1",     // ñ
    0xf2 => "\xc3\xb2",     // ò
    0xf3 => "\xc3\xb3",     // ó
    0xf4 => "\xc3\xb4",     // ô
    0xf5 => "\xc3\xb5",     // õ
    0xf6 => "\xc3\xb6",     // ö
    0xf7 => "\xc3\xb7",     // ÷
    0xf8 => "\xc3\xb8",     // ø
    0xf9 => "\xc3\xb9",     // ù
    0xfa => "\xc3\xba",     // ú
    0xfb => "\xc3\xbb",     // û
    0xfc => "\xc3\xbc",     // ü
    0xfd => "\xc3\xbd",     // ý
    0xfe => "\xc3\xbe",     // þ
];
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * ## 🇷🇺 Русским гражданам
 * В Украине сейчас идет война. Силами РФ наносятся удары по гражданской инфраструктуре в [Харькове][1], [Киеве][2], [Чернигове][3], [Сумах][4], [Ирпене][5] и десятках других городов. Гибнут люди - и гражданское население, и военные, в том числе российские призывники, которых бросили воевать. Чтобы лишить собственный народ доступа к информации, правительство РФ запретило называть войну войной, закрыло независимые СМИ и принимает сейчас ряд диктаторских законов. Эти законы призваны заткнуть рот всем, кто против войны. За обычный призыв к миру сейчас можно получить несколько лет тюрьмы.
 * Не молчите! Молчание - знак вашего согласия с политикой российского правительства.
 *  **Вы можете сделать выбор НЕ МОЛЧАТЬ.**
 * ---
 * ## 🇺🇸 To people of Russia
 * There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilian infrastructure in [Kharkiv][1], [Kyiv][2], [Chernihiv][3], [Sumy][4], [Irpin][5] and dozens of other cities. People are dying – both civilians and military servicemen, including Russian conscripts who were thrown into the fighting. In order to deprive its own people of access to information, the government of the Russian Federation has forbidden calling a war a war, shut down independent media and is passing a number of dictatorial laws. These laws are meant to silence all those who are against war. You can be jailed for multiple years for simply calling for peace.
 * Do not be silent! Silence is a sign that you accept the Russian government's policy.
 * **You can choose NOT TO BE SILENT.**
 * ---
 * - [1] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/P7K2MSZDGFMIJPDD7CI2GIROJI.jpg "Kharkiv under attack"
 * - [2] https://gdb.voanews.com/01bd0000-0aff-0242-fad0-08d9fc92c5b3_cx0_cy5_cw0_w1023_r1_s.jpg "Kyiv under attack"
 * - [3] https://ichef.bbci.co.uk/news/976/cpsprodpb/163DD/production/_123510119_hi074310744.jpg "Chernihiv under attack"
 * - [4] https://www.youtube.com/watch?v=8K-bkqKKf2A "Sumy under attack"
 * - [5] https://cloudfront-us-east-2.images.arcpublishing.com/reuters/K4MTMLEHTRKGFK3GSKAT4GR3NE.jpg "Irpin under attack"
 *
 * @immutable
 */
final class UTF8
{
    /**
     * Bom => Byte-Length
     *
     * INFO: https://en.wikipedia.org/wiki/Byte_order_mark
     *
     * @var array<string, int>
     */
    private static $BOM = [
        "\xef\xbb\xbf"     => 3, // UTF-8 BOM
        'ï»¿'              => 6, // UTF-8 BOM as "WINDOWS-1252" (one char has [maybe] more then one byte ...)
        "\x00\x00\xfe\xff" => 4, // UTF-32 (BE) BOM
        '  þÿ'             => 6, // UTF-32 (BE) BOM as "WINDOWS-1252"
        "\xff\xfe\x00\x00" => 4, // UTF-32 (LE) BOM
        'ÿþ  '             => 6, // UTF-32 (LE) BOM as "WINDOWS-1252"
        "\xfe\xff"         => 2, // UTF-16 (BE) BOM
        'þÿ'               => 4, // UTF-16 (BE) BOM as "WINDOWS-1252"
        "\xff\xfe"         => 2, // UTF-16 (LE) BOM
        'ÿþ'               => 4, // UTF-16 (LE) BOM as "WINDOWS-1252"
    ];

    /**
     * Numeric code point => UTF-8 Character
     *
     * url: http://www.w3schools.com/charsets/ref_utf_punctuation.asp
     *
     * @var array<int, string>
     */
    private static $WHITESPACE = [
        // NULL Byte
        0 => "\x0",
        // Tab
        9 => "\x9",
        // New Line
        10 => "\xa",
        // Vertical Tab
        11 => "\xb",
        // Carriage Return
        13 => "\xd",
        // Ordinary Space
        32 => "\x20",
        // NO-BREAK SPACE
        160 => "\xc2\xa0",
        // OGHAM SPACE MARK
        5760 => "\xe1\x9a\x80",
        // MONGOLIAN VOWEL SEPARATOR
        6158 => "\xe1\xa0\x8e",
        // EN QUAD
        8192 => "\xe2\x80\x80",
        // EM QUAD
        8193 => "\xe2\x80\x81",
        // EN SPACE
        8194 => "\xe2\x80\x82",
        // EM SPACE
        8195 => "\xe2\x80\x83",
        // THREE-PER-EM SPACE
        8196 => "\xe2\x80\x84",
        // FOUR-PER-EM SPACE
        8197 => "\xe2\x80\x85",
        // SIX-PER-EM SPACE
        8198 => "\xe2\x80\x86",
        // FIGURE SPACE
        8199 => "\xe2\x80\x87",
        // PUNCTUATION SPACE
        8200 => "\xe2\x80\x88",
        // THIN SPACE
        8201 => "\xe2\x80\x89",
        // HAIR SPACE
        8202 => "\xe2\x80\x8a",
        // LINE SEPARATOR
        8232 => "\xe2\x80\xa8",
        // PARAGRAPH SEPARATOR
        8233 => "\xe2\x80\xa9",
        // NARROW NO-BREAK SPACE
        8239 => "\xe2\x80\xaf",
        // MEDIUM MATHEMATICAL SPACE
        8287 => "\xe2\x81\x9f",
        // HALFWIDTH HANGUL FILLER
        65440 => "\xef\xbe\xa0",
        // IDEOGRAPHIC SPACE
        12288 => "\xe3\x80\x80",
    ];

    /**
     * @var array<string, string>
     */
    private static $WHITESPACE_TABLE = [
        'SPACE'                     => "\x20",
        'NO-BREAK SPACE'            => "\xc2\xa0",
        'OGHAM SPACE MARK'          => "\xe1\x9a\x80",
        'EN QUAD'                   => "\xe2\x80\x80",
        'EM QUAD'                   => "\xe2\x80\x81",
        'EN SPACE'                  => "\xe2\x80\x82",
        'EM SPACE'                  => "\xe2\x80\x83",
        'THREE-PER-EM SPACE'        => "\xe2\x80\x84",
        'FOUR-PER-EM SPACE'         => "\xe2\x80\x85",
        'SIX-PER-EM SPACE'          => "\xe2\x80\x86",
        'FIGURE SPACE'              => "\xe2\x80\x87",
        'PUNCTUATION SPACE'         => "\xe2\x80\x88",
        'THIN SPACE'                => "\xe2\x80\x89",
        'HAIR SPACE'                => "\xe2\x80\x8a",
        'LINE SEPARATOR'            => "\xe2\x80\xa8",
        'PARAGRAPH SEPARATOR'       => "\xe2\x80\xa9",
        'ZERO WIDTH SPACE'          => "\xe2\x80\x8b",
        'NARROW NO-BREAK SPACE'     => "\xe2\x80\xaf",
        'MEDIUM MATHEMATICAL SPACE' => "\xe2\x81\x9f",
        'IDEOGRAPHIC SPACE'         => "\xe3\x80\x80",
        'HALFWIDTH HANGUL FILLER'   => "\xef\xbe\xa0",
    ];

    /**
     * @var array
     *
     * @phpstan-var array{upper: string[], lower: string[]}
     */
    private static $COMMON_CASE_FOLD = [
        'upper' => [
            'µ',
            'ſ',
            "\xCD\x85",
            'ς',
            'ẞ',
            "\xCF\x90",
            "\xCF\x91",
            "\xCF\x95",
            "\xCF\x96",
            "\xCF\xB0",
            "\xCF\xB1",
            "\xCF\xB5",
            "\xE1\xBA\x9B",
            "\xE1\xBE\xBE",
        ],
        'lower' => [
            'μ',
            's',
            'ι',
            'σ',
            'ß',
            'β',
            'θ',
            'φ',
            'π',
            'κ',
            'ρ',
            'ε',
            "\xE1\xB9\xA1",
            'ι',
        ],
    ];

    /**
     * @var array
     *
     * @phpstan-var array<string, mixed>
     */
    private static $SUPPORT = [];

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string, string>|null
     */
    private static $BROKEN_UTF8_FIX;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<int, string>|null
     */
    private static $WIN1252_TO_UTF8;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<int ,string>|null
     */
    private static $INTL_TRANSLITERATOR_LIST;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string>|null
     */
    private static $ENCODINGS;

    /**
     * @var int[]|null
     *
     * @phpstan-var array<string ,int>|null
     */
    private static $ORD;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string, string>|null
     */
    private static $EMOJI;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string>|null
     */
    private static $EMOJI_VALUES_CACHE;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string>|null
     */
    private static $EMOJI_KEYS_CACHE;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<string>|null
     */
    private static $EMOJI_KEYS_REVERSIBLE_CACHE;

    /**
     * @var string[]|null
     *
     * @phpstan-var array<int, string>|null
     */
    private static $CHR;

    /**
     * __construct()
     */
    public function __construct()
    {
    }

    /**
     * Return the character at the specified position: $str[1] like functionality.
     *
     * EXAMPLE: <code>UTF8::access('fòô', 1); // 'ò'</code>
     *
     * @param string $str      <p>A UTF-8 string.</p>
     * @param int    $pos      <p>The position of character to return.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Single multi-byte character.</p>
     */
    public static function access(string $str, int $pos, string $encoding = 'UTF-8'): string
    {
        if ($str === '' || $pos < 0) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str, $pos, 1);
        }

        return (string) self::substr($str, $pos, 1, $encoding);
    }

    /**
     * Prepends UTF-8 BOM character to the string and returns the whole string.
     *
     * INFO: If BOM already existed there, the Input string is returned.
     *
     * EXAMPLE: <code>UTF8::add_bom_to_string('fòô'); // "\xEF\xBB\xBF" . 'fòô'</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return non-empty-string
     *                           <p>The output string that contains BOM.</p>
     */
    public static function add_bom_to_string(string $str): string
    {
        if (!self::string_has_bom($str)) {
            $str = self::bom() . $str;
        }

        \assert($str !== '');

        return $str;
    }

    /**
     * Changes all keys in an array.
     *
     * @param array<string, mixed> $array    <p>The array to work on</p>
     * @param int                  $case     [optional] <p> Either <strong>CASE_UPPER</strong><br>
     *                                       or <strong>CASE_LOWER</strong> (default)</p>
     * @param string               $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string[]
     *                  <p>An array with its keys lower- or uppercased.</p>
     */
    public static function array_change_key_case(
        array $array,
        int $case = \CASE_LOWER,
        string $encoding = 'UTF-8'
    ): array {
        if (
            $case !== \CASE_LOWER
            &&
            $case !== \CASE_UPPER
        ) {
            $case = \CASE_LOWER;
        }

        $return = [];
        foreach ($array as $key => &$value) {
            $key = $case === \CASE_LOWER
                ? self::strtolower($key, $encoding)
                : self::strtoupper($key, $encoding);

            $return[$key] = $value;
        }

        return $return;
    }

    /**
     * Returns the substring between $start and $end, if found, or an empty
     * string. An optional offset may be supplied from which to begin the
     * search for the start string.
     *
     * @param string $str
     * @param string $start    <p>Delimiter marking the start of the substring.</p>
     * @param string $end      <p>Delimiter marking the end of the substring.</p>
     * @param int    $offset   [optional] <p>Index from which to begin the search. Default: 0</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function between(
        string $str,
        string $start,
        string $end,
        int $offset = 0,
        string $encoding = 'UTF-8'
    ): string {
        if ($encoding === 'UTF-8') {
            $start_position = \mb_strpos($str, $start, $offset);
            if ($start_position === false) {
                return '';
            }

            $substr_index = $start_position + (int) \mb_strlen($start);
            $end_position = \mb_strpos($str, $end, $substr_index);
            if (
                $end_position === false
                ||
                $end_position === $substr_index
            ) {
                return '';
            }

            return (string) \mb_substr($str, $substr_index, $end_position - $substr_index);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        $start_position = self::strpos($str, $start, $offset, $encoding);
        if ($start_position === false) {
            return '';
        }

        $substr_index = $start_position + (int) self::strlen($start, $encoding);
        $end_position = self::strpos($str, $end, $substr_index, $encoding);
        if (
            $end_position === false
            ||
            $end_position === $substr_index
        ) {
            return '';
        }

        return (string) self::substr(
            $str,
            $substr_index,
            $end_position - $substr_index,
            $encoding
        );
    }

    /**
     * Convert binary into a string.
     *
     * INFO: opposite to UTF8::str_to_binary()
     *
     * EXAMPLE: <code>UTF8::binary_to_str('11110000100111111001100010000011'); // '😃'</code>
     *
     * @param string $bin 1|0
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function binary_to_str($bin): string
    {
        if (!isset($bin[0])) {
            return '';
        }

        $convert = \base_convert($bin, 2, 16);
        if ($convert === '0') {
            return '';
        }

        return \pack('H*', $convert);
    }

    /**
     * Returns the UTF-8 Byte Order Mark Character.
     *
     * INFO: take a look at UTF8::$bom for e.g. UTF-16 and UTF-32 BOM values
     *
     * EXAMPLE: <code>UTF8::bom(); // "\xEF\xBB\xBF"</code>
     *
     * @psalm-pure
     *
     * @return non-empty-string
     *                           <p>UTF-8 Byte Order Mark.</p>
     */
    public static function bom(): string
    {
        return "\xef\xbb\xbf";
    }

    /**
     * @alias of UTF8::chr_map()
     *
     * @param callable(string): string $callback
     * @param string   $str
     *
     * @psalm-pure
     *
     * @return string[]
     *
     * @see   UTF8::chr_map()
     */
    public static function callback($callback, string $str): array
    {
        return self::chr_map($callback, $str);
    }

    /**
     * Returns the character at $index, with indexes starting at 0.
     *
     * @param string      $str        <p>The input string.</p>
     * @param int<1, max> $index <p>Position of the character.</p>
     * @param string      $encoding   [optional] <p>Default is UTF-8</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The character at $index.</p>
     */
    public static function char_at(string $str, int $index, string $encoding = 'UTF-8'): string
    {
        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str, $index, 1);
        }

        return (string) self::substr($str, $index, 1, $encoding);
    }

    /**
     * Returns an array consisting of the characters in the string.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return string[]
     *                  <p>An array of chars.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-list<string> : list<string>)
     */
    public static function chars(string $str): array
    {
        return self::str_split($str);
    }

    /**
     * This method will auto-detect your server environment for UTF-8 support.
     *
     * @return true|null
     *
     * @internal <p>You don't need to run it manually, it will be triggered if it's needed.</p>
     */
    public static function checkForSupport()
    {
        if (!isset(self::$SUPPORT['already_checked_via_portable_utf8'])) {
            self::$SUPPORT['already_checked_via_portable_utf8'] = true;

            // http://php.net/manual/en/book.mbstring.php
            self::$SUPPORT['mbstring'] = self::mbstring_loaded();

            self::$SUPPORT['mbstring_func_overload'] = self::mbstring_overloaded();
            if (self::$SUPPORT['mbstring'] === true) {
                \mb_internal_encoding('UTF-8');
                \mb_regex_encoding('UTF-8');
                self::$SUPPORT['mbstring_internal_encoding'] = 'UTF-8';
            }

            // http://php.net/manual/en/book.iconv.php
            self::$SUPPORT['iconv'] = self::iconv_loaded();

            // http://php.net/manual/en/book.intl.php
            self::$SUPPORT['intl'] = self::intl_loaded();

            // http://php.net/manual/en/class.intlchar.php
            self::$SUPPORT['intlChar'] = self::intlChar_loaded();

            // http://php.net/manual/en/book.ctype.php
            self::$SUPPORT['ctype'] = self::ctype_loaded();

            // http://php.net/manual/en/class.finfo.php
            self::$SUPPORT['finfo'] = self::finfo_loaded();

            // http://php.net/manual/en/book.json.php
            self::$SUPPORT['json'] = self::json_loaded();

            // http://php.net/manual/en/book.pcre.php
            self::$SUPPORT['pcre_utf8'] = self::pcre_utf8_support();

            self::$SUPPORT['symfony_polyfill_used'] = self::symfony_polyfill_used();
            if (self::$SUPPORT['symfony_polyfill_used'] === true) {
                \mb_internal_encoding('UTF-8');
                self::$SUPPORT['mbstring_internal_encoding'] = 'UTF-8';
            }

            return true;
        }

        return null;
    }

    /**
     * Generates a UTF-8 encoded character from the given code point.
     *
     * INFO: opposite to UTF8::ord()
     *
     * EXAMPLE: <code>UTF8::chr(0x2603); // '☃'</code>
     *
     * @param int    $code_point <p>The code point for which to generate a character.</p>
     * @param string $encoding   [optional] <p>Default is UTF-8</p>
     *
     * @psalm-pure
     *
     * @return string|null
     *                     <p>Multi-byte character, returns null on failure or empty input.</p>
     */
    public static function chr($code_point, string $encoding = 'UTF-8')
    {
        // init
        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<string,string>
         */
        static $CHAR_CACHE = [];

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if (
            $encoding !== 'UTF-8'
            &&
            $encoding !== 'ISO-8859-1'
            &&
            $encoding !== 'WINDOWS-1252'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::chr() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        if (
            !\is_int($code_point) /* @phpstan-ignore-line | hack for bad inputs */
            ||
            $code_point <= 0
        ) {
            return null;
        }

        $cache_key = $code_point . '_' . $encoding;
        if (isset($CHAR_CACHE[$cache_key])) {
            return $CHAR_CACHE[$cache_key];
        }

        if ($code_point <= 0x80) { // only for "simple"-chars

            if (self::$CHR === null) {
                self::$CHR = self::getData('chr');
            }

            /**
             * @psalm-suppress PossiblyNullArrayAccess
             */
            $chr = self::$CHR[$code_point];

            if ($encoding !== 'UTF-8') {
                $chr = self::encode($encoding, $chr);
            }

            return $CHAR_CACHE[$cache_key] = $chr;
        }

        //
        // fallback via "IntlChar"
        //

        if (self::$SUPPORT['intlChar'] === true) {
            $chr = \IntlChar::chr($code_point);

            if ($encoding !== 'UTF-8') {
                $chr = self::encode($encoding, $chr);
            }

            return $CHAR_CACHE[$cache_key] = $chr;
        }

        //
        // fallback via vanilla php
        //

        if (self::$CHR === null) {
            self::$CHR = self::getData('chr');
        }

        $code_point = (int) $code_point;
        if ($code_point <= 0x7FF) {
            /**
             * @psalm-suppress PossiblyNullArrayAccess
             */
            $chr = self::$CHR[($code_point >> 6) + 0xC0] .
                   self::$CHR[($code_point & 0x3F) + 0x80];
        } elseif ($code_point <= 0xFFFF) {
            /**
             * @psalm-suppress PossiblyNullArrayAccess
             */
            $chr = self::$CHR[($code_point >> 12) + 0xE0] .
                   self::$CHR[(($code_point >> 6) & 0x3F) + 0x80] .
                   self::$CHR[($code_point & 0x3F) + 0x80];
        } else {
            /**
             * @psalm-suppress PossiblyNullArrayAccess
             */
            $chr = self::$CHR[($code_point >> 18) + 0xF0] .
                   self::$CHR[(($code_point >> 12) & 0x3F) + 0x80] .
                   self::$CHR[(($code_point >> 6) & 0x3F) + 0x80] .
                   self::$CHR[($code_point & 0x3F) + 0x80];
        }

        if ($encoding !== 'UTF-8') {
            $chr = self::encode($encoding, $chr);
        }

        return $CHAR_CACHE[$cache_key] = $chr;
    }

    /**
     * Applies callback to all characters of a string.
     *
     * EXAMPLE: <code>UTF8::chr_map([UTF8::class, 'strtolower'], 'Κόσμε'); // ['κ','ό', 'σ', 'μ', 'ε']</code>
     *
     * @param callable(string): string $callback <p>The callback function.</p>
     * @param string   $str      <p>UTF-8 string to run callback on.</p>
     *
     * @psalm-pure
     *
     * @return string[]
     *                  <p>The outcome of the callback, as array.</p>
     */
    public static function chr_map($callback, string $str): array
    {
        return \array_map(
            $callback,
            self::str_split($str)
        );
    }

    /**
     * Generates an array of byte length of each character of a Unicode string.
     *
     * 1 byte => U+0000  - U+007F
     * 2 byte => U+0080  - U+07FF
     * 3 byte => U+0800  - U+FFFF
     * 4 byte => U+10000 - U+10FFFF
     *
     * EXAMPLE: <code>UTF8::chr_size_list('中文空白-test'); // [3, 3, 3, 3, 1, 1, 1, 1, 1]</code>
     *
     * @param string $str <p>The original unicode string.</p>
     *
     * @psalm-pure
     *
     * @return int[]
     *               <p>An array of byte lengths of each character.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-list<1|2|3|4> : list<1|2|3|4>)
     */
    public static function chr_size_list(string $str): array
    {
        if ($str === '') {
            return [];
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            /* @phpstan-ignore-next-line | str_split only give one char, so that we only got int<1,4> */
            return \array_map(
                static function (string $data): int {
                    // "mb_" is available if overload is used, so use it ...
                    return \mb_strlen($data, 'CP850'); // 8-BIT
                },
                self::str_split($str)
            );
        }

        /* @phpstan-ignore-next-line | str_split only give one char, so that we only got int<1,4> */
        return \array_map('\strlen', self::str_split($str));
    }

    /**
     * Get a decimal code representation of a specific character.
     *
     * INFO: opposite to UTF8::decimal_to_chr()
     *
     * EXAMPLE: <code>UTF8::chr_to_decimal('§'); // 0xa7</code>
     *
     * @param string $char <p>The input character.</p>
     *
     * @psalm-pure
     *
     * @return int
     */
    public static function chr_to_decimal(string $char): int
    {
        if (self::$SUPPORT['iconv'] === true) {
            $chr_tmp = \iconv('UTF-8', 'UCS-4LE', $char);
            if ($chr_tmp !== false) {
                /** @phpstan-ignore-next-line - "unpack": only false if the format string contains errors */
                return \unpack('V', $chr_tmp)[1];
            }
        }

        $code = self::ord($char[0]);
        $bytes = 1;

        if (!($code & 0x80)) {
            // 0xxxxxxx
            return $code;
        }

        if (($code & 0xe0) === 0xc0) {
            // 110xxxxx
            $bytes = 2;
            $code &= ~0xc0;
        } elseif (($code & 0xf0) === 0xe0) {
            // 1110xxxx
            $bytes = 3;
            $code &= ~0xe0;
        } elseif (($code & 0xf8) === 0xf0) {
            // 11110xxx
            $bytes = 4;
            $code &= ~0xf0;
        }

        for ($i = 2; $i <= $bytes; ++$i) {
            // 10xxxxxx
            $code = ($code << 6) + (self::ord($char[$i - 1]) & ~0x80);
        }

        return $code;
    }

    /**
     * Get hexadecimal code point (U+xxxx) of a UTF-8 encoded character.
     *
     * EXAMPLE: <code>UTF8::chr_to_hex('§'); // U+00a7</code>
     *
     * @param int|string $char   <p>The input character</p>
     * @param string     $prefix [optional]
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The code point encoded as U+xxxx.</p>
     */
    public static function chr_to_hex($char, string $prefix = 'U+'): string
    {
        if ($char === '') {
            return '';
        }

        if ($char === '&#0;') {
            $char = '';
        }

        return self::int_to_hex(self::ord((string) $char), $prefix);
    }

    /**
     * Splits a string into smaller chunks and multiple lines, using the specified line ending character.
     *
     * EXAMPLE: <code>UTF8::chunk_split('ABC-ÖÄÜ-中文空白-κόσμε', 3); // "ABC\r\n-ÖÄ\r\nÜ-中\r\n文空白\r\n-κό\r\nσμε"</code>
     *
     * @param string      $str          <p>The original string to be split.</p>
     * @param int<1, max> $chunk_length [optional] <p>The maximum character length of a chunk.</p>
     * @param string      $end          [optional] <p>The character(s) to be inserted at the end of each chunk.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The chunked string.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function chunk_split(string $str, int $chunk_length = 76, string $end = "\r\n"): string
    {
        return \implode($end, self::str_split($str, $chunk_length));
    }

    /**
     * Accepts a string and removes all non-UTF-8 characters from it + extras if needed.
     *
     * EXAMPLE: <code>UTF8::clean("\xEF\xBB\xBF„Abcdef\xc2\xa0\x20…” — 😃 - DÃ¼sseldorf", true, true); // '„Abcdef  …” — 😃 - DÃ¼sseldorf'</code>
     *
     * @param string $str                                     <p>The string to be sanitized.</p>
     * @param bool   $remove_bom                              [optional] <p>Set to true, if you need to remove
     *                                                        UTF-BOM.</p>
     * @param bool   $normalize_whitespace                    [optional] <p>Set to true, if you need to normalize the
     *                                                        whitespace.</p>
     * @param bool   $normalize_msword                        [optional] <p>Set to true, if you need to normalize MS
     *                                                        Word chars e.g.: "…"
     *                                                        => "..."</p>
     * @param bool   $keep_non_breaking_space                 [optional] <p>Set to true, to keep non-breaking-spaces,
     *                                                        in
     *                                                        combination with
     *                                                        $normalize_whitespace</p>
     * @param bool   $replace_diamond_question_mark           [optional] <p>Set to true, if you need to remove diamond
     *                                                        question mark e.g.: "�"</p>
     * @param bool   $remove_invisible_characters             [optional] <p>Set to false, if you not want to remove
     *                                                        invisible characters e.g.: "\0"</p>
     * @param bool   $remove_invisible_characters_url_encoded [optional] <p>Set to true, if you not want to remove
     *                                                        invisible url encoded characters e.g.: "%0B"<br> WARNING:
     *                                                        maybe contains false-positives e.g. aa%0Baa -> aaaa.
     *                                                        </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>An clean UTF-8 encoded string.</p>
     */
    public static function clean(
        string $str,
        bool $remove_bom = false,
        bool $normalize_whitespace = false,
        bool $normalize_msword = false,
        bool $keep_non_breaking_space = false,
        bool $replace_diamond_question_mark = false,
        bool $remove_invisible_characters = true,
        bool $remove_invisible_characters_url_encoded = false
    ): string {
        // http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string
        // caused connection reset problem on larger strings

        $regex = '/
          (
            (?: [\x00-\x7F]               # single-byte sequences   0xxxxxxx
            |   [\xC0-\xDF][\x80-\xBF]    # double-byte sequences   110xxxxx 10xxxxxx
            |   [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences   1110xxxx 10xxxxxx * 2
            |   [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
            ){1,100}                      # ...one or more times
          )
        | ( [\x80-\xBF] )                 # invalid byte in range 10000000 - 10111111
        | ( [\xC0-\xFF] )                 # invalid byte in range 11000000 - 11111111
        /x';
        $str = (string) \preg_replace($regex, '$1', $str);

        if ($replace_diamond_question_mark) {
            $str = self::replace_diamond_question_mark($str);
        }

        if ($remove_invisible_characters) {
            $str = self::remove_invisible_characters($str, $remove_invisible_characters_url_encoded);
        }

        if ($normalize_whitespace) {
            $str = self::normalize_whitespace($str, $keep_non_breaking_space);
        }

        if ($normalize_msword) {
            $str = self::normalize_msword($str);
        }

        if ($remove_bom) {
            $str = self::remove_bom($str);
        }

        return $str;
    }

    /**
     * Clean-up a string and show only printable UTF-8 chars at the end  + fix UTF-8 encoding.
     *
     * EXAMPLE: <code>UTF8::cleanup("\xEF\xBB\xBF„Abcdef\xc2\xa0\x20…” — 😃 - DÃ¼sseldorf", true, true); // '„Abcdef  …” — 😃 - Düsseldorf'</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function cleanup($str): string
    {
        // init
        $str = (string) $str;

        if ($str === '') {
            return '';
        }

        // fixed ISO <-> UTF-8 Errors
        $str = self::fix_simple_utf8($str);

        // remove all none UTF-8 symbols
        // && remove diamond question mark (�)
        // && remove remove invisible characters (e.g. "\0")
        // && remove BOM
        // && normalize whitespace chars (but keep non-breaking-spaces)
        return self::clean(
            $str,
            true,
            true,
            false,
            true,
            true
        );
    }

    /**
     * Accepts a string or an array of chars and returns an array of Unicode code points.
     *
     * INFO: opposite to UTF8::string()
     *
     * EXAMPLE: <code>
     * UTF8::codepoints('κöñ'); // array(954, 246, 241)
     * // ... OR ...
     * UTF8::codepoints('κöñ', true); // array('U+03ba', 'U+00f6', 'U+00f1')
     * </code>
     *
     * @param string|string[] $arg         <p>A UTF-8 encoded string or an array of such chars.</p>
     * @param bool            $use_u_style <p>If True, will return code points in U+xxxx format,
     *                                     default, code points will be returned as integers.</p>
     *
     * @psalm-pure
     *
     * @return int[]|string[]
     *                        <p>
     *                        The array of code points:<br>
     *                        int[] for $u_style === false<br>
     *                        string[] for $u_style === true<br>
     *                        </p>
     *
     * @template T as string|string[]
     * @phpstan-param T $arg
     * @phpstan-return (T is non-empty-string ? ($use_u_style is true ? non-empty-list<string> : non-empty-list<int>) : ($use_u_style is true ? list<string> : list<int>))
     */
    public static function codepoints($arg, bool $use_u_style = false): array
    {
        if (\is_string($arg)) {
            $arg = self::str_split($arg);
        }

        /**
         * @psalm-suppress DocblockTypeContradiction
         * @phpstan-ignore-next-line hack for bad inputs
         */
        if (!\is_array($arg)) {
            return [];
        }

        if ($arg === []) {
            return [];
        }

        $arg = \array_map(
            [
                self::class,
                'ord',
            ],
            $arg
        );

        if ($use_u_style) {
            $arg = \array_map(
                [
                    self::class,
                    'int_to_hex',
                ],
                $arg
            );
        }

        /* @phpstan-ignore-next-line | FP? */
        return $arg;
    }

    /**
     * Trims the string and replaces consecutive whitespace characters with a
     * single space. This includes tabs and newline characters, as well as
     * multibyte whitespace such as the thin space and ideographic space.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with trimmed $str and condensed whitespace.</p>
     */
    public static function collapse_whitespace(string $str): string
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \trim((string) \mb_ereg_replace('[[:space:]]+', ' ', $str));
        }

        return \trim(self::regex_replace($str, '[[:space:]]+', ' '));
    }

    /**
     * Returns count of characters used in a string.
     *
     * EXAMPLE: <code>UTF8::count_chars('κaκbκc'); // array('κ' => 3, 'a' => 1, 'b' => 1, 'c' => 1)</code>
     *
     * @param string $str                     <p>The input string.</p>
     * @param bool   $clean_utf8              [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param bool   $try_to_use_mb_functions [optional] <p>Set to false, if you don't want to use
     *
     * @psalm-pure
     *
     * @return int[]
     *               <p>An associative array of Character as keys and
     *               their count as values.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-array<string, int> : array<string, int>)
     */
    public static function count_chars(
        string $str,
        bool $clean_utf8 = false,
        bool $try_to_use_mb_functions = true
    ): array {
        return \array_count_values(
            self::str_split(
                $str,
                1,
                $clean_utf8,
                $try_to_use_mb_functions
            )
        );
    }

    /**
     * Create a valid CSS identifier for e.g. "class"- or "id"-attributes.
     *
     * EXAMPLE: <code>UTF8::css_identifier('123foo/bar!!!'); // _23foo-bar</code>
     *
     * copy&past from https://github.com/drupal/core/blob/8.8.x/lib/Drupal/Component/Utility/Html.php#L95
     *
     * @param string   $str        <p>INFO: if no identifier is given e.g. " " or "", we will create a unique string automatically</p>
     * @param string[] $filter
     * @param bool     $strip_tags
     * @param bool     $strtolower
     *
     * @psalm-pure
     *
     * @return string
     *
     * @phpstan-param array<string,string> $filter
     */
    public static function css_identifier(
        string $str = '',
        array $filter = [
            ' ' => '-',
            '/' => '-',
            '[' => '',
            ']' => '',
        ],
        bool $strip_tags = false,
        bool $strtolower = true
    ): string {
        // We could also use strtr() here but its much slower than str_replace(). In
        // order to keep '__' to stay '__' we first replace it with a different
        // placeholder after checking that it is not defined as a filter.
        $double_underscore_replacements = 0;

        $str = \trim($str);
        if ($str) {
            $str = self::clean($str, true);
        }

        if ($strip_tags) {
            $str = \strip_tags($str);
        }

        $str = \trim($str);
        // fallback (1)
        if (!$str) {
            $str = \uniqid('auto-generated-css-class', true);
        }

        if ($strtolower) {
            $str = \strtolower($str);
        }

        if (!isset($filter['__'])) {
            $str = \str_replace('__', '##', $str, $double_underscore_replacements);
        }

        $str = \str_replace(\array_keys($filter), \array_values($filter), $str);
        // Replace temporary placeholder '##' with '__' only if the original
        // $identifier contained '__'.
        if ($double_underscore_replacements > 0) {
            $str = \str_replace('##', '__', $str);
        }

        // Valid characters in a CSS identifier are:
        // - the hyphen (U+002D)
        // - a-z (U+0030 - U+0039)
        // - A-Z (U+0041 - U+005A)
        // - the underscore (U+005F)
        // - 0-9 (U+0061 - U+007A)
        // - ISO 10646 characters U+00A1 and higher
        // We strip out any character not in the above list.
        $str = (string) \preg_replace('/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u', '', $str);
        // Identifiers cannot start with a digit, two hyphens, or a hyphen followed by a digit.
        $str = (string) \preg_replace(['/^[0-9]/', '/^(-[0-9])|^(--)/'], ['_', '__'], $str);

        return \trim($str, '-');
    }

    /**
     * Remove css media-queries.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function css_stripe_media_queries(string $str): string
    {
        return (string) \preg_replace(
            '#@media\\s+(?:only\\s)?(?:[\\s{(]|screen|all)\\s?[^{]+{.*}\\s*}\\s*#isumU',
            '',
            $str
        );
    }

    /**
     * Checks whether ctype is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function ctype_loaded(): bool
    {
        return \extension_loaded('ctype');
    }

    /**
     * Converts an int value into a UTF-8 character.
     *
     * INFO: opposite to UTF8::string()
     *
     * EXAMPLE: <code>UTF8::decimal_to_chr(931); // 'Σ'</code>
     *
     * @param int|string $int
     *
     * @phpstan-param int|numeric-string $int
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function decimal_to_chr($int): string
    {
        // We cannot use html_entity_decode() here, as it will not return
        // characters for many values < 160.
        return \mb_convert_encoding('&#' . $int . ';', 'UTF-8', 'HTML-ENTITIES');
    }

    /**
     * Decodes a MIME header field
     *
     * @param string $str
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>A decoded MIME field on success,
     *                      or false if an error occurs during the decoding.</p>
     */
    public static function decode_mimeheader($str, string $encoding = 'UTF-8')
    {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        // always fallback via symfony polyfill
        return \iconv_mime_decode($str, \ICONV_MIME_DECODE_CONTINUE_ON_ERROR, $encoding);
    }

    /**
     * Convert any two-letter country code (ISO 3166-1) to the corresponding Emoji.
     *
     * @see https://en.wikipedia.org/wiki/ISO_3166-1
     *
     * @param string $country_code_iso_3166_1 <p>e.g. DE</p>
     *
     * @return string
     *                <p>Emoji or empty string on error.</p>
     */
    public static function emoji_from_country_code(string $country_code_iso_3166_1): string
    {
        if ($country_code_iso_3166_1 === '') {
            return '';
        }

        if (self::strlen($country_code_iso_3166_1) !== 2) {
            return '';
        }

        $country_code_iso_3166_1 = \strtoupper($country_code_iso_3166_1);

        $flagOffset = 0x1F1E6;
        $asciiOffset = 0x41;

        return (self::chr((self::ord($country_code_iso_3166_1[0]) - $asciiOffset + $flagOffset)) ?? '') .
               (self::chr((self::ord($country_code_iso_3166_1[1]) - $asciiOffset + $flagOffset)) ?? '');
    }

    /**
     * Decodes a string which was encoded by "UTF8::emoji_encode()".
     *
     * INFO: opposite to UTF8::emoji_encode()
     *
     * EXAMPLE: <code>
     * UTF8::emoji_decode('foo CHARACTER_OGRE', false); // 'foo 👹'
     * //
     * UTF8::emoji_decode('foo _-_PORTABLE_UTF8_-_308095726_-_627590803_-_8FTU_ELBATROP_-_', true); // 'foo 👹'
     * </code>
     *
     * @param string $str                            <p>The input string.</p>
     * @param bool   $use_reversible_string_mappings [optional] <p>
     *                                               When <b>TRUE</b>, we se a reversible string mapping
     *                                               between "emoji_encode" and "emoji_decode".</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function emoji_decode(
        string $str,
        bool $use_reversible_string_mappings = false
    ): string {
        if (self::$EMOJI_KEYS_CACHE === null) {
            /** @phpstan-ignore-next-line - we need to load the data first */
            self::initEmojiData();
        }

        if ($use_reversible_string_mappings) {
            return (string) \str_replace(
                (array) self::$EMOJI_KEYS_REVERSIBLE_CACHE,
                (array) self::$EMOJI_VALUES_CACHE,
                $str
            );
        }

        return (string) \str_replace(
            (array) self::$EMOJI_KEYS_CACHE,
            (array) self::$EMOJI_VALUES_CACHE,
            $str
        );
    }

    /**
     * Encode a string with emoji chars into a non-emoji string.
     *
     * INFO: opposite to UTF8::emoji_decode()
     *
     * EXAMPLE: <code>
     * UTF8::emoji_encode('foo 👹', false)); // 'foo CHARACTER_OGRE'
     * //
     * UTF8::emoji_encode('foo 👹', true)); // 'foo _-_PORTABLE_UTF8_-_308095726_-_627590803_-_8FTU_ELBATROP_-_'
     * </code>
     *
     * @param string $str                            <p>The input string</p>
     * @param bool   $use_reversible_string_mappings [optional] <p>
     *                                               when <b>TRUE</b>, we use a reversible string mapping
     *                                               between "emoji_encode" and "emoji_decode"</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function emoji_encode(
        string $str,
        bool $use_reversible_string_mappings = false
    ): string {
        if (self::$EMOJI_KEYS_CACHE === null) {
            /** @phpstan-ignore-next-line - we need to load the data first */
            self::initEmojiData();
        }

        if ($use_reversible_string_mappings) {
            return (string) \str_replace(
                (array) self::$EMOJI_VALUES_CACHE,
                (array) self::$EMOJI_KEYS_REVERSIBLE_CACHE,
                $str
            );
        }

        return (string) \str_replace(
            (array) self::$EMOJI_VALUES_CACHE,
            (array) self::$EMOJI_KEYS_CACHE,
            $str
        );
    }

    /**
     * Encode a string with a new charset-encoding.
     *
     * INFO:  This function will also try to fix broken / double encoding,
     *        so you can call this function also on a UTF-8 string and you don't mess up the string.
     *
     * EXAMPLE: <code>
     * UTF8::encode('ISO-8859-1', '-ABC-中文空白-'); // '-ABC-????-'
     * //
     * UTF8::encode('UTF-8', '-ABC-中文空白-'); // '-ABC-中文空白-'
     * //
     * UTF8::encode('HTML', '-ABC-中文空白-'); // '-ABC-&#20013;&#25991;&#31354;&#30333;-'
     * //
     * UTF8::encode('BASE64', '-ABC-中文空白-'); // 'LUFCQy3kuK3mlofnqbrnmb0t'
     * </code>
     *
     * @param string $to_encoding                   <p>e.g. 'UTF-16', 'UTF-8', 'ISO-8859-1', etc.</p>
     * @param string $str                           <p>The input string</p>
     * @param bool   $auto_detect_the_from_encoding [optional] <p>Force the new encoding (we try to fix broken / double
     *                                              encoding for UTF-8)<br> otherwise we auto-detect the current
     *                                              string-encoding</p>
     * @param string $from_encoding                 [optional] <p>e.g. 'UTF-16', 'UTF-8', 'ISO-8859-1', etc.<br>
     *                                              A empty string will trigger the autodetect anyway.</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @psalm-suppress InvalidReturnStatement
     */
    public static function encode(
        string $to_encoding,
        string $str,
        bool $auto_detect_the_from_encoding = true,
        string $from_encoding = ''
    ): string {
        if ($str === '' || $to_encoding === '') {
            return $str;
        }

        if ($to_encoding !== 'UTF-8' && $to_encoding !== 'CP850') {
            $to_encoding = self::normalize_encoding($to_encoding, 'UTF-8');
        }

        if ($from_encoding && $from_encoding !== 'UTF-8' && $from_encoding !== 'CP850') {
            $from_encoding = self::normalize_encoding($from_encoding);
        }

        if (
            $to_encoding
            &&
            $from_encoding
            &&
            $from_encoding === $to_encoding
        ) {
            return $str;
        }

        if ($from_encoding === 'JSON') {
            $str = self::json_decode($str);
            $from_encoding = '';
        }

        if ($from_encoding === 'BASE64') {
            $str = \base64_decode($str, true);
            $from_encoding = '';
        }

        if ($from_encoding === 'HTML-ENTITIES') {
            /* @phpstan-ignore-next-line | $str has manybe changed */
            $str = self::html_entity_decode($str, \ENT_COMPAT);
            $from_encoding = '';
        }

        if ($to_encoding === 'JSON') {
            $return = self::json_encode($str);
            if ($return === false) {
                throw new \InvalidArgumentException('The input string [' . $str . '] can not be used for json_encode().');
            }

            return $return;
        }

        if ($to_encoding === 'BASE64') {
            return \base64_encode($str);
        }

        if ($to_encoding === 'HTML-ENTITIES') {
            /* @phpstan-ignore-next-line | $str has manybe changed */
            return self::html_encode($str, true);
        }

        if (
            $auto_detect_the_from_encoding
            ||
            !$from_encoding
        ) {
            $from_encoding_auto_detected = self::str_detect_encoding($str);
        } else {
            $from_encoding_auto_detected = false;
        }

        // DEBUG
        //var_dump($to_encoding, $from_encoding, $from_encoding_auto_detected, $str, "\n\n");

        if ($from_encoding_auto_detected !== false) {
            $from_encoding = $from_encoding_auto_detected;
        } elseif ($auto_detect_the_from_encoding) {
            // fallback for the "autodetect"-mode
            /* @phpstan-ignore-next-line | $str has manybe changed */
            return self::to_utf8($str);
        }

        if (
            !$from_encoding
            ||
            $from_encoding === $to_encoding
        ) {
            return $str;
        }

        if (
            $to_encoding === 'UTF-8'
            &&
            (
                $from_encoding === 'WINDOWS-1252'
                ||
                $from_encoding === 'ISO-8859-1'
            )
        ) {
            /* @phpstan-ignore-next-line | $str has manybe changed */
            return self::to_utf8($str);
        }

        if (
            $to_encoding === 'ISO-8859-1'
            &&
            (
                $from_encoding === 'WINDOWS-1252'
                ||
                $from_encoding === 'UTF-8'
            )
        ) {
            /* @phpstan-ignore-next-line | $str has manybe changed */
            return self::to_iso8859($str);
        }

        if (
            $to_encoding !== 'UTF-8'
            &&
            $to_encoding !== 'ISO-8859-1'
            &&
            $to_encoding !== 'WINDOWS-1252'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::encode() without mbstring cannot handle "' . $to_encoding . '" encoding', \E_USER_WARNING);
        }

        if (self::$SUPPORT['mbstring'] === true) {
            $str_encoded = \mb_convert_encoding(
                $str,
                $to_encoding,
                $from_encoding
            );

            if ($str_encoded) {
                \assert(\is_string($str_encoded));

                return $str_encoded;
            }
        }

        /** @noinspection PhpUsageOfSilenceOperatorInspection - Detected an incomplete multibyte character in input string */
        $return = @\iconv($from_encoding, $to_encoding, $str);
        if ($return !== false) {
            return $return;
        }

        return $str;
    }

    /**
     * @param string      $str
     * @param string      $from_charset      [optional] <p>Set the input charset.</p>
     * @param string      $to_charset        [optional] <p>Set the output charset.</p>
     * @param string      $transfer_encoding [optional] <p>Set the transfer encoding.</p>
     * @param string      $linefeed          [optional] <p>Set the used linefeed.</p>
     * @param int<1, max> $indent            [optional] <p>Set the max length indent.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>An encoded MIME field on success,
     *                      or false if an error occurs during the encoding.</p>
     */
    public static function encode_mimeheader(
        string $str,
        string $from_charset = 'UTF-8',
        string $to_charset = 'UTF-8',
        string $transfer_encoding = 'Q',
        string $linefeed = "\r\n",
        int $indent = 76
    ) {
        if ($from_charset !== 'UTF-8' && $from_charset !== 'CP850') {
            $from_charset = self::normalize_encoding($from_charset, 'UTF-8');
        }

        if ($to_charset !== 'UTF-8' && $to_charset !== 'CP850') {
            $to_charset = self::normalize_encoding($to_charset, 'UTF-8');
        }

        // always fallback via symfony polyfill
        return \iconv_mime_encode(
            '',
            $str,
            [
                'scheme'           => $transfer_encoding,
                'line-length'      => $indent,
                'input-charset'    => $from_charset,
                'output-charset'   => $to_charset,
                'line-break-chars' => $linefeed,
            ]
        );
    }

    /**
     * Create an extract from a sentence, so if the search-string was found, it tries to center in the output.
     *
     * @param string   $str                       <p>The input string.</p>
     * @param string   $search                    <p>The searched string.</p>
     * @param int|null $length                    [optional] <p>Default: null === text->length / 2</p>
     * @param string   $replacer_for_skipped_text [optional] <p>Default: …</p>
     * @param string   $encoding                  [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function extract_text(
        string $str,
        string $search = '',
        int $length = null,
        string $replacer_for_skipped_text = '…',
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '') {
            return '';
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        $trim_chars = "\t\r\n -_()!~?=+/*\\,.:;\"'[]{}`&";

        if ($length === null) {
            $length = (int) \round((int) self::strlen($str, $encoding) / 2);
        }

        if ($search === '') {
            if ($encoding === 'UTF-8') {
                if ($length > 0) {
                    $string_length = (int) \mb_strlen($str);
                    $end = ($length - 1) > $string_length ? $string_length : ($length - 1);
                } else {
                    $end = 0;
                }

                $pos = (int) \min(
                    \mb_strpos($str, ' ', $end),
                    \mb_strpos($str, '.', $end)
                );
            } else {
                if ($length > 0) {
                    $string_length = (int) self::strlen($str, $encoding);
                    $end = ($length - 1) > $string_length ? $string_length : ($length - 1);
                } else {
                    $end = 0;
                }

                $pos = (int) \min(
                    self::strpos($str, ' ', $end, $encoding),
                    self::strpos($str, '.', $end, $encoding)
                );
            }

            if ($pos) {
                if ($encoding === 'UTF-8') {
                    $str_sub = \mb_substr($str, 0, $pos);
                } else {
                    $str_sub = self::substr($str, 0, $pos, $encoding);
                }

                if ($str_sub === false) {
                    return '';
                }

                return \rtrim($str_sub, $trim_chars) . $replacer_for_skipped_text;
            }

            return $str;
        }

        if ($encoding === 'UTF-8') {
            $word_position = (int) \mb_stripos($str, $search);
            $half_side = (int) ($word_position - $length / 2 + (int) \mb_strlen($search) / 2);
        } else {
            $word_position = (int) self::stripos($str, $search, 0, $encoding);
            $half_side = (int) ($word_position - $length / 2 + (int) self::strlen($search, $encoding) / 2);
        }

        $pos_start = 0;
        if ($half_side > 0) {
            if ($encoding === 'UTF-8') {
                $half_text = \mb_substr($str, 0, $half_side);
            } else {
                $half_text = self::substr($str, 0, $half_side, $encoding);
            }
            if ($half_text !== false) {
                if ($encoding === 'UTF-8') {
                    $pos_start = (int) \max(
                        \mb_strrpos($half_text, ' '),
                        \mb_strrpos($half_text, '.')
                    );
                } else {
                    $pos_start = (int) \max(
                        self::strrpos($half_text, ' ', 0, $encoding),
                        self::strrpos($half_text, '.', 0, $encoding)
                    );
                }
            }
        }

        if ($word_position && $half_side > 0) {
            $offset = $pos_start + $length - 1;
            $real_length = (int) self::strlen($str, $encoding);

            if ($offset > $real_length) {
                $offset = $real_length;
            }

            if ($encoding === 'UTF-8') {
                $pos_end = (int) \min(
                    \mb_strpos($str, ' ', $offset),
                    \mb_strpos($str, '.', $offset)
                ) - $pos_start;
            } else {
                $pos_end = (int) \min(
                    self::strpos($str, ' ', $offset, $encoding),
                    self::strpos($str, '.', $offset, $encoding)
                ) - $pos_start;
            }

            if (!$pos_end || $pos_end <= 0) {
                if ($encoding === 'UTF-8') {
                    $str_sub = \mb_substr($str, $pos_start, (int) \mb_strlen($str));
                } else {
                    $str_sub = self::substr($str, $pos_start, (int) self::strlen($str, $encoding), $encoding);
                }
                if ($str_sub !== false) {
                    $extract = $replacer_for_skipped_text . \ltrim($str_sub, $trim_chars);
                } else {
                    $extract = '';
                }
            } else {
                if ($encoding === 'UTF-8') {
                    $str_sub = \mb_substr($str, $pos_start, $pos_end);
                } else {
                    $str_sub = self::substr($str, $pos_start, $pos_end, $encoding);
                }
                if ($str_sub !== false) {
                    $extract = $replacer_for_skipped_text . \trim($str_sub, $trim_chars) . $replacer_for_skipped_text;
                } else {
                    $extract = '';
                }
            }
        } else {
            $offset = $length - 1;
            $true_length = (int) self::strlen($str, $encoding);

            if ($offset > $true_length) {
                $offset = $true_length;
            }

            if ($encoding === 'UTF-8') {
                $pos_end = (int) \min(
                    \mb_strpos($str, ' ', $offset),
                    \mb_strpos($str, '.', $offset)
                );
            } else {
                $pos_end = (int) \min(
                    self::strpos($str, ' ', $offset, $encoding),
                    self::strpos($str, '.', $offset, $encoding)
                );
            }

            if ($pos_end) {
                if ($encoding === 'UTF-8') {
                    $str_sub = \mb_substr($str, 0, $pos_end);
                } else {
                    $str_sub = self::substr($str, 0, $pos_end, $encoding);
                }
                if ($str_sub !== false) {
                    $extract = \rtrim($str_sub, $trim_chars) . $replacer_for_skipped_text;
                } else {
                    $extract = '';
                }
            } else {
                $extract = $str;
            }
        }

        return $extract;
    }

    /**
     * Reads entire file into a string.
     *
     * EXAMPLE: <code>UTF8::file_get_contents('utf16le.txt'); // ...</code>
     *
     * WARNING: Do not use UTF-8 Option ($convert_to_utf8) for binary files (e.g.: images) !!!
     *
     * @see http://php.net/manual/en/function.file-get-contents.php
     *
     * @param string        $filename         <p>
     *                                        Name of the file to read.
     *                                        </p>
     * @param bool          $use_include_path [optional] <p>
     *                                        Prior to PHP 5, this parameter is called
     *                                        use_include_path and is a bool.
     *                                        As of PHP 5 the FILE_USE_INCLUDE_PATH can be used
     *                                        to trigger include path
     *                                        search.
     *                                        </p>
     * @param resource|null $context          [optional] <p>
     *                                        A valid context resource created with
     *                                        stream_context_create. If you don't need to use a
     *                                        custom context, you can skip this parameter by &null;.
     *                                        </p>
     * @param int|null      $offset           [optional] <p>
     *                                        The offset where the reading starts.
     *                                        </p>
     * @param int<0, max>|null $max_length       [optional] <p>
     *                                        Maximum length of data read. The default is to read until end
     *                                        of file is reached.
     *                                        </p>
     * @param int           $timeout          <p>The time in seconds for the timeout.</p>
     * @param bool          $convert_to_utf8  <strong>WARNING!!!</strong> <p>Maybe you can't use this option for
     *                                        some files, because they used non default utf-8 chars. Binary files
     *                                        like images or pdf will not be converted.</p>
     * @param string        $from_encoding    [optional] <p>e.g. 'UTF-16', 'UTF-8', 'ISO-8859-1', etc.<br>
     *                                        A empty string will trigger the autodetect anyway.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The function returns the read data as string or <b>false</b> on failure.</p>
     */
    public static function file_get_contents(
        string $filename,
        bool $use_include_path = false,
        $context = null,
        int $offset = null,
        int $max_length = null,
        int $timeout = 10,
        bool $convert_to_utf8 = true,
        string $from_encoding = ''
    ) {
        // init
        /** @noinspection CallableParameterUseCaseInTypeContextInspection - is ok here */
        $filename = Bootup::filter_sanitize_string_polyfill($filename);
        if ($filename === false) {
            return false;
        }

        if ($timeout && $context === null) {
            $context = \stream_context_create(
                [
                    'http' => [
                        'timeout' => $timeout,
                    ],
                ]
            );
        }

        if ($offset === null) {
            $offset = 0;
        }

        if (\is_int($max_length)) {
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            if ($max_length < 0) {
                $max_length = 0;
            }

            $data = \file_get_contents($filename, $use_include_path, $context, $offset, $max_length);
        } else {
            $data = \file_get_contents($filename, $use_include_path, $context, $offset);
        }

        // return false on error
        if ($data === false) {
            return false;
        }

        if (
            $convert_to_utf8
            &&
            (
                !self::is_binary($data, true)
                ||
                self::is_utf16($data, false) !== false
                ||
                self::is_utf32($data, false) !== false
            )
        ) {
            $data = self::encode('UTF-8', $data, false, $from_encoding);
            $data = self::cleanup($data);
        }

        return $data;
    }

    /**
     * Checks if a file starts with BOM (Byte Order Mark) character.
     *
     * EXAMPLE: <code>UTF8::file_has_bom('utf8_with_bom.txt'); // true</code>
     *
     * @param string $file_path <p>Path to a valid file.</p>
     *
     * @throws \RuntimeException if file_get_contents() returned false
     *
     * @return bool
     *              <p><strong>true</strong> if the file has BOM at the start, <strong>false</strong> otherwise</p>
     *
     * @psalm-pure
     */
    public static function file_has_bom(string $file_path): bool
    {
        $file_content = \file_get_contents($file_path);
        if ($file_content === false) {
            throw new \RuntimeException('file_get_contents() returned false for:' . $file_path);
        }

        return self::string_has_bom($file_content);
    }

    /**
     * Normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * EXAMPLE: <code>UTF8::filter(array("\xE9", 'à', 'a')); // array('é', 'à', 'a')</code>
     *
     * @param array|object|string $var
     * @param int                 $normalization_form
     * @param string              $leading_combining
     *
     * @psalm-pure
     *
     * @return mixed
     *
     * @template TFilter
     * @phpstan-param TFilter $var
     * @phpstan-return TFilter
     */
    public static function filter(
        $var,
        int $normalization_form = \Normalizer::NFC,
        string $leading_combining = '◌'
    ) {
        switch (\gettype($var)) {
            case 'object':
            case 'array':
                /* @phpstan-ignore-next-line | object & array are both iterable */
                foreach ($var as &$v) {
                    $v = self::filter($v, $normalization_form, $leading_combining);
                }
                unset($v);

                break;
            case 'string':

                if (\strpos($var, "\r") !== false) {
                    $var = self::normalize_line_ending($var);
                }

                if (!ASCII::is_ascii($var)) {
                    if (\Normalizer::isNormalized($var, $normalization_form)) {
                        $n = '-';
                    } else {
                        $n = \Normalizer::normalize($var, $normalization_form);

                        if ($n && isset($n[0])) {
                            $var = $n;
                        } else {
                            $var = self::encode('UTF-8', $var);
                        }
                    }

                    \assert(\is_string($var));
                    if (
                        $n
                        &&
                        $var[0] >= "\x80"
                        &&
                        isset($n[0], $leading_combining[0])
                        &&
                        \preg_match('/^\\p{Mn}/u', $var)
                    ) {
                        // Prevent leading combining chars
                        // for NFC-safe concatenations.
                        $var = $leading_combining . $var;
                    }
                }

                break;
            default:
                // nothing
        }

        /** @noinspection PhpSillyAssignmentInspection */
        /** @phpstan-var TFilter $var */
        $var = $var;

        return $var;
    }

    /**
     * "filter_input()"-wrapper with normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * Gets a specific external variable by name and optionally filters it.
     *
     * EXAMPLE: <code>
     * // _GET['foo'] = 'bar';
     * UTF8::filter_input(INPUT_GET, 'foo', FILTER_UNSAFE_RAW)); // 'bar'
     * </code>
     *
     * @see http://php.net/manual/en/function.filter-input.php
     *
     * @param int            $type          <p>
     *                                      One of <b>INPUT_GET</b>, <b>INPUT_POST</b>,
     *                                      <b>INPUT_COOKIE</b>, <b>INPUT_SERVER</b>, or
     *                                      <b>INPUT_ENV</b>.
     *                                      </p>
     * @param string         $variable_name <p>
     *                                      Name of a variable to get.
     *                                      </p>
     * @param int            $filter        [optional] <p>
     *                                      The ID of the filter to apply. The
     *                                      manual page lists the available filters.
     *                                      </p>
     * @param int|int[]|null $options       [optional] <p>
     *                                      Associative array of options or bitwise disjunction of flags. If filter
     *                                      accepts options, flags can be provided in "flags" field of array.
     *                                      </p>
     *
     * @psalm-pure
     *
     * @return mixed
     *               <p>
     *               Value of the requested variable on success, <b>FALSE</b> if the filter fails, or <b>NULL</b> if the
     *               <i>variable_name</i> variable is not set. If the flag <b>FILTER_NULL_ON_FAILURE</b> is used, it
     *               returns <b>FALSE</b> if the variable is not set and <b>NULL</b> if the filter fails.
     *               </p>
     */
    public static function filter_input(
        int $type,
        string $variable_name,
        int $filter = \FILTER_DEFAULT,
        $options = null
    ) {
        /**
         * @psalm-suppress ImpureFunctionCall - we use func_num_args only for args count matching here
         */
        if ($options === null || \func_num_args() < 4) {
            $var = \filter_input($type, $variable_name, $filter);
        } else {
            $var = \filter_input($type, $variable_name, $filter, $options);
        }

        return self::filter($var);
    }

    /**
     * "filter_input_array()"-wrapper with normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * Gets external variables and optionally filters them.
     *
     * EXAMPLE: <code>
     * // _GET['foo'] = 'bar';
     * UTF8::filter_input_array(INPUT_GET, array('foo' => 'FILTER_UNSAFE_RAW')); // array('bar')
     * </code>
     *
     * @see http://php.net/manual/en/function.filter-input-array.php
     *
     * @param int                       $type       <p>
     *                                              One of <b>INPUT_GET</b>, <b>INPUT_POST</b>,
     *                                              <b>INPUT_COOKIE</b>, <b>INPUT_SERVER</b>, or
     *                                              <b>INPUT_ENV</b>.
     *                                              </p>
     * @param array<string, mixed>|null $definition [optional] <p>
     *                                              An array defining the arguments. A valid key is a string
     *                                              containing a variable name and a valid value is either a filter type, or an array
     *                                              optionally specifying the filter, flags and options. If the value is an
     *                                              array, valid keys are filter which specifies the
     *                                              filter type,
     *                                              flags which specifies any flags that apply to the
     *                                              filter, and options which specifies any options that
     *                                              apply to the filter. See the example below for a better understanding.
     *                                              </p>
     *                                              <p>
     *                                              This parameter can be also an integer holding a filter constant. Then all values in the
     *                                              input array are filtered by this filter.
     *                                              </p>
     * @param bool                      $add_empty  [optional] <p>
     *                                              Add missing keys as <b>NULL</b> to the return value.
     *                                              </p>
     *
     * @psalm-pure
     *
     * @return array<string, mixed>|false|null
     *                                         <p>
     *                                         An array containing the values of the requested variables on success, or <b>FALSE</b> on failure.
     *                                         An array value will be <b>FALSE</b> if the filter fails, or <b>NULL</b> if the variable is not
     *                                         set. Or if the flag <b>FILTER_NULL_ON_FAILURE</b> is used, it returns <b>FALSE</b> if the variable
     *                                         is not set and <b>NULL</b> if the filter fails.
     *                                         </p>
     */
    public static function filter_input_array(
        int $type,
        $definition = null,
        bool $add_empty = true
    ) {
        /**
         * @psalm-suppress ImpureFunctionCall - we use func_num_args only for args count matching here
         */
        if ($definition === null || \func_num_args() < 2) {
            $a = \filter_input_array($type);
        } else {
            $a = \filter_input_array($type, $definition, $add_empty);
        }

        /* @phpstan-ignore-next-line | magic frm self::filter :/ */
        return self::filter($a);
    }

    /**
     * "filter_var()"-wrapper with normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * Filters a variable with a specified filter.
     *
     * EXAMPLE: <code>UTF8::filter_var('-ABC-中文空白-', FILTER_VALIDATE_URL); // false</code>
     *
     * @see http://php.net/manual/en/function.filter-var.php
     *
     * @param float|int|string|null $variable <p>
     *                                        Value to filter.
     *                                        </p>
     * @param int                   $filter   [optional] <p>
     *                                        The ID of the filter to apply. The
     *                                        manual page lists the available filters.
     *                                        </p>
     * @param int|int[]             $options  [optional] <p>
     *                                        Associative array of options or bitwise disjunction of flags. If filter
     *                                        accepts options, flags can be provided in "flags" field of array. For
     *                                        the "callback" filter, callable type should be passed. The
     *                                        callback must accept one argument, the value to be filtered, and return
     *                                        the value after filtering/sanitizing it.
     *                                        </p>
     *                                        <p>
     *                                        <code>
     *                                        // for filters that accept options, use this format
     *                                        $options = array(
     *                                        'options' => array(
     *                                        'default' => 3, // value to return if the filter fails
     *                                        // other options here
     *                                        'min_range' => 0
     *                                        ),
     *                                        'flags' => FILTER_FLAG_ALLOW_OCTAL,
     *                                        );
     *                                        $var = filter_var('0755', FILTER_VALIDATE_INT, $options);
     *                                        // for filter that only accept flags, you can pass them directly
     *                                        $var = filter_var('oops', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
     *                                        // for filter that only accept flags, you can also pass as an array
     *                                        $var = filter_var('oops', FILTER_VALIDATE_BOOLEAN,
     *                                        array('flags' => FILTER_NULL_ON_FAILURE));
     *                                        // callback validate filter
     *                                        function foo($value)
     *                                        {
     *                                        // Expected format: Surname, GivenNames
     *                                        if (strpos($value, ", ") === false) return false;
     *                                        list($surname, $givennames) = explode(", ", $value, 2);
     *                                        $empty = (empty($surname) || empty($givennames));
     *                                        $notstrings = (!is_string($surname) || !is_string($givennames));
     *                                        if ($empty || $notstrings) {
     *                                        return false;
     *                                        } else {
     *                                        return $value;
     *                                        }
     *                                        }
     *                                        $var = filter_var('Doe, Jane Sue', FILTER_CALLBACK, array('options' => 'foo'));
     *                                        </code>
     *                                        </p>
     *
     * @psalm-pure
     *
     * @return mixed
     *               <p>The filtered data, or <b>FALSE</b> if the filter fails.</p>
     */
    public static function filter_var(
        $variable,
        int $filter = \FILTER_DEFAULT,
        $options = 0
    ) {
        /**
         * @psalm-suppress ImpureFunctionCall - we use func_num_args only for args count matching here
         */
        if (\func_num_args() < 3) {
            $variable = \filter_var($variable, $filter);
        } else {
            $variable = \filter_var($variable, $filter, $options);
        }

        return self::filter($variable);
    }

    /**
     * "filter_var_array()"-wrapper with normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
     *
     * Gets multiple variables and optionally filters them.
     *
     * EXAMPLE: <code>
     * $filters = [
     *     'name'  => ['filter'  => FILTER_CALLBACK, 'options' => [UTF8::class, 'ucwords']],
     *     'age'   => ['filter'  => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 120]],
     *     'email' => FILTER_VALIDATE_EMAIL,
     * ];
     *
     * $data = [
     *     'name' => 'κόσμε',
     *     'age' => '18',
     *     'email' => 'foo@bar.de'
     * ];
     *
     * UTF8::filter_var_array($data, $filters, true); // ['name' => 'Κόσμε', 'age' => 18, 'email' => 'foo@bar.de']
     * </code>
     *
     * @see http://php.net/manual/en/function.filter-var-array.php
     *
     * @param array<string, mixed>          $data       <p>
     *                                                  An array with string keys containing the data to filter.
     *                                                  </p>
     * @param array<string, mixed>|int      $definition [optional] <p>
     *                                                  An array defining the arguments. A valid key is a string
     *                                                  containing a variable name and a valid value is either a
     *                                                  filter type, or an
     *                                                  array optionally specifying the filter, flags and options.
     *                                                  If the value is an array, valid keys are filter
     *                                                  which specifies the filter type,
     *                                                  flags which specifies any flags that apply to the
     *                                                  filter, and options which specifies any options that
     *                                                  apply to the filter. See the example below for a better understanding.
     *                                                  </p>
     *                                                  <p>
     *                                                  This parameter can be also an integer holding a filter constant. Then all values
     *                                                  in the input array are filtered by this filter.
     *                                                  </p>
     * @param bool                          $add_empty  [optional] <p>
     *                                                  Add missing keys as <b>NULL</b> to the return value.
     *                                                  </p>
     *
     * @psalm-pure
     *
     * @return array<string, mixed>|false|null
     *                                         <p>
     *                                         An array containing the values of the requested variables on success, or <b>FALSE</b> on failure.
     *                                         An array value will be <b>FALSE</b> if the filter fails, or <b>NULL</b> if the variable is not
     *                                         set.
     *                                         </p>
     */
    public static function filter_var_array(
        array $data,
        $definition = 0,
        bool $add_empty = true
    ) {
        /**
         * @psalm-suppress ImpureFunctionCall - we use func_num_args only for args count matching here
         */
        if (\func_num_args() < 2) {
            $a = \filter_var_array($data);
        } else {
            $a = \filter_var_array($data, $definition, $add_empty);
        }

        /* @phpstan-ignore-next-line | magic frm self::filter :/ */
        return self::filter($a);
    }

    /**
     * Checks whether finfo is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function finfo_loaded(): bool
    {
        return \class_exists('finfo');
    }

    /**
     * Returns the first $n characters of the string.
     *
     * @param string      $str      <p>The input string.</p>
     * @param int<1, max> $n        <p>Number of characters to retrieve from the start.</p>
     * @param string      $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function first_char(
        string $str,
        int $n = 1,
        string $encoding = 'UTF-8'
    ): string {
        if (
            $str === ''
            ||
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            $n <= 0
        ) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str, 0, $n);
        }

        return (string) self::substr($str, 0, $n, $encoding);
    }

    /**
     * Check if the number of Unicode characters isn't greater than the specified integer.
     *
     * EXAMPLE: <code>UTF8::fits_inside('κόσμε', 6); // false</code>
     *
     * @param string $str      the original string to be checked
     * @param int    $box_size the size in number of chars to be checked against string
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>TRUE</strong> if string is less than or equal to $box_size, <strong>FALSE</strong> otherwise.</p>
     */
    public static function fits_inside(string $str, int $box_size): bool
    {
        return (int) self::strlen($str) <= $box_size;
    }

    /**
     * Try to fix simple broken UTF-8 strings.
     *
     * INFO: Take a look at "UTF8::fix_utf8()" if you need a more advanced fix for broken UTF-8 strings.
     *
     * EXAMPLE: <code>UTF8::fix_simple_utf8('DÃ¼sseldorf'); // 'Düsseldorf'</code>
     *
     * If you received an UTF-8 string that was converted from Windows-1252 as it was ISO-8859-1
     * (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it.
     * See: http://en.wikipedia.org/wiki/Windows-1252
     *
     * @param string $str <p>The input string</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function fix_simple_utf8(string $str): string
    {
        if ($str === '') {
            return '';
        }

        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<mixed>|null
         */
        static $BROKEN_UTF8_TO_UTF8_KEYS_CACHE = null;

        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<mixed>|null
         */
        static $BROKEN_UTF8_TO_UTF8_VALUES_CACHE = null;

        if ($BROKEN_UTF8_TO_UTF8_KEYS_CACHE === null) {
            if (self::$BROKEN_UTF8_FIX === null) {
                self::$BROKEN_UTF8_FIX = self::getData('utf8_fix');
            }

            $BROKEN_UTF8_TO_UTF8_KEYS_CACHE = \array_keys(self::$BROKEN_UTF8_FIX ?: []);
            $BROKEN_UTF8_TO_UTF8_VALUES_CACHE = self::$BROKEN_UTF8_FIX;
        }

        \assert(\is_array($BROKEN_UTF8_TO_UTF8_VALUES_CACHE));

        return \str_replace($BROKEN_UTF8_TO_UTF8_KEYS_CACHE, $BROKEN_UTF8_TO_UTF8_VALUES_CACHE, $str);
    }

    /**
     * Fix a double (or multiple) encoded UTF8 string.
     *
     * EXAMPLE: <code>UTF8::fix_utf8('FÃÂÂÂÂ©dÃÂÂÂÂ©ration'); // 'Fédération'</code>
     *
     * @param string|string[] $str you can use a string or an array of strings
     *
     * @psalm-pure
     *
     * @return string|string[]
     *                         <p>Will return the fixed input-"array" or
     *                         the fixed input-"string".</p>
     *
     * @template TFixUtf8 as string|string[]
     * @phpstan-param TFixUtf8 $str
     * @phpstan-return TFixUtf8
     */
    public static function fix_utf8($str)
    {
        if (\is_array($str)) {
            foreach ($str as &$v) {
                $v = self::fix_utf8($v);
            }
            unset($v);

            /**
             * @psalm-suppress InvalidReturnStatement
             */
            return $str;
        }

        $str = (string) $str; /* @phpstan-ignore-line | TFixUtf8 is string here */
        $last = '';
        while ($last !== $str) {
            $last = $str;
            /**
             * @psalm-suppress PossiblyInvalidArgument
             */
            $str = self::to_utf8(
                self::utf8_decode($str, true)
            );
        }

        /**
         * @psalm-suppress InvalidReturnStatement
         */
        return $str;
    }

    /**
     * Get character of a specific character.
     *
     * EXAMPLE: <code>UTF8::getCharDirection('ا'); // 'RTL'</code>
     *
     * @param string $char
     *
     * @psalm-pure
     *
     * @return string
     *                <p>'RTL' or 'LTR'.</p>
     */
    public static function getCharDirection(string $char): string
    {
        if (self::$SUPPORT['intlChar'] === true) {
            $tmp_return = \IntlChar::charDirection($char);

            // from "IntlChar"-Class
            $char_direction = [
                'RTL' => [1, 13, 14, 15, 21],
                'LTR' => [0, 11, 12, 20],
            ];

            if (\in_array($tmp_return, $char_direction['LTR'], true)) {
                return 'LTR';
            }

            if (\in_array($tmp_return, $char_direction['RTL'], true)) {
                return 'RTL';
            }
        }

        $c = static::chr_to_decimal($char);

        if (!($c >= 0x5be && $c <= 0x10b7f)) {
            return 'LTR';
        }

        if ($c <= 0x85e) {
            if ($c === 0x5be ||
                $c === 0x5c0 ||
                $c === 0x5c3 ||
                $c === 0x5c6 ||
                ($c >= 0x5d0 && $c <= 0x5ea) ||
                ($c >= 0x5f0 && $c <= 0x5f4) ||
                $c === 0x608 ||
                $c === 0x60b ||
                $c === 0x60d ||
                $c === 0x61b ||
                ($c >= 0x61e && $c <= 0x64a) ||
                ($c >= 0x66d && $c <= 0x66f) ||
                ($c >= 0x671 && $c <= 0x6d5) ||
                ($c >= 0x6e5 && $c <= 0x6e6) ||
                ($c >= 0x6ee && $c <= 0x6ef) ||
                ($c >= 0x6fa && $c <= 0x70d) ||
                $c === 0x710 ||
                ($c >= 0x712 && $c <= 0x72f) ||
                ($c >= 0x74d && $c <= 0x7a5) ||
                $c === 0x7b1 ||
                ($c >= 0x7c0 && $c <= 0x7ea) ||
                ($c >= 0x7f4 && $c <= 0x7f5) ||
                $c === 0x7fa ||
                ($c >= 0x800 && $c <= 0x815) ||
                $c === 0x81a ||
                $c === 0x824 ||
                $c === 0x828 ||
                ($c >= 0x830 && $c <= 0x83e) ||
                ($c >= 0x840 && $c <= 0x858) ||
                $c === 0x85e
            ) {
                return 'RTL';
            }
        } elseif ($c === 0x200f) {
            return 'RTL';
        } elseif ($c >= 0xfb1d) {
            if ($c === 0xfb1d ||
                ($c >= 0xfb1f && $c <= 0xfb28) ||
                ($c >= 0xfb2a && $c <= 0xfb36) ||
                ($c >= 0xfb38 && $c <= 0xfb3c) ||
                $c === 0xfb3e ||
                ($c >= 0xfb40 && $c <= 0xfb41) ||
                ($c >= 0xfb43 && $c <= 0xfb44) ||
                ($c >= 0xfb46 && $c <= 0xfbc1) ||
                ($c >= 0xfbd3 && $c <= 0xfd3d) ||
                ($c >= 0xfd50 && $c <= 0xfd8f) ||
                ($c >= 0xfd92 && $c <= 0xfdc7) ||
                ($c >= 0xfdf0 && $c <= 0xfdfc) ||
                ($c >= 0xfe70 && $c <= 0xfe74) ||
                ($c >= 0xfe76 && $c <= 0xfefc) ||
                ($c >= 0x10800 && $c <= 0x10805) ||
                $c === 0x10808 ||
                ($c >= 0x1080a && $c <= 0x10835) ||
                ($c >= 0x10837 && $c <= 0x10838) ||
                $c === 0x1083c ||
                ($c >= 0x1083f && $c <= 0x10855) ||
                ($c >= 0x10857 && $c <= 0x1085f) ||
                ($c >= 0x10900 && $c <= 0x1091b) ||
                ($c >= 0x10920 && $c <= 0x10939) ||
                $c === 0x1093f ||
                $c === 0x10a00 ||
                ($c >= 0x10a10 && $c <= 0x10a13) ||
                ($c >= 0x10a15 && $c <= 0x10a17) ||
                ($c >= 0x10a19 && $c <= 0x10a33) ||
                ($c >= 0x10a40 && $c <= 0x10a47) ||
                ($c >= 0x10a50 && $c <= 0x10a58) ||
                ($c >= 0x10a60 && $c <= 0x10a7f) ||
                ($c >= 0x10b00 && $c <= 0x10b35) ||
                ($c >= 0x10b40 && $c <= 0x10b55) ||
                ($c >= 0x10b58 && $c <= 0x10b72) ||
                ($c >= 0x10b78)
            ) {
                return 'RTL';
            }
        }

        return 'LTR';
    }

    /**
     * Check for php-support.
     *
     * @param string|null $key
     *
     * @psalm-pure
     *
     * @return mixed
     *               Return the full support-"array", if $key === null<br>
     *               return bool-value, if $key is used and available<br>
     *               otherwise return <strong>null</strong>
     */
    public static function getSupportInfo(string $key = null)
    {
        if ($key === null) {
            return self::$SUPPORT;
        }

        if (self::$INTL_TRANSLITERATOR_LIST === null) {
            self::$INTL_TRANSLITERATOR_LIST = self::getData('transliterator_list');
        }
        // compatibility fix for old versions
        self::$SUPPORT['intl__transliterator_list_ids'] = self::$INTL_TRANSLITERATOR_LIST;

        return self::$SUPPORT[$key] ?? null;
    }

    /**
     * Warning: this method only works for some file-types (png, jpg)
     *          if you need more supported types, please use e.g. "finfo"
     *
     * @param string                                                        $str
     * @param array{ext: null|string, mime: null|string, type: null|string} $fallback
     *
     * @return array{ext: null|string, mime: null|string, type: null|string}
     *
     * @psalm-pure
     */
    public static function get_file_type(
        string $str,
        array $fallback = [
            'ext'  => null,
            'mime' => 'application/octet-stream',
            'type' => null,
        ]
    ): array {
        if ($str === '') {
            return $fallback;
        }

        /** @var false|string $str_info - needed for PhpStan (stubs error) */
        $str_info = \substr($str, 0, 2);
        if ($str_info === false || \strlen($str_info) !== 2) {
            return $fallback;
        }

        // DEBUG
        //var_dump($str_info);

        $str_info = \unpack('C2chars', $str_info);

        if ($str_info === false) {
            return $fallback;
        }
        $type_code = (int) ($str_info['chars1'] . $str_info['chars2']);

        // DEBUG
        //var_dump($type_code);

        //
        // info: https://en.wikipedia.org/wiki/Magic_number_%28programming%29#Format_indicator
        //
        switch ($type_code) {
            // WARNING: do not add too simple comparisons, because of false-positive results:
            //
            // 3780 => 'pdf', 7790 => 'exe', 7784 => 'midi', 8075 => 'zip',
            // 8297 => 'rar', 7173 => 'gif', 7373 => 'tiff' 6677 => 'bmp', ...
            //
            case 255216:
                $ext = 'jpg';
                $mime = 'image/jpeg';
                $type = 'binary';

                break;
            case 13780:
                $ext = 'png';
                $mime = 'image/png';
                $type = 'binary';

                break;
            default:
                return $fallback;
        }

        return [
            'ext'  => $ext,
            'mime' => $mime,
            'type' => $type,
        ];
    }

    /**
     * @param int<1, max> $length         <p>Length of the random string.</p>
     * @param string      $possible_chars [optional] <p>Characters string for the random selection.</p>
     * @param string      $encoding       [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $possible_chars
     * @phpstan-return (T is non-empty-string ? non-empty-string : '')
     */
    public static function get_random_string(
        int $length,
        string $possible_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
        string $encoding = 'UTF-8'
    ): string {
        // init
        $i = 0;
        $str = '';

        //
        // add random chars
        //

        if ($encoding === 'UTF-8') {
            $max_length = (int) \mb_strlen($possible_chars);
            if ($max_length === 0) {
                return '';
            }

            while ($i < $length) {
                try {
                    $rand_int = \random_int(0, $max_length - 1);
                } catch (\Exception $e) {
                    $rand_int = \mt_rand(0, $max_length - 1);
                }
                $char = \mb_substr($possible_chars, $rand_int, 1);
                /* @phpstan-ignore-next-line | "false" was at least the return type in the past, or? */
                if ($char !== false) {
                    $str .= $char;
                    ++$i;
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $max_length = (int) self::strlen($possible_chars, $encoding);
            if ($max_length === 0) {
                return '';
            }

            while ($i < $length) {
                try {
                    $rand_int = \random_int(0, $max_length - 1);
                } catch (\Exception $e) {
                    $rand_int = \mt_rand(0, $max_length - 1);
                }
                $char = self::substr($possible_chars, $rand_int, 1, $encoding);
                if ($char !== false) {
                    $str .= $char;
                    ++$i;
                }
            }
        }

        return $str;
    }

    /**
     * @param int|string $extra_entropy [optional] <p>Extra entropy via a string or int value.</p>
     * @param bool       $use_md5       [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
     *
     * @return non-empty-string
     */
    public static function get_unique_string($extra_entropy = '', bool $use_md5 = true): string
    {
        try {
            $rand_int = \random_int(0, \mt_getrandmax());
        } catch (\Exception $e) {
            $rand_int = \mt_rand(0, \mt_getrandmax());
        }

        $unique_helper = $rand_int .
                         \session_id() .
                         ($_SERVER['REMOTE_ADDR'] ?? '') .
                         ($_SERVER['SERVER_ADDR'] ?? '') .
                         $extra_entropy;

        $unique_string = \uniqid($unique_helper, true);

        if ($use_md5) {
            $unique_string = \md5($unique_string . $unique_helper);
        }

        return $unique_string;
    }

    /**
     * Returns true if the string contains a lower case char, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not the string contains a lower case character.</p>
     */
    public static function has_lowercase(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('.*[[:lower:]]', $str);
        }

        return self::str_matches_pattern($str, '.*[[:lower:]]');
    }

    /**
     * Returns true if the string contains whitespace, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not the string contains whitespace.</p>
     */
    public static function has_whitespace(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('.*[[:space:]]', $str);
        }

        return self::str_matches_pattern($str, '.*[[:space:]]');
    }

    /**
     * Returns true if the string contains an upper case char, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not the string contains an upper case character.</p>
     */
    public static function has_uppercase(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('.*[[:upper:]]', $str);
        }

        return self::str_matches_pattern($str, '.*[[:upper:]]');
    }

    /**
     * Converts a hexadecimal value into a UTF-8 character.
     *
     * INFO: opposite to UTF8::chr_to_hex()
     *
     * EXAMPLE: <code>UTF8::hex_to_chr('U+00a7'); // '§'</code>
     *
     * @param string $hexdec <p>The hexadecimal value.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                      <p>One single UTF-8 character.</p>
     */
    public static function hex_to_chr(string $hexdec)
    {
        /** @noinspection PhpUsageOfSilenceOperatorInspection - Invalid characters passed for attempted conversion, these have been ignored */
        return self::decimal_to_chr((int) @\hexdec($hexdec));
    }

    /**
     * Converts hexadecimal U+xxxx code point representation to integer.
     *
     * INFO: opposite to UTF8::int_to_hex()
     *
     * EXAMPLE: <code>UTF8::hex_to_int('U+00f1'); // 241</code>
     *
     * @param string $hexdec <p>The hexadecimal code point representation.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The code point, or false on failure.</p>
     */
    public static function hex_to_int($hexdec)
    {
        // init
        $hexdec = (string) $hexdec;

        if ($hexdec === '') {
            return false;
        }

        if (\preg_match('/^(?:\\\u|U\+|)([a-zA-Z0-9]{4,6})$/', $hexdec, $match)) {
            return \intval($match[1], 16);
        }

        return false;
    }

    /**
     * Converts a UTF-8 string to a series of HTML numbered entities.
     *
     * INFO: opposite to UTF8::html_decode()
     *
     * EXAMPLE: <code>UTF8::html_encode('中文空白'); // '&#20013;&#25991;&#31354;&#30333;'</code>
     *
     * @param string $str              <p>The Unicode string to be encoded as numbered entities.</p>
     * @param bool   $keep_ascii_chars [optional] <p>Keep ASCII chars.</p>
     * @param string $encoding         [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>HTML numbered entities.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function html_encode(
        string $str,
        bool $keep_ascii_chars = false,
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '') {
            return '';
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        // INFO: http://stackoverflow.com/questions/35854535/better-explanation-of-convmap-in-mb-encode-numericentity
        if (self::$SUPPORT['mbstring'] === true) {
            if ($keep_ascii_chars) {
                $start_code = 0x80;
            } else {
                $start_code = 0x00;
            }

            if ($encoding === 'UTF-8') {
                /** @var false|string|null $return - needed for PhpStan (stubs error) */
                $return = \mb_encode_numericentity(
                    $str,
                    [$start_code, 0xfffff, 0, 0xfffff]
                );
                if ($return !== null && $return !== false) {
                    return $return;
                }
            }

            /** @var false|string|null $return - needed for PhpStan (stubs error) */
            $return = \mb_encode_numericentity(
                $str,
                [$start_code, 0xfffff, 0, 0xfffff],
                $encoding
            );
            if ($return !== null && $return !== false) {
                return $return;
            }
        }

        //
        // fallback via vanilla php
        //

        return \implode(
            '',
            \array_map(
                static function (string $chr) use ($keep_ascii_chars, $encoding): string {
                    return self::single_chr_html_encode($chr, $keep_ascii_chars, $encoding);
                },
                self::str_split($str)
            )
        );
    }

    /**
     * UTF-8 version of html_entity_decode()
     *
     * The reason we are not using html_entity_decode() by itself is because
     * while it is not technically correct to leave out the semicolon
     * at the end of an entity most browsers will still interpret the entity
     * correctly. html_entity_decode() does not convert entities without
     * semicolons, so we are left with our own little solution here. Bummer.
     *
     * Convert all HTML entities to their applicable characters.
     *
     * INFO: opposite to UTF8::html_encode()
     *
     * EXAMPLE: <code>UTF8::html_entity_decode('&#20013;&#25991;&#31354;&#30333;'); // '中文空白'</code>
     *
     * @see http://php.net/manual/en/function.html-entity-decode.php
     *
     * @param string   $str      <p>
     *                           The input string.
     *                           </p>
     * @param int|null $flags    [optional] <p>
     *                           A bitmask of one or more of the following flags, which specify how to handle quotes
     *                           and which document type to use. The default is ENT_COMPAT | ENT_HTML401.
     *                           <table>
     *                           Available <i>flags</i> constants
     *                           <tr valign="top">
     *                           <td>Constant Name</td>
     *                           <td>Description</td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_COMPAT</b></td>
     *                           <td>Will convert double-quotes and leave single-quotes alone.</td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_QUOTES</b></td>
     *                           <td>Will convert both double and single quotes.</td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_NOQUOTES</b></td>
     *                           <td>Will leave both double and single quotes unconverted.</td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_HTML401</b></td>
     *                           <td>
     *                           Handle code as HTML 4.01.
     *                           </td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_XML1</b></td>
     *                           <td>
     *                           Handle code as XML 1.
     *                           </td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_XHTML</b></td>
     *                           <td>
     *                           Handle code as XHTML.
     *                           </td>
     *                           </tr>
     *                           <tr valign="top">
     *                           <td><b>ENT_HTML5</b></td>
     *                           <td>
     *                           Handle code as HTML 5.
     *                           </td>
     *                           </tr>
     *                           </table>
     *                           </p>
     * @param string   $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The decoded string.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function html_entity_decode(
        string $str,
        int $flags = null,
        string $encoding = 'UTF-8'
    ): string {
        if (
            !isset($str[3]) // examples: &; || &x;
            ||
            \strpos($str, '&') === false // no "&"
        ) {
            return $str;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($flags === null) {
            $flags = \ENT_QUOTES | \ENT_HTML5;
        }

        if (
            $encoding !== 'UTF-8'
            &&
            $encoding !== 'ISO-8859-1'
            &&
            $encoding !== 'WINDOWS-1252'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::html_entity_decode() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        do {
            $str_compare = $str;

            if (\strpos($str, '&') !== false) {
                if (\strpos($str, '&#') !== false) {
                    // decode also numeric & UTF16 two byte entities
                    $str = (string) \preg_replace(
                        '/(&#(?:x0*[0-9a-fA-F]{2,6}(?![0-9a-fA-F;])|(?:0*\d{2,6}(?![0-9;]))))/S',
                        '$1;',
                        $str
                    );
                }

                $str = \html_entity_decode(
                    $str,
                    $flags,
                    $encoding
                );
            }
        } while ($str_compare !== $str);

        return $str;
    }

    /**
     * Create a escape html version of the string via "UTF8::htmlspecialchars()".
     *
     * @param string $str
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function html_escape(string $str, string $encoding = 'UTF-8'): string
    {
        return self::htmlspecialchars(
            $str,
            \ENT_QUOTES | \ENT_SUBSTITUTE,
            $encoding
        );
    }

    /**
     * Remove empty html-tag.
     *
     * e.g.: <pre><tag></tag></pre>
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function html_stripe_empty_tags(string $str): string
    {
        return (string) \preg_replace(
            '/<[^\\/>]*?>\\s*?<\\/[^>]*?>/u',
            '',
            $str
        );
    }

    /**
     * Convert all applicable characters to HTML entities: UTF-8 version of htmlentities().
     *
     * EXAMPLE: <code>UTF8::htmlentities('<白-öäü>'); // '&lt;&#30333;-&ouml;&auml;&uuml;&gt;'</code>
     *
     * @see http://php.net/manual/en/function.htmlentities.php
     *
     * @param string $str           <p>
     *                              The input string.
     *                              </p>
     * @param int    $flags         [optional] <p>
     *                              A bitmask of one or more of the following flags, which specify how to handle
     *                              quotes, invalid code unit sequences and the used document type. The default is
     *                              ENT_COMPAT | ENT_HTML401.
     *                              <table>
     *                              Available <i>flags</i> constants
     *                              <tr valign="top">
     *                              <td>Constant Name</td>
     *                              <td>Description</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_COMPAT</b></td>
     *                              <td>Will convert double-quotes and leave single-quotes alone.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_QUOTES</b></td>
     *                              <td>Will convert both double and single quotes.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_NOQUOTES</b></td>
     *                              <td>Will leave both double and single quotes unconverted.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_IGNORE</b></td>
     *                              <td>
     *                              Silently discard invalid code unit sequences instead of returning
     *                              an empty string. Using this flag is discouraged as it
     *                              may have security implications.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_SUBSTITUTE</b></td>
     *                              <td>
     *                              Replace invalid code unit sequences with a Unicode Replacement Character
     *                              U+FFFD (UTF-8) or &#38;#38;#FFFD; (otherwise) instead of returning an empty
     *                              string.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_DISALLOWED</b></td>
     *                              <td>
     *                              Replace invalid code points for the given document type with a
     *                              Unicode Replacement Character U+FFFD (UTF-8) or &#38;#38;#FFFD;
     *                              (otherwise) instead of leaving them as is. This may be useful, for
     *                              instance, to ensure the well-formedness of XML documents with
     *                              embedded external content.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_HTML401</b></td>
     *                              <td>
     *                              Handle code as HTML 4.01.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_XML1</b></td>
     *                              <td>
     *                              Handle code as XML 1.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_XHTML</b></td>
     *                              <td>
     *                              Handle code as XHTML.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_HTML5</b></td>
     *                              <td>
     *                              Handle code as HTML 5.
     *                              </td>
     *                              </tr>
     *                              </table>
     *                              </p>
     * @param string $encoding      [optional] <p>
     *                              Like <b>htmlspecialchars</b>,
     *                              <b>htmlentities</b> takes an optional third argument
     *                              <i>encoding</i> which defines encoding used in
     *                              conversion.
     *                              Although this argument is technically optional, you are highly
     *                              encouraged to specify the correct value for your code.
     *                              </p>
     * @param bool   $double_encode [optional] <p>
     *                              When <i>double_encode</i> is turned off PHP will not
     *                              encode existing html entities. The default is to convert everything.
     *                              </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>
     *                The encoded string.
     *                <br><br>
     *                If the input <i>string</i> contains an invalid code unit
     *                sequence within the given <i>encoding</i> an empty string
     *                will be returned, unless either the <b>ENT_IGNORE</b> or
     *                <b>ENT_SUBSTITUTE</b> flags are set.
     *                </p>
     */
    public static function htmlentities(
        string $str,
        int $flags = \ENT_COMPAT,
        string $encoding = 'UTF-8',
        bool $double_encode = true
    ): string {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        $str = \htmlentities(
            $str,
            $flags,
            $encoding,
            $double_encode
        );

        /**
         * PHP doesn't replace a backslash to its html entity since this is something
         * that's mostly used to escape characters when inserting in a database. Since
         * we're using a decent database layer, we don't need this shit and we're replacing
         * the double backslashes by its' html entity equivalent.
         *
         * https://github.com/forkcms/library/blob/master/spoon/filter/filter.php#L303
         */
        $str = \str_replace('\\', '&#92;', $str);

        return self::html_encode($str, true, $encoding);
    }

    /**
     * Convert only special characters to HTML entities: UTF-8 version of htmlspecialchars()
     *
     * INFO: Take a look at "UTF8::htmlentities()"
     *
     * EXAMPLE: <code>UTF8::htmlspecialchars('<白-öäü>'); // '&lt;白-öäü&gt;'</code>
     *
     * @see http://php.net/manual/en/function.htmlspecialchars.php
     *
     * @param string $str           <p>
     *                              The string being converted.
     *                              </p>
     * @param int    $flags         [optional] <p>
     *                              A bitmask of one or more of the following flags, which specify how to handle
     *                              quotes, invalid code unit sequences and the used document type. The default is
     *                              ENT_COMPAT | ENT_HTML401.
     *                              <table>
     *                              Available <i>flags</i> constants
     *                              <tr valign="top">
     *                              <td>Constant Name</td>
     *                              <td>Description</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_COMPAT</b></td>
     *                              <td>Will convert double-quotes and leave single-quotes alone.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_QUOTES</b></td>
     *                              <td>Will convert both double and single quotes.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_NOQUOTES</b></td>
     *                              <td>Will leave both double and single quotes unconverted.</td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_IGNORE</b></td>
     *                              <td>
     *                              Silently discard invalid code unit sequences instead of returning
     *                              an empty string. Using this flag is discouraged as it
     *                              may have security implications.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_SUBSTITUTE</b></td>
     *                              <td>
     *                              Replace invalid code unit sequences with a Unicode Replacement Character
     *                              U+FFFD (UTF-8) or &#38;#38;#FFFD; (otherwise) instead of returning an empty
     *                              string.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_DISALLOWED</b></td>
     *                              <td>
     *                              Replace invalid code points for the given document type with a
     *                              Unicode Replacement Character U+FFFD (UTF-8) or &#38;#38;#FFFD;
     *                              (otherwise) instead of leaving them as is. This may be useful, for
     *                              instance, to ensure the well-formedness of XML documents with
     *                              embedded external content.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_HTML401</b></td>
     *                              <td>
     *                              Handle code as HTML 4.01.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_XML1</b></td>
     *                              <td>
     *                              Handle code as XML 1.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_XHTML</b></td>
     *                              <td>
     *                              Handle code as XHTML.
     *                              </td>
     *                              </tr>
     *                              <tr valign="top">
     *                              <td><b>ENT_HTML5</b></td>
     *                              <td>
     *                              Handle code as HTML 5.
     *                              </td>
     *                              </tr>
     *                              </table>
     *                              </p>
     * @param string $encoding      [optional] <p>
     *                              Defines encoding used in conversion.
     *                              </p>
     *                              <p>
     *                              For the purposes of this function, the encodings
     *                              ISO-8859-1, ISO-8859-15,
     *                              UTF-8, cp866,
     *                              cp1251, cp1252, and
     *                              KOI8-R are effectively equivalent, provided the
     *                              <i>string</i> itself is valid for the encoding, as
     *                              the characters affected by <b>htmlspecialchars</b> occupy
     *                              the same positions in all of these encodings.
     *                              </p>
     * @param bool   $double_encode [optional] <p>
     *                              When <i>double_encode</i> is turned off PHP will not
     *                              encode existing html entities, the default is to convert everything.
     *                              </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The converted string.</p>
     *                <p>
     *                If the input <i>string</i> contains an invalid code unit
     *                sequence within the given <i>encoding</i> an empty string
     *                will be returned, unless either the <b>ENT_IGNORE</b> or
     *                <b>ENT_SUBSTITUTE</b> flags are set.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function htmlspecialchars(
        string $str,
        int $flags = \ENT_COMPAT,
        string $encoding = 'UTF-8',
        bool $double_encode = true
    ): string {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        return \htmlspecialchars(
            $str,
            $flags,
            $encoding,
            $double_encode
        );
    }

    /**
     * Checks whether iconv is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function iconv_loaded(): bool
    {
        return \extension_loaded('iconv');
    }

    /**
     * Converts Integer to hexadecimal U+xxxx code point representation.
     *
     * INFO: opposite to UTF8::hex_to_int()
     *
     * EXAMPLE: <code>UTF8::int_to_hex(241); // 'U+00f1'</code>
     *
     * @param int    $int    <p>The integer to be converted to hexadecimal code point.</p>
     * @param string $prefix [optional]
     *
     * @psalm-pure
     *
     * @return string the code point, or empty string on failure
     */
    public static function int_to_hex(int $int, string $prefix = 'U+'): string
    {
        $hex = \dechex($int);

        $hex = (\strlen($hex) < 4 ? \substr('0000' . $hex, -4) : $hex);

        return $prefix . $hex . '';
    }

    /**
     * Checks whether intl-char is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function intlChar_loaded(): bool
    {
        return \class_exists('IntlChar');
    }

    /**
     * Checks whether intl is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function intl_loaded(): bool
    {
        return \extension_loaded('intl');
    }

    /**
     * Returns true if the string contains only alphabetic chars, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only alphabetic chars.</p>
     */
    public static function is_alpha(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:alpha:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:alpha:]]*$');
    }

    /**
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
     */
    public static function is_alphanumeric(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:alnum:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:alnum:]]*$');
    }

    /**
     * Returns true if the string contains only punctuation chars, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only punctuation chars.</p>
     */
    public static function is_punctuation(string $str): bool
    {
        return self::str_matches_pattern($str, '^[[:punct:]]*$');
    }

    /**
     * Returns true if the string contains only printable (non-invisible) chars, false otherwise.
     *
     * @param string $str                       <p>The input string.</p>
     * @param bool   $ignore_control_characters [optional] <p>Ignore control characters like [LRM] or [LSEP].</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only printable (non-invisible) chars.</p>
     */
    public static function is_printable(string $str, bool $ignore_control_characters = false): bool
    {
        return self::remove_invisible_characters($str, false, '', $ignore_control_characters) === $str;
    }

    /**
     * Checks if a string is 7 bit ASCII.
     *
     * EXAMPLE: <code>UTF8::is_ascii('白'); // false</code>
     *
     * @param string $str <p>The string to check.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>
     *              <strong>true</strong> if it is ASCII<br>
     *              <strong>false</strong> otherwise
     *              </p>
     */
    public static function is_ascii(string $str): bool
    {
        return ASCII::is_ascii($str);
    }

    /**
     * Returns true if the string is base64 encoded, false otherwise.
     *
     * EXAMPLE: <code>UTF8::is_base64('4KSu4KWL4KSo4KS/4KSa'); // true</code>
     *
     * @param string|null $str                   <p>The input string.</p>
     * @param bool        $empty_string_is_valid [optional] <p>Is an empty string valid base64 or not?</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str is base64 encoded.</p>
     */
    public static function is_base64($str, bool $empty_string_is_valid = false): bool
    {
        if (
            !$empty_string_is_valid
            &&
            $str === ''
        ) {
            return false;
        }

        if (!\is_string($str)) {
            return false;
        }

        $base64String = \base64_decode($str, true);

        return $base64String !== false && \base64_encode($base64String) === $str;
    }

    /**
     * Check if the input is binary... (is look like a hack).
     *
     * EXAMPLE: <code>UTF8::is_binary(01); // true</code>
     *
     * @param int|string $input
     * @param bool       $strict
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function is_binary($input, bool $strict = false): bool
    {
        $input = (string) $input;
        if ($input === '') {
            return false;
        }

        if (\preg_match('~^[01]+$~', $input)) {
            return true;
        }

        $ext = self::get_file_type($input);
        if ($ext['type'] === 'binary') {
            return true;
        }

        if (!$strict) {
            $test_length = \strlen($input);
            $test_null_counting = \substr_count($input, "\x0", 0, $test_length);
            if (($test_null_counting / $test_length) > 0.25) {
                return true;
            }
        }

        if ($strict) {
            if (self::$SUPPORT['finfo'] === false) {
                throw new \RuntimeException('ext-fileinfo: is not installed');
            }

            /**
             * @psalm-suppress ImpureMethodCall - it will return the same result for the same file ...
             */
            $finfo_encoding = (new \finfo(\FILEINFO_MIME_ENCODING))->buffer($input);
            if ($finfo_encoding && $finfo_encoding === 'binary') {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if the file is binary.
     *
     * EXAMPLE: <code>UTF8::is_binary('./utf32.txt'); // true</code>
     *
     * @param string $file
     *
     * @return bool
     */
    public static function is_binary_file($file): bool
    {
        // init
        $block = '';

        $fp = \fopen($file, 'rb');
        if (\is_resource($fp)) {
            $block = \fread($fp, 512);
            \fclose($fp);
        }

        if ($block === '' || $block === false) {
            return false;
        }

        return self::is_binary($block, true);
    }

    /**
     * Returns true if the string contains only whitespace chars, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only whitespace characters.</p>
     */
    public static function is_blank(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:space:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:space:]]*$');
    }

    /**
     * Checks if the given string is equal to any "Byte Order Mark".
     *
     * WARNING: Use "UTF8::string_has_bom()" if you will check BOM in a string.
     *
     * EXAMPLE: <code>UTF8::is_bom("\xef\xbb\xbf"); // true</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if the $utf8_chr is Byte Order Mark, <strong>false</strong> otherwise.</p>
     */
    public static function is_bom($str): bool
    {
        /** @noinspection PhpUnusedLocalVariableInspection */
        foreach (self::$BOM as $bom_string => &$bom_byte_length) {
            if ($str === $bom_string) {
                return true;
            }
        }

        return false;
    }

    /**
     * Determine whether the string is considered to be empty.
     *
     * A variable is considered empty if it does not exist or if its value equals FALSE.
     * empty() does not generate a warning if the variable does not exist.
     *
     * @param array<array-key, mixed>|float|int|string $str
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str is empty().</p>
     */
    public static function is_empty($str): bool
    {
        return empty($str);
    }

    /**
     * Returns true if the string contains only hexadecimal chars, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
     */
    public static function is_hexadecimal(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:xdigit:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:xdigit:]]*$');
    }

    /**
     * Check if the string contains any HTML tags.
     *
     * EXAMPLE: <code>UTF8::is_html('<b>lall</b>'); // true</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains html elements.</p>
     */
    public static function is_html(string $str): bool
    {
        if ($str === '') {
            return false;
        }

        // init
        $matches = [];

        $str = self::emoji_encode($str); // hack for emoji support :/

        \preg_match("/<\\/?\\w+(?:(?:\\s+\\w+(?:\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)*\\s*|\\s*)\\/?>/u", $str, $matches);

        return $matches !== [];
    }

    /**
     * Check if $url is an correct url.
     *
     * @param string $url
     * @param bool   $disallow_localhost
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function is_url(string $url, bool $disallow_localhost = false): bool
    {
        if ($url === '') {
            return false;
        }

        // WARNING: keep this as hack protection
        if (!self::str_istarts_with_any($url, ['http://', 'https://'])) {
            return false;
        }

        // e.g. -> the server itself connect to "https://foo.localhost/phpmyadmin/...
        if ($disallow_localhost) {
            if (self::str_istarts_with_any(
                $url,
                [
                    'http://localhost',
                    'https://localhost',
                    'http://127.0.0.1',
                    'https://127.0.0.1',
                    'http://::1',
                    'https://::1',
                ]
            )) {
                return false;
            }

            $regex = '/^(?:http(?:s)?:\/\/).*?(?:\.localhost)/iu';
            if (\preg_match($regex, $url)) {
                return false;
            }
        }

        // INFO: this is needed for e.g. "http://müller.de/" (internationalized domain names) and non ASCII-parameters
        $regex = '/^(?:http(?:s)?:\\/\\/)(?:[\p{L}0-9][\p{L}0-9_-]*(?:\\.[\p{L}0-9][\p{L}0-9_-]*))(?:\\d+)?(?:\\/\\.*)?/iu';
        if (\preg_match($regex, $url)) {
            return true;
        }

        return \filter_var($url, \FILTER_VALIDATE_URL) !== false;
    }

    /**
     * Try to check if "$str" is a JSON-string.
     *
     * EXAMPLE: <code>UTF8::is_json('{"array":[1,"¥","ä"]}'); // true</code>
     *
     * @param string $str                                    <p>The input string.</p>
     * @param bool   $only_array_or_object_results_are_valid [optional] <p>Only array and objects are valid json
     *                                                       results.</p>
     *
     * @return bool
     *              <p>Whether or not the $str is in JSON format.</p>
     */
    public static function is_json(string $str, bool $only_array_or_object_results_are_valid = true): bool
    {
        if ($str === '') {
            return false;
        }

        if (self::$SUPPORT['json'] === false) {
            throw new \RuntimeException('ext-json: is not installed');
        }

        $jsonOrNull = self::json_decode($str);
        if ($jsonOrNull === null && \strtoupper($str) !== 'NULL') {
            return false;
        }

        if (
            $only_array_or_object_results_are_valid
            &&
            !\is_object($jsonOrNull)
            &&
            !\is_array($jsonOrNull)
        ) {
            return false;
        }

        return \json_last_error() === \JSON_ERROR_NONE;
    }

    /**
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only lowercase chars.</p>
     */
    public static function is_lowercase(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:lower:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:lower:]]*$');
    }

    /**
     * Returns true if the string is serialized, false otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str is serialized.</p>
     */
    public static function is_serialized(string $str): bool
    {
        if ($str === '') {
            return false;
        }

        /** @noinspection PhpUsageOfSilenceOperatorInspection */
        /** @noinspection UnserializeExploitsInspection */
        return $str === 'b:0;'
               ||
               @\unserialize($str, []) !== false;
    }

    /**
     * Returns true if the string contains only lower case chars, false
     * otherwise.
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains only lower case characters.</p>
     */
    public static function is_uppercase(string $str): bool
    {
        if (self::$SUPPORT['mbstring'] === true) {
            return \mb_ereg_match('^[[:upper:]]*$', $str);
        }

        return self::str_matches_pattern($str, '^[[:upper:]]*$');
    }

    /**
     * Check if the string is UTF-16.
     *
     * EXAMPLE: <code>
     * UTF8::is_utf16(file_get_contents('utf-16-le.txt')); // 1
     * //
     * UTF8::is_utf16(file_get_contents('utf-16-be.txt')); // 2
     * //
     * UTF8::is_utf16(file_get_contents('utf-8.txt')); // false
     * </code>
     *
     * @param string $str                       <p>The input string.</p>
     * @param bool   $check_if_string_is_binary
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <strong>false</strong> if is't not UTF-16,<br>
     *                   <strong>1</strong> for UTF-16LE,<br>
     *                   <strong>2</strong> for UTF-16BE
     */
    public static function is_utf16($str, bool $check_if_string_is_binary = true)
    {
        // init
        $str = (string) $str;
        $str_chars = [];

        // fix for the "binary"-check
        if ($check_if_string_is_binary !== false && self::string_has_bom($str)) {
            $check_if_string_is_binary = false;
        }

        if (
            $check_if_string_is_binary
            &&
            !self::is_binary($str, true)
        ) {
            return false;
        }

        if (self::$SUPPORT['mbstring'] === false) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::is_utf16() without mbstring may did not work correctly', \E_USER_WARNING);
        }

        $str = self::remove_bom($str);

        $maybe_utf16le = 0;
        $test = \mb_convert_encoding($str, 'UTF-8', 'UTF-16LE');
        if ($test) {
            $test2 = \mb_convert_encoding($test, 'UTF-16LE', 'UTF-8');
            $test3 = \mb_convert_encoding($test2, 'UTF-8', 'UTF-16LE');
            if ($test3 === $test) {
                $str_chars = self::count_chars($str, true, false);
                foreach (self::count_chars($test3) as $test3char => &$test3charEmpty) {
                    if (\in_array($test3char, $str_chars, true)) {
                        ++$maybe_utf16le;
                    }
                }
                unset($test3charEmpty);
            }
        }

        $maybe_utf16be = 0;
        $test = \mb_convert_encoding($str, 'UTF-8', 'UTF-16BE');
        if ($test) {
            $test2 = \mb_convert_encoding($test, 'UTF-16BE', 'UTF-8');
            $test3 = \mb_convert_encoding($test2, 'UTF-8', 'UTF-16BE');
            if ($test3 === $test) {
                if ($str_chars === []) {
                    $str_chars = self::count_chars($str, true, false);
                }
                foreach (self::count_chars($test3) as $test3char => &$test3charEmpty) {
                    if (\in_array($test3char, $str_chars, true)) {
                        ++$maybe_utf16be;
                    }
                }
                unset($test3charEmpty);
            }
        }

        if ($maybe_utf16be !== $maybe_utf16le) {
            if ($maybe_utf16le > $maybe_utf16be) {
                return 1;
            }

            return 2;
        }

        return false;
    }

    /**
     * Check if the string is UTF-32.
     *
     * EXAMPLE: <code>
     * UTF8::is_utf32(file_get_contents('utf-32-le.txt')); // 1
     * //
     * UTF8::is_utf32(file_get_contents('utf-32-be.txt')); // 2
     * //
     * UTF8::is_utf32(file_get_contents('utf-8.txt')); // false
     * </code>
     *
     * @param string $str                       <p>The input string.</p>
     * @param bool   $check_if_string_is_binary
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <strong>false</strong> if is't not UTF-32,<br>
     *                   <strong>1</strong> for UTF-32LE,<br>
     *                   <strong>2</strong> for UTF-32BE
     */
    public static function is_utf32($str, bool $check_if_string_is_binary = true)
    {
        // init
        $str = (string) $str;
        $str_chars = [];

        // fix for the "binary"-check
        if ($check_if_string_is_binary !== false && self::string_has_bom($str)) {
            $check_if_string_is_binary = false;
        }

        if (
            $check_if_string_is_binary
            &&
            !self::is_binary($str, true)
        ) {
            return false;
        }

        if (self::$SUPPORT['mbstring'] === false) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::is_utf32() without mbstring may did not work correctly', \E_USER_WARNING);
        }

        $str = self::remove_bom($str);

        $maybe_utf32le = 0;
        $test = \mb_convert_encoding($str, 'UTF-8', 'UTF-32LE');
        if ($test) {
            $test2 = \mb_convert_encoding($test, 'UTF-32LE', 'UTF-8');
            $test3 = \mb_convert_encoding($test2, 'UTF-8', 'UTF-32LE');
            if ($test3 === $test) {
                $str_chars = self::count_chars($str, true, false);
                foreach (self::count_chars($test3) as $test3char => &$test3charEmpty) {
                    if (\in_array($test3char, $str_chars, true)) {
                        ++$maybe_utf32le;
                    }
                }
                unset($test3charEmpty);
            }
        }

        $maybe_utf32be = 0;
        $test = \mb_convert_encoding($str, 'UTF-8', 'UTF-32BE');
        if ($test) {
            $test2 = \mb_convert_encoding($test, 'UTF-32BE', 'UTF-8');
            $test3 = \mb_convert_encoding($test2, 'UTF-8', 'UTF-32BE');
            if ($test3 === $test) {
                if ($str_chars === []) {
                    $str_chars = self::count_chars($str, true, false);
                }
                foreach (self::count_chars($test3) as $test3char => &$test3charEmpty) {
                    if (\in_array($test3char, $str_chars, true)) {
                        ++$maybe_utf32be;
                    }
                }
                unset($test3charEmpty);
            }
        }

        if ($maybe_utf32be !== $maybe_utf32le) {
            if ($maybe_utf32le > $maybe_utf32be) {
                return 1;
            }

            return 2;
        }

        return false;
    }

    /**
     * Checks whether the passed input contains only byte sequences that appear valid UTF-8.
     *
     * EXAMPLE: <code>
     * UTF8::is_utf8(['Iñtërnâtiônàlizætiøn', 'foo']); // true
     * //
     * UTF8::is_utf8(["Iñtërnâtiônàlizætiøn\xA0\xA1", 'bar']); // false
     * </code>
     *
     * @param int|string|string[]|null $str    <p>The input to be checked.</p>
     * @param bool                     $strict <p>Check also if the string is not UTF-16 or UTF-32.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function is_utf8($str, bool $strict = false): bool
    {
        if (\is_array($str)) {
            foreach ($str as &$v) {
                if (!self::is_utf8($v, $strict)) {
                    return false;
                }
            }

            return true;
        }

        return self::is_utf8_string((string) $str, $strict);
    }

    /**
     * (PHP 5 &gt;= 5.2.0, PECL json &gt;= 1.2.0)<br/>
     * Decodes a JSON string
     *
     * EXAMPLE: <code>UTF8::json_decode('[1,"\u00a5","\u00e4"]'); // array(1, '¥', 'ä')</code>
     *
     * @see http://php.net/manual/en/function.json-decode.php
     *
     * @param string $json    <p>
     *                        The <i>json</i> string being decoded.
     *                        </p>
     *                        <p>
     *                        This function only works with UTF-8 encoded strings.
     *                        </p>
     *                        <p>PHP implements a superset of
     *                        JSON - it will also encode and decode scalar types and <b>NULL</b>. The JSON standard
     *                        only supports these values when they are nested inside an array or an object.
     *                        </p>
     * @param bool   $assoc   [optional] <p>
     *                        When <b>TRUE</b>, returned objects will be converted into
     *                        associative arrays.
     *                        </p>
     * @param int    $depth   [optional] <p>
     *                        User specified recursion depth.
     *                        </p>
     * @param int    $options [optional] <p>
     *                        Bitmask of JSON decode options. Currently only
     *                        <b>JSON_BIGINT_AS_STRING</b>
     *                        is supported (default is to cast large integers as floats)
     *                        </p>
     *
     * @psalm-pure
     *
     * @return mixed
     *               <p>The value encoded in <i>json</i> in appropriate PHP type. Values true, false and
     *               null (case-insensitive) are returned as <b>TRUE</b>, <b>FALSE</b> and <b>NULL</b> respectively.
     *               <b>NULL</b> is returned if the <i>json</i> cannot be decoded or if the encoded data
     *               is deeper than the recursion limit.</p>
     */
    public static function json_decode(
        string $json,
        bool $assoc = false,
        int $depth = 512,
        int $options = 0
    ) {
        $json = self::filter($json);

        if (self::$SUPPORT['json'] === false) {
            throw new \RuntimeException('ext-json: is not installed');
        }

        if ($depth < 1) {
            $depth = 1;
        }

        return \json_decode($json, $assoc, $depth, $options);
    }

    /**
     * (PHP 5 &gt;= 5.2.0, PECL json &gt;= 1.2.0)<br/>
     * Returns the JSON representation of a value.
     *
     * EXAMPLE: <code>UTF8::json_encode(array(1, '¥', 'ä')); // '[1,"\u00a5","\u00e4"]'</code>
     *
     * @see http://php.net/manual/en/function.json-encode.php
     *
     * @param mixed $value   <p>
     *                       The <i>value</i> being encoded. Can be any type except
     *                       a resource.
     *                       </p>
     *                       <p>
     *                       All string data must be UTF-8 encoded.
     *                       </p>
     *                       <p>PHP implements a superset of
     *                       JSON - it will also encode and decode scalar types and <b>NULL</b>. The JSON standard
     *                       only supports these values when they are nested inside an array or an object.
     *                       </p>
     * @param int   $options [optional] <p>
     *                       Bitmask consisting of <b>JSON_HEX_QUOT</b>,
     *                       <b>JSON_HEX_TAG</b>,
     *                       <b>JSON_HEX_AMP</b>,
     *                       <b>JSON_HEX_APOS</b>,
     *                       <b>JSON_NUMERIC_CHECK</b>,
     *                       <b>JSON_PRETTY_PRINT</b>,
     *                       <b>JSON_UNESCAPED_SLASHES</b>,
     *                       <b>JSON_FORCE_OBJECT</b>,
     *                       <b>JSON_UNESCAPED_UNICODE</b>. The behaviour of these
     *                       constants is described on
     *                       the JSON constants page.
     *                       </p>
     * @param int   $depth   [optional] <p>
     *                       Set the maximum depth. Must be greater than zero.
     *                       </p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>A JSON encoded <strong>string</strong> on success or<br>
     *                      <strong>FALSE</strong> on failure.</p>
     */
    public static function json_encode($value, int $options = 0, int $depth = 512)
    {
        $value = self::filter($value);

        if (self::$SUPPORT['json'] === false) {
            throw new \RuntimeException('ext-json: is not installed');
        }

        if ($depth < 1) {
            $depth = 1;
        }

        return \json_encode($value, $options, $depth);
    }

    /**
     * Checks whether JSON is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function json_loaded(): bool
    {
        return \function_exists('json_decode');
    }

    /**
     * Makes string's first char lowercase.
     *
     * EXAMPLE: <code>UTF8::lcfirst('ÑTËRNÂTIÔNÀLIZÆTIØN'); // ñTËRNÂTIÔNÀLIZÆTIØN</code>
     *
     * @param string      $str                           <p>The input string</p>
     * @param string      $encoding                      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The resulting string.</p>
     */
    public static function lcfirst(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if ($clean_utf8) {
            $str = self::clean($str);
        }

        $use_mb_functions = ($lang === null && !$try_to_keep_the_string_length);

        if ($encoding === 'UTF-8') {
            $str_part_two = (string) \mb_substr($str, 1);

            if ($use_mb_functions) {
                $str_part_one = \mb_strtolower(
                    (string) \mb_substr($str, 0, 1)
                );
            } else {
                $str_part_one = self::strtolower(
                    (string) \mb_substr($str, 0, 1),
                    $encoding,
                    false,
                    $lang,
                    $try_to_keep_the_string_length
                );
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $str_part_two = (string) self::substr($str, 1, null, $encoding);

            $str_part_one = self::strtolower(
                (string) self::substr($str, 0, 1, $encoding),
                $encoding,
                false,
                $lang,
                $try_to_keep_the_string_length
            );
        }

        return $str_part_one . $str_part_two;
    }

    /**
     * Lowercase for all words in the string.
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string[]    $exceptions                    [optional] <p>Exclusion for some words.</p>
     * @param string      $char_list                     [optional] <p>Additional chars that contains to words and do
     *                                                   not start a new word.</p>
     * @param string      $encoding                      [optional] <p>Set the charset.</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function lcwords(
        string $str,
        array $exceptions = [],
        string $char_list = '',
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if (!$str) {
            return '';
        }

        $words = self::str_to_words($str, $char_list);
        $use_exceptions = $exceptions !== [];

        $words_str = '';
        foreach ($words as &$word) {
            if (!$word) {
                continue;
            }

            if (
                !$use_exceptions
                ||
                !\in_array($word, $exceptions, true)
            ) {
                $words_str .= self::lcfirst($word, $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length);
            } else {
                $words_str .= $word;
            }
        }

        return $words_str;
    }

    /**
     * Calculate Levenshtein distance between two strings.
     *
     * For better performance, in a real application with a single input string
     * matched against many strings from a database, you will probably want to pre-
     * encode the input only once and use \levenshtein().
     *
     * Source: https://github.com/KEINOS/mb_levenshtein
     *
     * @see https://www.php.net/manual/en/function.levenshtein
     *
     * @param string $str1            <p>One of the strings being evaluated for Levenshtein distance.</p>
     * @param string $str2            <p>One of the strings being evaluated for Levenshtein distance.</p>
     * @param int    $insertionCost   [optional] <p>Defines the cost of insertion.</p>
     * @param int    $replacementCost [optional] <p>Defines the cost of replacement.</p>
     * @param int    $deletionCost    [optional] <p>Defines the cost of deletion.</p>
     *
     * @return int
     */
    public static function levenshtein(
        string $str1,
        string $str2,
        int $insertionCost = 1,
        int $replacementCost = 1,
        int $deletionCost = 1
    ): int {
        $result = ASCII::to_ascii_remap($str1, $str2);

        return \levenshtein($result[0], $result[1], $insertionCost, $replacementCost, $deletionCost);
    }

    /**
     * Strip whitespace or other characters from the beginning of a UTF-8 string.
     *
     * EXAMPLE: <code>UTF8::ltrim('　中文空白　 '); // '中文空白　 '</code>
     *
     * @param string      $str   <p>The string to be trimmed</p>
     * @param string|null $chars <p>Optional characters to be stripped</p>
     *
     * @psalm-pure
     *
     * @return string the string with unwanted characters stripped from the left
     */
    public static function ltrim(string $str = '', string $chars = null): string
    {
        if ($str === '') {
            return '';
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($chars !== null) {
                /** @noinspection PregQuoteUsageInspection */
                $chars = \preg_quote($chars);
                $pattern = "^[{$chars}]+";
            } else {
                $pattern = '^[\\s]+';
            }

            return (string) \mb_ereg_replace($pattern, '', $str);
        }

        if ($chars !== null) {
            $chars = \preg_quote($chars, '/');
            $pattern = "^[{$chars}]+";
        } else {
            $pattern = '^[\\s]+';
        }

        return self::regex_replace($str, $pattern, '');
    }

    /**
     * Returns the UTF-8 character with the maximum code point in the given data.
     *
     * EXAMPLE: <code>UTF8::max('abc-äöü-中文空白'); // 'ø'</code>
     *
     * @param string|string[] $arg <p>A UTF-8 encoded string or an array of such strings.</p>
     *
     * @psalm-pure
     *
     * @return string|null the character with the highest code point than others, returns null on failure or empty input
     */
    public static function max($arg)
    {
        if (\is_array($arg)) {
            $arg = \implode('', $arg);
        }

        $codepoints = self::codepoints($arg);
        if ($codepoints === []) {
            return null;
        }

        $codepoint_max = \max($codepoints);

        return self::chr((int) $codepoint_max);
    }

    /**
     * Calculates and returns the maximum number of bytes taken by any
     * UTF-8 encoded character in the given string.
     *
     * EXAMPLE: <code>UTF8::max_chr_width('Intërnâtiônàlizætiøn'); // 2</code>
     *
     * @param string $str <p>The original Unicode string.</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <p>Max byte lengths of the given chars.</p>
     *
     * @phpstan-return 0|1|2|3|4
     */
    public static function max_chr_width(string $str): int
    {
        $bytes = self::chr_size_list($str);
        if ($bytes !== []) {
            return (int) \max($bytes);
        }

        return 0;
    }

    /**
     * Checks whether mbstring is available on the server.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if available, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function mbstring_loaded(): bool
    {
        return \extension_loaded('mbstring');
    }

    /**
     * Returns the UTF-8 character with the minimum code point in the given data.
     *
     * EXAMPLE: <code>UTF8::min('abc-äöü-中文空白'); // '-'</code>
     *
     * @param string|string[] $arg <strong>A UTF-8 encoded string or an array of such strings.</strong>
     *
     * @psalm-pure
     *
     * @return string|null
     *                     <p>The character with the lowest code point than others, returns null on failure or empty input.</p>
     */
    public static function min($arg)
    {
        if (\is_array($arg)) {
            $arg = \implode('', $arg);
        }

        $codepoints = self::codepoints($arg);
        if ($codepoints === []) {
            return null;
        }

        $codepoint_min = \min($codepoints);

        return self::chr((int) $codepoint_min);
    }

    /**
     * Normalize the encoding-"name" input.
     *
     * EXAMPLE: <code>UTF8::normalize_encoding('UTF8'); // 'UTF-8'</code>
     *
     * @param mixed $encoding <p>e.g.: ISO, UTF8, WINDOWS-1251 etc.</p>
     * @param mixed $fallback <p>e.g.: UTF-8</p>
     *
     * @psalm-pure
     *
     * @return mixed|string
     *                      <p>e.g.: ISO-8859-1, UTF-8, WINDOWS-1251 etc.<br>Will return a empty string as fallback (by default)</p>
     *
     * @template TNormalizeEncodingFallback
     * @phpstan-param string|TNormalizeEncodingFallback $fallback
     * @phpstan-return string|TNormalizeEncodingFallback
     */
    public static function normalize_encoding($encoding, $fallback = '')
    {
        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<string,string>
         */
        static $STATIC_NORMALIZE_ENCODING_CACHE = [];

        // init
        $encoding = (string) $encoding;

        if (!$encoding) {
            return $fallback;
        }

        if (
            $encoding === 'UTF-8'
            ||
            $encoding === 'UTF8'
        ) {
            return 'UTF-8';
        }

        if (
            $encoding === '8BIT'
            ||
            $encoding === 'BINARY'
        ) {
            return 'CP850';
        }

        if (
            $encoding === 'HTML'
            ||
            $encoding === 'HTML-ENTITIES'
        ) {
            return 'HTML-ENTITIES';
        }

        if (
            $encoding === 'ISO'
            ||
            $encoding === 'ISO-8859-1'
        ) {
            return 'ISO-8859-1';
        }

        // only a fallback, for non "strict_types" usage ...
        if ($encoding === '1') {
            return $fallback;
        }

        if (isset($STATIC_NORMALIZE_ENCODING_CACHE[$encoding])) {
            return $STATIC_NORMALIZE_ENCODING_CACHE[$encoding];
        }

        if (self::$ENCODINGS === null) {
            self::$ENCODINGS = self::getData('encodings');
        }

        if (\in_array($encoding, self::$ENCODINGS, true)) {
            $STATIC_NORMALIZE_ENCODING_CACHE[$encoding] = $encoding;

            return $encoding;
        }

        $encoding_original = $encoding;
        $encoding = \strtoupper($encoding);
        $encoding_upper_helper = (string) \preg_replace('/[^a-zA-Z0-9]/u', '', $encoding);

        $equivalences = [
            'ISO8859'     => 'ISO-8859-1',
            'ISO88591'    => 'ISO-8859-1',
            'ISO'         => 'ISO-8859-1',
            'LATIN'       => 'ISO-8859-1',
            'LATIN1'      => 'ISO-8859-1', // Western European
            'ISO88592'    => 'ISO-8859-2',
            'LATIN2'      => 'ISO-8859-2', // Central European
            'ISO88593'    => 'ISO-8859-3',
            'LATIN3'      => 'ISO-8859-3', // Southern European
            'ISO88594'    => 'ISO-8859-4',
            'LATIN4'      => 'ISO-8859-4', // Northern European
            'ISO88595'    => 'ISO-8859-5',
            'ISO88596'    => 'ISO-8859-6', // Greek
            'ISO88597'    => 'ISO-8859-7',
            'ISO88598'    => 'ISO-8859-8', // Hebrew
            'ISO88599'    => 'ISO-8859-9',
            'LATIN5'      => 'ISO-8859-9', // Turkish
            'ISO885911'   => 'ISO-8859-11',
            'TIS620'      => 'ISO-8859-11', // Thai
            'ISO885910'   => 'ISO-8859-10',
            'LATIN6'      => 'ISO-8859-10', // Nordic
            'ISO885913'   => 'ISO-8859-13',
            'LATIN7'      => 'ISO-8859-13', // Baltic
            'ISO885914'   => 'ISO-8859-14',
            'LATIN8'      => 'ISO-8859-14', // Celtic
            'ISO885915'   => 'ISO-8859-15',
            'LATIN9'      => 'ISO-8859-15', // Western European (with some extra chars e.g. €)
            'ISO885916'   => 'ISO-8859-16',
            'LATIN10'     => 'ISO-8859-16', // Southeast European
            'CP1250'      => 'WINDOWS-1250',
            'WIN1250'     => 'WINDOWS-1250',
            'WINDOWS1250' => 'WINDOWS-1250',
            'CP1251'      => 'WINDOWS-1251',
            'WIN1251'     => 'WINDOWS-1251',
            'WINDOWS1251' => 'WINDOWS-1251',
            'CP1252'      => 'WINDOWS-1252',
            'WIN1252'     => 'WINDOWS-1252',
            'WINDOWS1252' => 'WINDOWS-1252',
            'CP1253'      => 'WINDOWS-1253',
            'WIN1253'     => 'WINDOWS-1253',
            'WINDOWS1253' => 'WINDOWS-1253',
            'CP1254'      => 'WINDOWS-1254',
            'WIN1254'     => 'WINDOWS-1254',
            'WINDOWS1254' => 'WINDOWS-1254',
            'CP1255'      => 'WINDOWS-1255',
            'WIN1255'     => 'WINDOWS-1255',
            'WINDOWS1255' => 'WINDOWS-1255',
            'CP1256'      => 'WINDOWS-1256',
            'WIN1256'     => 'WINDOWS-1256',
            'WINDOWS1256' => 'WINDOWS-1256',
            'CP1257'      => 'WINDOWS-1257',
            'WIN1257'     => 'WINDOWS-1257',
            'WINDOWS1257' => 'WINDOWS-1257',
            'CP1258'      => 'WINDOWS-1258',
            'WIN1258'     => 'WINDOWS-1258',
            'WINDOWS1258' => 'WINDOWS-1258',
            'UTF16'       => 'UTF-16',
            'UTF32'       => 'UTF-32',
            'UTF8'        => 'UTF-8',
            'UTF'         => 'UTF-8',
            'UTF7'        => 'UTF-7',
            '8BIT'        => 'CP850',
            'BINARY'      => 'CP850',
        ];

        if (!empty($equivalences[$encoding_upper_helper])) {
            $encoding = $equivalences[$encoding_upper_helper];
        }

        $STATIC_NORMALIZE_ENCODING_CACHE[$encoding_original] = $encoding;

        return $encoding;
    }

    /**
     * Standardize line ending to unix-like.
     *
     * @param string          $str      <p>The input string.</p>
     * @param string|string[] $replacer <p>The replacer char e.g. "\n" (Linux) or "\r\n" (Windows). You can also use \PHP_EOL
     *                                  here.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with normalized line ending.</p>
     */
    public static function normalize_line_ending(string $str, $replacer = "\n"): string
    {
        return \str_replace(["\r\n", "\r", "\n"], $replacer, $str);
    }

    /**
     * Normalize some MS Word special characters.
     *
     * EXAMPLE: <code>UTF8::normalize_msword('„Abcdef…”'); // '"Abcdef..."'</code>
     *
     * @param string $str <p>The string to be normalized.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with normalized characters for commonly used chars in Word documents.</p>
     */
    public static function normalize_msword(string $str): string
    {
        return ASCII::normalize_msword($str);
    }

    /**
     * Normalize the whitespace.
     *
     * EXAMPLE: <code>UTF8::normalize_whitespace("abc-\xc2\xa0-öäü-\xe2\x80\xaf-\xE2\x80\xAC", true); // "abc-\xc2\xa0-öäü- -"</code>
     *
     * @param string $str                          <p>The string to be normalized.</p>
     * @param bool   $keep_non_breaking_space      [optional] <p>Set to true, to keep non-breaking-spaces.</p>
     * @param bool   $keep_bidi_unicode_controls   [optional] <p>Set to true, to keep non-printable (for the web)
     *                                             bidirectional text chars.</p>
     * @param bool   $normalize_control_characters [optional] <p>Set to true, to convert e.g. LINE-, PARAGRAPH-SEPARATOR with "\n" and LINE TABULATION with "\t".</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with normalized whitespace.</p>
     */
    public static function normalize_whitespace(
        string $str,
        bool $keep_non_breaking_space = false,
        bool $keep_bidi_unicode_controls = false,
        bool $normalize_control_characters = false
    ): string {
        return ASCII::normalize_whitespace(
            $str,
            $keep_non_breaking_space,
            $keep_bidi_unicode_controls,
            $normalize_control_characters
        );
    }

    /**
     * Calculates Unicode code point of the given UTF-8 encoded character.
     *
     * INFO: opposite to UTF8::chr()
     *
     * EXAMPLE: <code>UTF8::ord('☃'); // 0x2603</code>
     *
     * @param string $chr      <p>The character of which to calculate code point.<p/>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <p>Unicode code point of the given character,<br>
     *             0 on invalid UTF-8 byte sequence</p>
     */
    public static function ord($chr, string $encoding = 'UTF-8'): int
    {
        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<string,int>
         */
        static $CHAR_CACHE = [];

        // init
        $chr = (string) $chr;

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        $cache_key = $chr . '_' . $encoding;
        if (isset($CHAR_CACHE[$cache_key])) {
            return $CHAR_CACHE[$cache_key];
        }

        // check again, if it's still not UTF-8
        if ($encoding !== 'UTF-8') {
            $chr = self::encode($encoding, $chr);
        }

        if (self::$ORD === null) {
            self::$ORD = self::getData('ord');
        }

        if (isset(self::$ORD[$chr])) {
            return $CHAR_CACHE[$cache_key] = self::$ORD[$chr];
        }

        //
        // fallback via "IntlChar"
        //

        if (self::$SUPPORT['intlChar'] === true) {
            $code = \IntlChar::ord($chr);
            if ($code) {
                return $CHAR_CACHE[$cache_key] = $code;
            }
        }

        //
        // fallback via vanilla php
        //

        $chr = \unpack('C*', (string) \substr($chr, 0, 4));
        /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
        /** @var int[] $chr - "unpack": only false if the format string contains errors */
        $chr = $chr;
        $code = $chr ? $chr[1] : 0;

        if ($code >= 0xF0 && isset($chr[4])) {
            return $CHAR_CACHE[$cache_key] = ((($code - 0xF0) << 18) + (($chr[2] - 0x80) << 12) + (($chr[3] - 0x80) << 6) + $chr[4] - 0x80);
        }

        if ($code >= 0xE0 && isset($chr[3])) {
            return $CHAR_CACHE[$cache_key] = ((($code - 0xE0) << 12) + (($chr[2] - 0x80) << 6) + $chr[3] - 0x80);
        }

        if ($code >= 0xC0 && isset($chr[2])) {
            return $CHAR_CACHE[$cache_key] = ((($code - 0xC0) << 6) + $chr[2] - 0x80);
        }

        return $CHAR_CACHE[$cache_key] = $code;
    }

    /**
     * Parses the string into an array (into the the second parameter).
     *
     * WARNING: Unlike "parse_str()", this method does not (re-)place variables in the current scope,
     *          if the second parameter is not set!
     *
     * EXAMPLE: <code>
     * UTF8::parse_str('Iñtërnâtiônéàlizætiøn=測試&arr[]=foo+測試&arr[]=ການທົດສອບ', $array);
     * echo $array['Iñtërnâtiônéàlizætiøn']; // '測試'
     * </code>
     *
     * @see http://php.net/manual/en/function.parse-str.php
     *
     * @param string               $str        <p>The input string.</p>
     * @param array<string, mixed> $result     <p>The result will be returned into this reference parameter.</p>
     * @param bool                 $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Will return <strong>false</strong> if php can't parse the string and we haven't any $result.</p>
     */
    public static function parse_str(string $str, &$result, bool $clean_utf8 = false): bool
    {
        if ($clean_utf8) {
            $str = self::clean($str);
        }

        if (self::$SUPPORT['mbstring'] === true) {
            $return = \mb_parse_str($str, $result);

            return $return !== false && $result !== [];
        }

        /**
         * @psalm-suppress ImpureFunctionCall - we use the second parameter, so we don't change variables by magic
         */
        \parse_str($str, $result);

        return $result !== [];
    }

    /**
     * Checks if \u modifier is available that enables Unicode support in PCRE.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>
     *              <strong>true</strong> if support is available,<br>
     *              <strong>false</strong> otherwise
     *              </p>
     */
    public static function pcre_utf8_support(): bool
    {
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
        return (bool) @\preg_match('//u', '');
    }

    /**
     * Create an array containing a range of UTF-8 characters.
     *
     * EXAMPLE: <code>UTF8::range('κ', 'ζ'); // array('κ', 'ι', 'θ', 'η', 'ζ',)</code>
     *
     * @param int|string $var1      <p>Numeric or hexadecimal code points, or a UTF-8 character to start from.</p>
     * @param int|string $var2      <p>Numeric or hexadecimal code points, or a UTF-8 character to end at.</p>
     * @param bool       $use_ctype <p>use ctype to detect numeric and hexadecimal, otherwise we will use a simple
     *                              "is_numeric"</p>
     * @param string     $encoding  [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param float|int  $step      [optional] <p>
     *                              If a step value is given, it will be used as the
     *                              increment between elements in the sequence. step
     *                              should be given as a positive number. If not specified,
     *                              step will default to 1.
     *                              </p>
     *
     * @psalm-pure
     *
     * @return list<string>
     */
    public static function range(
        $var1,
        $var2,
        bool $use_ctype = true,
        string $encoding = 'UTF-8',
        $step = 1
    ): array {
        if (!$var1 || !$var2) {
            return [];
        }

        if ($step !== 1) {
            /**
             * @psalm-suppress RedundantConditionGivenDocblockType
             * @psalm-suppress DocblockTypeContradiction
             * @phpstan-ignore-next-line | ignore wrong inputs
             */
            if (!\is_numeric($step)) {
                throw new \InvalidArgumentException('$step need to be a number, type given: ' . \gettype($step));
            }

            /**
             * @psalm-suppress RedundantConditionGivenDocblockType - false-positive from psalm?
             */
            if ($step <= 0) {
                throw new \InvalidArgumentException('$step need to be a positive number, given: ' . $step);
            }
        }

        if ($use_ctype && self::$SUPPORT['ctype'] === false) {
            throw new \RuntimeException('ext-ctype: is not installed');
        }

        $is_digit = false;
        $is_xdigit = false;

        if ($use_ctype && \ctype_digit((string) $var1) && \ctype_digit((string) $var2)) {
            $is_digit = true;
            $start = (int) $var1;
        } elseif ($use_ctype && \ctype_xdigit($var1) && \ctype_xdigit($var2)) {
            $is_xdigit = true;
            $start = (int) self::hex_to_int((string) $var1);
        } elseif (!$use_ctype && \is_numeric($var1)) {
            $start = (int) $var1;
        } else {
            $start = self::ord((string) $var1);
        }

        if (!$start) {
            return [];
        }

        if ($is_digit) {
            $end = (int) $var2;
        } elseif ($is_xdigit) {
            $end = (int) self::hex_to_int((string) $var2);
        } elseif (!$use_ctype && \is_numeric($var2)) {
            $end = (int) $var2;
        } else {
            $end = self::ord((string) $var2);
        }

        if (!$end) {
            return [];
        }

        $array = [];
        foreach (\range($start, $end, $step) as $i) {
            $array[] = (string) self::chr((int) $i, $encoding);
        }

        return $array;
    }

    /**
     * Get data from an array via array like string.
     *
     * EXAMPLE: <code>$array['foo'][123] = 'lall'; UTF8::getUrlParamFromArray('foo[123]', $array); // 'lall'</code>
     *
     * @param array<array-key, mixed> $data
     *
     * @return mixed
     */
    public static function getUrlParamFromArray(string $param, array $data)
    {
        /**
         * @param array<array-key, mixed> $searchArray
         * @param array<array-key, mixed> $array
         *
         * @return mixed
         */
        $getUrlArgFromArrayHelper = static function (array $searchArray, array $array) use (&$getUrlArgFromArrayHelper) {
            foreach ($searchArray as $key => $value) {
                if (isset($array[$key])) {
                    if (\is_array($value) && \is_array($array[$key])) {
                        return $getUrlArgFromArrayHelper($value, $array[$key]);
                    }

                    return $array[$key];
                }
            }

            return null;
        };

        /**
         * @param string $string
         * @return array|null
         */
        $getUrlKeyArgsFromString = static function (string $string) {
            if (!self::str_contains($string, '?')) {
                $string = '?' . $string;
            }

            $args = parse_url($string, PHP_URL_QUERY);
            if ($args) {
                $query = [];
                parse_str($args, $query);

                return $query;
            }

            return null;
        };

        if (isset($data[$param])) {
            return $data[$param];
        }

        $paramKeys = $getUrlKeyArgsFromString($param);
        if ($paramKeys !== null) {
            return $getUrlArgFromArrayHelper($paramKeys, $data);
        }

        return null;
    }

    /**
     * Multi decode HTML entity + fix urlencoded-win1252-chars.
     *
     * EXAMPLE: <code>UTF8::rawurldecode('tes%20öäü%20\u00edtest+test'); // 'tes öäü ítest+test'</code>
     *
     * e.g:
     * 'test+test'                     => 'test+test'
     * 'D&#252;sseldorf'               => 'Düsseldorf'
     * 'D%FCsseldorf'                  => 'Düsseldorf'
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
     * 'DÃ¼sseldorf'                   => 'Düsseldorf'
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
     *
     * @param string $str          <p>The input string.</p>
     * @param bool   $multi_decode <p>Decode as often as possible.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The decoded URL, as a string.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function rawurldecode(string $str, bool $multi_decode = true): string
    {
        if ($str === '') {
            return '';
        }

        $str = self::urldecode_unicode_helper($str);

        if ($multi_decode) {
            do {
                $str_compare = $str;

                /**
                 * @psalm-suppress PossiblyInvalidArgument
                 */
                $str = \rawurldecode(
                    self::html_entity_decode(
                        self::to_utf8($str),
                        \ENT_QUOTES | \ENT_HTML5
                    )
                );
            } while ($str_compare !== $str);
        } else {
            /**
             * @psalm-suppress PossiblyInvalidArgument
             */
            $str = \rawurldecode(
                self::html_entity_decode(
                    self::to_utf8($str),
                    \ENT_QUOTES | \ENT_HTML5
                )
            );
        }

        return self::fix_simple_utf8($str);
    }

    /**
     * Replaces all occurrences of $pattern in $str by $replacement.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $pattern     <p>The regular expression pattern.</p>
     * @param string $replacement <p>The string to replace with.</p>
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function regex_replace(
        string $str,
        string $pattern,
        string $replacement,
        string $options = '',
        string $delimiter = '/'
    ): string {
        if ($options === 'msr') {
            $options = 'ms';
        }

        // fallback
        if (!$delimiter) {
            $delimiter = '/';
        }

        return (string) \preg_replace(
            $delimiter . $pattern . $delimiter . 'u' . $options,
            $replacement,
            $str
        );
    }

    /**
     * Remove the BOM from UTF-8 / UTF-16 / UTF-32 strings.
     *
     * EXAMPLE: <code>UTF8::remove_bom("\xEF\xBB\xBFΜπορώ να"); // 'Μπορώ να'</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without UTF-BOM.</p>
     */
    public static function remove_bom(string $str): string
    {
        if ($str === '') {
            return '';
        }

        $str_length = \strlen($str);
        foreach (self::$BOM as $bom_string => $bom_byte_length) {
            if (\strncmp($str, $bom_string, $bom_byte_length) === 0) {
                /** @var false|string $str_tmp - needed for PhpStan (stubs error) */
                $str_tmp = \substr($str, $bom_byte_length, $str_length);
                if ($str_tmp === false) {
                    return '';
                }

                $str_length -= $bom_byte_length;

                $str = (string) $str_tmp;
            }
        }

        return $str;
    }

    /**
     * Removes duplicate occurrences of a string in another string.
     *
     * EXAMPLE: <code>UTF8::remove_duplicates('öäü-κόσμεκόσμε-äöü', 'κόσμε'); // 'öäü-κόσμε-äöü'</code>
     *
     * @param string          $str  <p>The base string.</p>
     * @param string|string[] $what <p>String to search for in the base string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with removed duplicates.</p>
     */
    public static function remove_duplicates(string $str, $what = ' '): string
    {
        if (\is_string($what)) {
            $what = [$what];
        }

        /**
         * @psalm-suppress RedundantConditionGivenDocblockType
         * @phpstan-ignore-next-line | ignore wrong inputs
         */
        if (\is_array($what)) {
            foreach ($what as $item) {
                $str = (string) \preg_replace('/(' . \preg_quote($item, '/') . ')+/u', $item, $str);
            }
        }

        return $str;
    }

    /**
     * Remove html via "strip_tags()" from the string.
     *
     * @param string $str            <p>The input string.</p>
     * @param string $allowable_tags [optional] <p>You can use the optional second parameter to specify tags which
     *                               should not be stripped. Default: null
     *                               </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with without html tags.</p>
     */
    public static function remove_html(string $str, string $allowable_tags = ''): string
    {
        return \strip_tags($str, $allowable_tags);
    }

    /**
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $replacement [optional] <p>Default is a empty string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without breaks.</p>
     */
    public static function remove_html_breaks(string $str, string $replacement = ''): string
    {
        return (string) \preg_replace("#/\r\n|\r|\n|<br.*/?>#isU", $replacement, $str);
    }

    /**
     * Remove invisible characters from a string.
     *
     * e.g.: This prevents sandwiching null characters between ascii characters, like Java\0script.
     *
     * EXAMPLE: <code>UTF8::remove_invisible_characters("κόσ\0με"); // 'κόσμε'</code>
     *
     * copy&past from https://github.com/bcit-ci/CodeIgniter/blob/develop/system/core/Common.php
     *
     * @param string $str                           <p>The input string.</p>
     * @param bool   $url_encoded                   [optional] <p>
     *                                              Try to remove url encoded control character.
     *                                              WARNING: maybe contains false-positives e.g. aa%0Baa -> aaaa.
     *                                              <br>
     *                                              Default: false
     *                                              </p>
     * @param string $replacement                   [optional] <p>The replacement character.</p>
     * @param bool   $keep_basic_control_characters [optional] <p>Keep control characters like [LRM] or [LSEP].</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without invisible chars.</p>
     */
    public static function remove_invisible_characters(
        string $str,
        bool $url_encoded = false,
        string $replacement = '',
        bool $keep_basic_control_characters = true
    ): string {
        return ASCII::remove_invisible_characters(
            $str,
            $url_encoded,
            $replacement,
            $keep_basic_control_characters
        );
    }

    /**
     * Returns a new string with the prefix $substring removed, if present.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $substring <p>The prefix to remove.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without the prefix $substring.</p>
     */
    public static function remove_left(
        string $str,
        string $substring,
        string $encoding = 'UTF-8'
    ): string {
        if (
            $substring
            &&
            \strpos($str, $substring) === 0
        ) {
            if ($encoding === 'UTF-8') {
                return (string) \mb_substr(
                    $str,
                    (int) \mb_strlen($substring)
                );
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return (string) self::substr(
                $str,
                (int) self::strlen($substring, $encoding),
                null,
                $encoding
            );
        }

        return $str;
    }

    /**
     * Returns a new string with the suffix $substring removed, if present.
     *
     * @param string $str
     * @param string $substring <p>The suffix to remove.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string having a $str without the suffix $substring.</p>
     */
    public static function remove_right(
        string $str,
        string $substring,
        string $encoding = 'UTF-8'
    ): string {
        if ($substring && \substr($str, -\strlen($substring)) === $substring) {
            if ($encoding === 'UTF-8') {
                return (string) \mb_substr(
                    $str,
                    0,
                    (int) \mb_strlen($str) - (int) \mb_strlen($substring)
                );
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return (string) self::substr(
                $str,
                0,
                (int) self::strlen($str, $encoding) - (int) self::strlen($substring, $encoding),
                $encoding
            );
        }

        return $str;
    }

    /**
     * Returns a new string with the suffix $substring removed, if present and case-insensitive.
     *
     * @param string $str
     * @param string $substring <p>The suffix to remove.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string having a $str without the suffix $substring.</p>
     */
    public static function remove_iright(
        string $str,
        string $substring,
        string $encoding = 'UTF-8'
    ): string {
        if ($substring && self::strtoupper(\substr($str, -\strlen($substring)), $encoding) === self::strtoupper($substring, $encoding)) {
            if ($encoding === 'UTF-8') {
                return (string) \mb_substr(
                    $str,
                    0,
                    (int) \mb_strlen($str) - (int) \mb_strlen($substring)
                );
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return (string) self::substr(
                $str,
                0,
                (int) self::strlen($str, $encoding) - (int) self::strlen($substring, $encoding),
                $encoding
            );
        }

        return $str;
    }

    /**
     * Returns a new string with the prefix $substring removed, if present and case-insensitive.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $substring <p>The prefix to remove.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without the prefix $substring.</p>
     */
    public static function remove_ileft(
        string $str,
        string $substring,
        string $encoding = 'UTF-8'
    ): string {
        if (
            $substring
            &&
            \strpos(self::strtoupper($str, $encoding), self::strtoupper($substring, $encoding)) === 0
        ) {
            if ($encoding === 'UTF-8') {
                return (string) \mb_substr(
                    $str,
                    (int) \mb_strlen($substring)
                );
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return (string) self::substr(
                $str,
                (int) self::strlen($substring, $encoding),
                null,
                $encoding
            );
        }

        return $str;
    }

    /**
     * Replaces all occurrences of $search in $str by $replacement.
     *
     * @param string $str            <p>The input string.</p>
     * @param string $search         <p>The needle to search for.</p>
     * @param string $replacement    <p>The string to replace with.</p>
     * @param bool   $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with replaced parts.</p>
     */
    public static function replace(
        string $str,
        string $search,
        string $replacement,
        bool $case_sensitive = true
    ): string {
        if ($case_sensitive) {
            return \str_replace($search, $replacement, $str);
        }

        return self::str_ireplace($search, $replacement, $str);
    }

    /**
     * Replaces all occurrences of $search in $str by $replacement.
     *
     * @param string          $str            <p>The input string.</p>
     * @param string[]        $search         <p>The elements to search for.</p>
     * @param string|string[] $replacement    <p>The string to replace with.</p>
     * @param bool            $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with replaced parts.</p>
     */
    public static function replace_all(
        string $str,
        array $search,
        $replacement,
        bool $case_sensitive = true
    ): string {
        if ($case_sensitive) {
            return \str_replace($search, $replacement, $str);
        }

        return self::str_ireplace($search, $replacement, $str);
    }

    /**
     * Replace the diamond question mark (�) and invalid-UTF8 chars with the replacement.
     *
     * EXAMPLE: <code>UTF8::replace_diamond_question_mark('中文空白�', ''); // '中文空白'</code>
     *
     * @param string $str                        <p>The input string</p>
     * @param string $replacement_char           <p>The replacement character.</p>
     * @param bool   $process_invalid_utf8_chars <p>Convert invalid UTF-8 chars </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string without diamond question marks (�).</p>
     */
    public static function replace_diamond_question_mark(
        string $str,
        string $replacement_char = '',
        bool $process_invalid_utf8_chars = true
    ): string {
        if ($str === '') {
            return '';
        }

        if ($process_invalid_utf8_chars) {
            if ($replacement_char === '') {
                $replacement_char_helper = 'none';
            } else {
                $replacement_char_helper = \ord($replacement_char);
            }

            if (self::$SUPPORT['mbstring'] === false) {
                // if there is no native support for "mbstring",
                // then we need to clean the string before ...
                $str = self::clean($str);
            }

            /**
             * @psalm-suppress ImpureFunctionCall - we will reset the value in the next step
             */
            $save = \mb_substitute_character();
            /** @noinspection PhpUsageOfSilenceOperatorInspection - ignore "Unknown character" warnings, it's working anyway */
            @\mb_substitute_character($replacement_char_helper);
            // the polyfill maybe return false, so cast to string
            $str = (string) \mb_convert_encoding($str, 'UTF-8', 'UTF-8');
            \mb_substitute_character($save);
        }

        return \str_replace(
            [
                "\xEF\xBF\xBD",
                '�',
            ],
            [
                $replacement_char,
                $replacement_char,
            ],
            $str
        );
    }

    /**
     * Strip whitespace or other characters from the end of a UTF-8 string.
     *
     * EXAMPLE: <code>UTF8::rtrim('-ABC-中文空白-  '); // '-ABC-中文空白-'</code>
     *
     * @param string      $str   <p>The string to be trimmed.</p>
     * @param string|null $chars <p>Optional characters to be stripped.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with unwanted characters stripped from the right.</p>
     */
    public static function rtrim(string $str = '', string $chars = null): string
    {
        if ($str === '') {
            return '';
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($chars !== null) {
                /** @noinspection PregQuoteUsageInspection */
                $chars = \preg_quote($chars);
                $pattern = "[{$chars}]+$";
            } else {
                $pattern = '[\\s]+$';
            }

            return (string) \mb_ereg_replace($pattern, '', $str);
        }

        if ($chars !== null) {
            $chars = \preg_quote($chars, '/');
            $pattern = "[{$chars}]+$";
        } else {
            $pattern = '[\\s]+$';
        }

        return self::regex_replace($str, $pattern, '');
    }

    /**
     * WARNING: Print native UTF-8 support (libs) by default, e.g. for debugging.
     *
     * @param bool $useEcho
     *
     * @psalm-pure
     *
     * @return string|void
     *
     * @phpstan-return ($useEcho is true ? void : string)
     */
    public static function showSupport(bool $useEcho = true)
    {
        // init
        $html = '';

        $html .= '<pre>';
        foreach (self::$SUPPORT as $key => &$value) {
            $html .= $key . ' - ' . \print_r($value, true) . "\n<br>";
        }
        $html .= '</pre>';

        if ($useEcho) {
            echo $html;
        }

        return $html;
    }

    /**
     * Converts a UTF-8 character to HTML Numbered Entity like "&#123;".
     *
     * EXAMPLE: <code>UTF8::single_chr_html_encode('κ'); // '&#954;'</code>
     *
     * @param string $char             <p>The Unicode character to be encoded as numbered entity.</p>
     * @param bool   $keep_ascii_chars <p>Set to <strong>true</strong> to keep ASCII chars.</>
     * @param string $encoding         [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The HTML numbered entity for the given character.</p>
     *
     * @template T as string
     * @phpstan-param T $char
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function single_chr_html_encode(
        string $char,
        bool $keep_ascii_chars = false,
        string $encoding = 'UTF-8'
    ): string {
        if ($char === '') {
            return '';
        }

        if (
            $keep_ascii_chars
            &&
            ASCII::is_ascii($char)
        ) {
            return $char;
        }

        return '&#' . self::ord($char, $encoding) . ';';
    }

    /**
     * @param string      $str
     * @param int<1, max> $tab_length
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function spaces_to_tabs(string $str, int $tab_length = 4): string
    {
        if ($tab_length === 4) {
            $tab = '    ';
        } elseif ($tab_length === 2) {
            $tab = '  ';
        } else {
            $tab = \str_repeat(' ', $tab_length);
        }

        return \str_replace($tab, "\t", $str);
    }

    /**
     * Returns a camelCase version of the string. Trims surrounding spaces,
     * capitalizes letters following digits, spaces, dashes and underscores,
     * and removes spaces, dashes, as well as underscores.
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string      $encoding                      [optional] <p>Default: 'UTF-8'</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_camelize(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if ($clean_utf8) {
            $str = self::clean($str);
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        $str = self::lcfirst(
            \trim($str),
            $encoding,
            false,
            $lang,
            $try_to_keep_the_string_length
        );
        $str = (string) \preg_replace('/^[-_]+/', '', $str);

        $use_mb_functions = $lang === null && !$try_to_keep_the_string_length;

        $str = (string) \preg_replace_callback(
            '/[-_\\s]+(.)?/u',
            /**
             * @param array $match
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $match) use ($use_mb_functions, $encoding, $lang, $try_to_keep_the_string_length): string {
                if (isset($match[1])) {
                    if ($use_mb_functions) {
                        if ($encoding === 'UTF-8') {
                            return \mb_strtoupper($match[1]);
                        }

                        return \mb_strtoupper($match[1], $encoding);
                    }

                    return self::strtoupper($match[1], $encoding, false, $lang, $try_to_keep_the_string_length);
                }

                return '';
            },
            $str
        );

        return (string) \preg_replace_callback(
            '/[\\p{N}]+(.)?/u',
            /**
             * @param array $match
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $match) use ($use_mb_functions, $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length): string {
                if ($use_mb_functions) {
                    if ($encoding === 'UTF-8') {
                        return \mb_strtoupper($match[0]);
                    }

                    return \mb_strtoupper($match[0], $encoding);
                }

                return self::strtoupper($match[0], $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length);
            },
            $str
        );
    }

    /**
     * Returns the string with the first letter of each word capitalized,
     * except for when the word is a name which shouldn't be capitalized.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with $str capitalized.</p>
     */
    public static function str_capitalize_name(string $str): string
    {
        return self::str_capitalize_name_helper(
            self::str_capitalize_name_helper(
                self::collapse_whitespace($str),
                ' '
            ),
            '-'
        );
    }

    /**
     * Returns true if the string contains $needle, false otherwise. By default
     * the comparison is case-sensitive, but can be made insensitive by setting
     * $case_sensitive to false.
     *
     * @param string $haystack       <p>The input string.</p>
     * @param string $needle         <p>Substring to look for.</p>
     * @param bool   $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $haystack contains $needle.</p>
     */
    public static function str_contains(
        string $haystack,
        string $needle,
        bool $case_sensitive = true
    ): bool {
        if ($case_sensitive) {
            if (\PHP_VERSION_ID >= 80000) {
                /** @phpstan-ignore-next-line - only for PHP8 */
                return \str_contains($haystack, $needle);
            }

            return \strpos($haystack, $needle) !== false;
        }

        return \mb_stripos($haystack, $needle) !== false;
    }

    /**
     * Returns true if the string contains all $needles, false otherwise. By
     * default, the comparison is case-sensitive, but can be made insensitive by
     * setting $case_sensitive to false.
     *
     * @param string   $haystack       <p>The input string.</p>
     * @param scalar[] $needles        <p>SubStrings to look for.</p>
     * @param bool     $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $haystack contains $needle.</p>
     */
    public static function str_contains_all(
        string $haystack,
        array $needles,
        bool $case_sensitive = true
    ): bool {
        if ($haystack === '' || $needles === []) {
            return false;
        }

        foreach ($needles as &$needle) {
            if (
                $case_sensitive
                &&
                (!$needle || \strpos($haystack, (string)$needle) === false)
            ) {
                return false;
            }

            if (!$needle || \mb_stripos($haystack, (string) $needle) === false) {
                return false;
            }
        }

        return true;
    }

    /**
     * Returns true if the string contains any $needles, false otherwise. By
     * default the comparison is case-sensitive, but can be made insensitive by
     * setting $case_sensitive to false.
     *
     * @param string   $haystack       <p>The input string.</p>
     * @param scalar[] $needles        <p>SubStrings to look for.</p>
     * @param bool     $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str contains $needle.</p>
     */
    public static function str_contains_any(
        string $haystack,
        array $needles,
        bool $case_sensitive = true
    ): bool {
        if ($haystack === '' || $needles === []) {
            return false;
        }

        foreach ($needles as &$needle) {
            if (!$needle) {
                continue;
            }

            if ($case_sensitive) {
                if (\strpos($haystack, (string) $needle) !== false) {
                    return true;
                }

                continue;
            }

            if (\mb_stripos($haystack, (string) $needle) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
     * inserted before uppercase characters (with the exception of the first
     * character of the string), and in place of spaces as well as underscores.
     *
     * @param string $str      <p>The input string.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_dasherize(string $str, string $encoding = 'UTF-8'): string
    {
        return self::str_delimit($str, '-', $encoding);
    }

    /**
     * Returns a lowercase and trimmed string separated by the given delimiter.
     *
     * Delimiters are inserted before uppercase characters (with the exception
     * of the first character of the string), and in place of spaces, dashes,
     * and underscores. Alpha delimiters are not converted to lowercase.
     *
     * EXAMPLE: <code>
     * UTF8::str_delimit('test case, '#'); // 'test#case'
     * UTF8::str_delimit('test -case', '**'); // 'test**case'
     * </code>
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string      $delimiter                     <p>Sequence used to separate parts of the string.</p>
     * @param string      $encoding                      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ ->
     *                                                   ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_delimit(
        string $str,
        string $delimiter,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if (self::$SUPPORT['mbstring'] === true) {
            $str = (string) \mb_ereg_replace('\\B(\\p{Lu})', '-\1', \trim($str));

            $use_mb_functions = $lang === null && !$try_to_keep_the_string_length;
            if ($use_mb_functions && $encoding === 'UTF-8') {
                $str = \mb_strtolower($str);
            } else {
                $str = self::strtolower($str, $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length);
            }

            return (string) \mb_ereg_replace('[\\-_\\s]+', $delimiter, $str);
        }

        $str = (string) \preg_replace('/\\B(\\p{Lu})/u', '-\1', \trim($str));

        $use_mb_functions = $lang === null && !$try_to_keep_the_string_length;
        if ($use_mb_functions && $encoding === 'UTF-8') {
            $str = \mb_strtolower($str);
        } else {
            $str = self::strtolower($str, $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length);
        }

        return (string) \preg_replace('/[\\-_\\s]+/u', $delimiter, $str);
    }

    /**
     * Optimized "mb_detect_encoding()"-function -> with support for UTF-16 and UTF-32.
     *
     * EXAMPLE: <code>
     * UTF8::str_detect_encoding('中文空白'); // 'UTF-8'
     * UTF8::str_detect_encoding('Abc'); // 'ASCII'
     * </code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>
     *                      The detected string-encoding e.g. UTF-8 or UTF-16BE,<br>
     *                      otherwise it will return false e.g. for BINARY or not detected encoding.
     *                      </p>
     */
    public static function str_detect_encoding($str)
    {
        // init
        $str = (string) $str;

        //
        // 1.) check binary strings (010001001...) like UTF-16 / UTF-32 / PDF / Images / ...
        //

        if (self::is_binary($str, self::string_has_bom($str) ? false : true)) {
            $is_utf32 = self::is_utf32($str, false);
            if ($is_utf32 === 1) {
                return 'UTF-32LE';
            }
            if ($is_utf32 === 2) {
                return 'UTF-32BE';
            }

            $is_utf16 = self::is_utf16($str, false);
            if ($is_utf16 === 1) {
                return 'UTF-16LE';
            }
            if ($is_utf16 === 2) {
                return 'UTF-16BE';
            }

            // is binary but not "UTF-16" or "UTF-32"
            return false;
        }

        //
        // 2.) simple check for ASCII chars
        //

        if (ASCII::is_ascii($str)) {
            return 'ASCII';
        }

        //
        // 3.) simple check for UTF-8 chars
        //

        if (self::is_utf8_string($str)) {
            return 'UTF-8';
        }

        //
        // 4.) check via "mb_detect_encoding()"
        //
        // INFO: UTF-16, UTF-32, UCS2 and UCS4, encoding detection will fail always with "mb_detect_encoding()"

        $encoding_detecting_order = [
            'ISO-8859-1',
            'ISO-8859-2',
            'ISO-8859-3',
            'ISO-8859-4',
            'ISO-8859-5',
            'ISO-8859-6',
            'ISO-8859-7',
            'ISO-8859-8',
            'ISO-8859-9',
            'ISO-8859-10',
            'ISO-8859-13',
            'ISO-8859-14',
            'ISO-8859-15',
            'ISO-8859-16',
            'WINDOWS-1251',
            'WINDOWS-1252',
            'WINDOWS-1254',
            'CP932',
            'CP936',
            'CP950',
            'CP866',
            'CP850',
            'CP51932',
            'CP50220',
            'CP50221',
            'CP50222',
            'ISO-2022-JP',
            'ISO-2022-KR',
            'JIS',
            'JIS-ms',
            'EUC-CN',
            'EUC-JP',
        ];

        if (self::$SUPPORT['mbstring'] === true) {
            // info: do not use the symfony polyfill here
            $encoding = \mb_detect_encoding($str, $encoding_detecting_order, true);
            if ($encoding) {
                return $encoding;
            }
        }

        //
        // 5.) check via "iconv()"
        //

        if (self::$ENCODINGS === null) {
            self::$ENCODINGS = self::getData('encodings');
        }

        foreach (self::$ENCODINGS as $encoding_tmp) {
            // INFO: //IGNORE but still throw notice
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
            if ((string) @\iconv($encoding_tmp, $encoding_tmp . '//IGNORE', $str) === $str) {
                return $encoding_tmp;
            }
        }

        return false;
    }

    /**
     * Check if the string ends with the given substring.
     *
     * EXAMPLE: <code>
     * UTF8::str_ends_with('BeginMiddleΚόσμε', 'Κόσμε'); // true
     * UTF8::str_ends_with('BeginMiddleΚόσμε', 'κόσμε'); // false
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function str_ends_with(string $haystack, string $needle): bool
    {
        if ($needle === '') {
            return true;
        }

        if ($haystack === '') {
            return false;
        }

        if (\PHP_VERSION_ID >= 80000) {
            /** @phpstan-ignore-next-line - only for PHP8 */
            return \str_ends_with($haystack, $needle);
        }

        return \substr($haystack, -\strlen($needle)) === $needle;
    }

    /**
     * Returns true if the string ends with any of $substrings, false otherwise.
     *
     * - case-sensitive
     *
     * @param string   $str        <p>The input string.</p>
     * @param string[] $substrings <p>Substrings to look for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str ends with $substring.</p>
     */
    public static function str_ends_with_any(string $str, array $substrings): bool
    {
        if ($substrings === []) {
            return false;
        }

        foreach ($substrings as &$substring) {
            if (\substr($str, -\strlen($substring)) === $substring) {
                return true;
            }
        }

        return false;
    }

    /**
     * Ensures that the string begins with $substring. If it doesn't, it's
     * prepended.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $substring <p>The substring to add if not present.</p>
     *
     * @psalm-pure
     *
     * @template T as string
     * @template TSub as string
     * @phpstan-param T $str
     * @phpstan-param TSub $substring
     * @phpstan-return (TSub is non-empty-string ? non-empty-string : (T is non-empty-string ? non-empty-string : string))
     */
    public static function str_ensure_left(string $str, string $substring): string
    {
        if (
            $substring !== ''
            &&
            \strpos($str, $substring) === 0
        ) {
            return $str;
        }

        return $substring . $str;
    }

    /**
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $substring <p>The substring to add if not present.</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @template TSub as string
     * @phpstan-param T $str
     * @phpstan-param TSub $substring
     * @phpstan-return (TSub is non-empty-string ? non-empty-string : (T is non-empty-string ? non-empty-string : string))
     */
    public static function str_ensure_right(string $str, string $substring): string
    {
        if (
            $str === ''
            ||
            $substring === ''
            ||
            \substr($str, -\strlen($substring)) !== $substring
        ) {
            $str .= $substring;
        }

        return $str;
    }

    /**
     * Capitalizes the first word of the string, replaces underscores with
     * spaces, and strips '_id'.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_humanize($str): string
    {
        $str = \str_replace(
            [
                '_id',
                '_',
            ],
            [
                '',
                ' ',
            ],
            $str
        );

        return self::ucfirst(\trim($str));
    }

    /**
     * Check if the string ends with the given substring, case-insensitive.
     *
     * EXAMPLE: <code>
     * UTF8::str_iends_with('BeginMiddleΚόσμε', 'Κόσμε'); // true
     * UTF8::str_iends_with('BeginMiddleΚόσμε', 'κόσμε'); // true
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function str_iends_with(string $haystack, string $needle): bool
    {
        if ($needle === '') {
            return true;
        }

        if ($haystack === '') {
            return false;
        }

        return self::strcasecmp(\substr($haystack, -\strlen($needle)), $needle) === 0;
    }

    /**
     * Returns true if the string ends with any of $substrings, false otherwise.
     *
     * - case-insensitive
     *
     * @param string   $str        <p>The input string.</p>
     * @param string[] $substrings <p>Substrings to look for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str ends with $substring.</p>
     */
    public static function str_iends_with_any(string $str, array $substrings): bool
    {
        if ($substrings === []) {
            return false;
        }

        foreach ($substrings as &$substring) {
            if (self::str_iends_with($str, $substring)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Inserts $substring into the string at the $index provided.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $substring <p>String to be inserted.</p>
     * @param int    $index     <p>The index at which to insert the substring.</p>
     * @param string $encoding  [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_insert(
        string $str,
        string $substring,
        int $index,
        string $encoding = 'UTF-8'
    ): string {
        if ($encoding === 'UTF-8') {
            $len = (int) \mb_strlen($str);
            if ($index > $len) {
                return $str;
            }

            /** @noinspection UnnecessaryCastingInspection */
            return (string) \mb_substr($str, 0, $index) .
                   $substring .
                   (string) \mb_substr($str, $index, $len);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        $len = (int) self::strlen($str, $encoding);
        if ($index > $len) {
            return $str;
        }

        return ((string) self::substr($str, 0, $index, $encoding)) .
               $substring .
               ((string) self::substr($str, $index, $len, $encoding));
    }

    /**
     * Case-insensitive and UTF-8 safe version of <function>str_replace</function>.
     *
     * EXAMPLE: <code>
     * UTF8::str_ireplace('lIzÆ', 'lise', 'Iñtërnâtiônàlizætiøn'); // 'Iñtërnâtiônàlisetiøn'
     * </code>
     *
     * @see http://php.net/manual/en/function.str-ireplace.php
     *
     * @param string|string[] $search      <p>
     *                                     Every replacement with search array is
     *                                     performed on the result of previous replacement.
     *                                     </p>
     * @param string|string[] $replacement <p>The replacement.</p>
     * @param string|string[] $subject     <p>
     *                                     If subject is an array, then the search and
     *                                     replace is performed with every entry of
     *                                     subject, and the return value is an array as
     *                                     well.
     *                                     </p>
     * @param int             $count       [optional] <p>
     *                                     The number of matched and replaced needles will
     *                                     be returned in count which is passed by
     *                                     reference.
     *                                     </p>
     *
     * @psalm-pure
     *
     * @return string|string[]
     *                         <p>A string or an array of replacements.</p>
     *
     * @template TStrIReplaceSubject
     * @phpstan-param TStrIReplaceSubject $subject
     * @phpstan-return TStrIReplaceSubject
     */
    public static function str_ireplace($search, $replacement, $subject, &$count = null)
    {
        $search = (array) $search;

        /** @noinspection AlterInForeachInspection */
        foreach ($search as &$s) {
            $s = (string) $s;
            if ($s === '') {
                $s = '/^(?<=.)$/';
            } else {
                $s = '/' . \preg_quote($s, '/') . '/ui';
            }
        }

        // fallback
        /** @phpstan-ignore-next-line - only a fallback for PHP8 */
        if ($replacement === null) {
            $replacement = '';
        }
        /** @phpstan-ignore-next-line - only a fallback for PHP8 */
        if ($subject === null) {
            $subject = '';
        }

        /**
         * @psalm-suppress PossiblyNullArgument
         * @phpstan-var TStrIReplaceSubject $subject
         */
        $subject = \preg_replace($search, $replacement, $subject, -1, $count);

        return $subject;
    }

    /**
     * Replaces $search from the beginning of string with $replacement.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string after the replacement.</p>
     */
    public static function str_ireplace_beginning(string $str, string $search, string $replacement): string
    {
        if ($str === '') {
            if ($replacement === '') {
                return '';
            }

            if ($search === '') {
                return $replacement;
            }
        }

        if ($search === '') {
            return $str . $replacement;
        }

        $searchLength = \strlen($search);
        if (\strncasecmp($str, $search, $searchLength) === 0) {
            return $replacement . \substr($str, $searchLength);
        }

        return $str;
    }

    /**
     * Replaces $search from the ending of string with $replacement.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string after the replacement.</p>
     */
    public static function str_ireplace_ending(string $str, string $search, string $replacement): string
    {
        if ($str === '') {
            if ($replacement === '') {
                return '';
            }

            if ($search === '') {
                return $replacement;
            }
        }

        if ($search === '') {
            return $str . $replacement;
        }

        if (\stripos($str, $search, \strlen($str) - \strlen($search)) !== false) {
            $str = \substr($str, 0, -\strlen($search)) . $replacement;
        }

        return $str;
    }

    /**
     * Check if the string starts with the given substring, case-insensitive.
     *
     * EXAMPLE: <code>
     * UTF8::str_istarts_with('ΚόσμεMiddleEnd', 'Κόσμε'); // true
     * UTF8::str_istarts_with('ΚόσμεMiddleEnd', 'κόσμε'); // true
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function str_istarts_with(string $haystack, string $needle): bool
    {
        if ($needle === '') {
            return true;
        }

        if ($haystack === '') {
            return false;
        }

        return self::stripos($haystack, $needle) === 0;
    }

    /**
     * Returns true if the string begins with any of $substrings, false otherwise.
     *
     * - case-insensitive
     *
     * @param string   $str        <p>The input string.</p>
     * @param scalar[] $substrings <p>Substrings to look for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str starts with $substring.</p>
     */
    public static function str_istarts_with_any(string $str, array $substrings): bool
    {
        if ($str === '') {
            return false;
        }

        if ($substrings === []) {
            return false;
        }

        foreach ($substrings as &$substring) {
            if (self::str_istarts_with($str, (string) $substring)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Gets the substring after the first occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_after_first_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        $offset = self::stripos($str, $separator);
        if ($offset === false) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr(
                $str,
                $offset + (int) \mb_strlen($separator)
            );
        }

        return (string) self::substr(
            $str,
            $offset + (int) self::strlen($separator, $encoding),
            null,
            $encoding
        );
    }

    /**
     * Gets the substring after the last occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_after_last_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        $offset = self::strripos($str, $separator);
        if ($offset === false) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr(
                $str,
                $offset + (int) self::strlen($separator)
            );
        }

        return (string) self::substr(
            $str,
            $offset + (int) self::strlen($separator, $encoding),
            null,
            $encoding
        );
    }

    /**
     * Gets the substring before the first occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_before_first_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        $offset = self::stripos($str, $separator);
        if ($offset === false) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str, 0, $offset);
        }

        return (string) self::substr($str, 0, $offset, $encoding);
    }

    /**
     * Gets the substring before the last occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_before_last_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $offset = \mb_strripos($str, $separator);
            if ($offset === false) {
                return '';
            }

            return (string) \mb_substr($str, 0, $offset);
        }

        $offset = self::strripos($str, $separator, 0, $encoding);
        if ($offset === false) {
            return '';
        }

        return (string) self::substr($str, 0, $offset, $encoding);
    }

    /**
     * Gets the substring after (or before via "$before_needle") the first occurrence of the "$needle".
     *
     * @param string $str           <p>The input string.</p>
     * @param string $needle        <p>The string to look for.</p>
     * @param bool   $before_needle [optional] <p>Default: false</p>
     * @param string $encoding      [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_first(
        string $str,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8'
    ): string {
        if (
            $needle === ''
            ||
            $str === ''
        ) {
            return '';
        }

        $part = self::stristr(
            $str,
            $needle,
            $before_needle,
            $encoding
        );
        if ($part === false) {
            return '';
        }

        return $part;
    }

    /**
     * Gets the substring after (or before via "$before_needle") the last occurrence of the "$needle".
     *
     * @param string $str           <p>The input string.</p>
     * @param string $needle        <p>The string to look for.</p>
     * @param bool   $before_needle [optional] <p>Default: false</p>
     * @param string $encoding      [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_isubstr_last(
        string $str,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8'
    ): string {
        if (
            $needle === ''
            ||
            $str === ''
        ) {
            return '';
        }

        $part = self::strrichr(
            $str,
            $needle,
            $before_needle,
            $encoding
        );
        if ($part === false) {
            return '';
        }

        return $part;
    }

    /**
     * Returns the last $n characters of the string.
     *
     * @param string $str      <p>The input string.</p>
     * @param int    $n        <p>Number of characters to retrieve from the end.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_last_char(
        string $str,
        int $n = 1,
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '' || $n <= 0) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str, -$n);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        return (string) self::substr($str, -$n, null, $encoding);
    }

    /**
     * Limit the number of characters in a string.
     *
     * @param string      $str        <p>The input string.</p>
     * @param int<1, max> $length     [optional] <p>Default: 100</p>
     * @param string      $str_add_on [optional] <p>Default: …</p>
     * @param string      $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_limit(
        string $str,
        int $length = 100,
        string $str_add_on = '…',
        string $encoding = 'UTF-8'
    ): string {
        if (
            $str === ''
            ||
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            $length <= 0
        ) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            if ((int) \mb_strlen($str) <= $length) {
                return $str;
            }

            /** @noinspection UnnecessaryCastingInspection */
            return (string) \mb_substr($str, 0, $length - (int) self::strlen($str_add_on)) . $str_add_on;
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ((int) self::strlen($str, $encoding) <= $length) {
            return $str;
        }

        return ((string) self::substr($str, 0, $length - (int) self::strlen($str_add_on), $encoding)) . $str_add_on;
    }

    /**
     * Limit the number of characters in a string in bytes.
     *
     * @param string      $str        <p>The input string.</p>
     * @param int<1, max> $length     [optional] <p>Default: 100</p>
     * @param string      $str_add_on [optional] <p>Default: ...</p>
     * @param string      $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_limit_in_byte(
        string $str,
        int $length = 100,
        string $str_add_on = '...',
        string $encoding = 'UTF-8'
    ): string {
        if (
            $str === ''
            ||
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            $length <= 0
        ) {
            return '';
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ((int) self::strlen_in_byte($str, $encoding) <= $length) {
            return $str;
        }

        return ((string) self::substr_in_byte($str, 0, $length - (int) self::strlen_in_byte($str_add_on), $encoding)) . $str_add_on;
    }

    /**
     * Limit the number of characters in a string, but also after the next word.
     *
     * EXAMPLE: <code>UTF8::str_limit_after_word('fòô bàř fòô', 8, ''); // 'fòô bàř'</code>
     *
     * @param string      $str        <p>The input string.</p>
     * @param int<1, max> $length     [optional] <p>Default: 100</p>
     * @param string      $str_add_on [optional] <p>Default: …</p>
     * @param string      $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_limit_after_word(
        string $str,
        int $length = 100,
        string $str_add_on = '…',
        string $encoding = 'UTF-8'
    ): string {
        if (
            $str === ''
            ||
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            $length <= 0
        ) {
            return '';
        }

        if ($encoding === 'UTF-8') {
            if ((int) \mb_strlen($str) <= $length) {
                return $str;
            }

            if (\mb_substr($str, $length - 1, 1) === ' ') {
                return ((string) \mb_substr($str, 0, $length - 1)) . $str_add_on;
            }

            $str = \mb_substr($str, 0, $length);

            $array = \explode(' ', $str, -1);
            $new_str = \implode(' ', $array);

            if ($new_str === '') {
                return ((string) \mb_substr($str, 0, $length - 1)) . $str_add_on;
            }
        } else {
            if ((int) self::strlen($str, $encoding) <= $length) {
                return $str;
            }

            if (self::substr($str, $length - 1, 1, $encoding) === ' ') {
                return ((string) self::substr($str, 0, $length - 1, $encoding)) . $str_add_on;
            }

            /** @noinspection CallableParameterUseCaseInTypeContextInspection - FP */
            $str = self::substr($str, 0, $length, $encoding);
            if ($str === false) {
                return '' . $str_add_on;
            }

            $array = \explode(' ', $str, -1);
            $new_str = \implode(' ', $array);

            if ($new_str === '') {
                return ((string) self::substr($str, 0, $length - 1, $encoding)) . $str_add_on;
            }
        }

        return $new_str . $str_add_on;
    }

    /**
     * Returns the longest common prefix between the $str1 and $str2.
     *
     * @param string $str1     <p>The input sting.</p>
     * @param string $str2     <p>Second string for comparison.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_longest_common_prefix(
        string $str1,
        string $str2,
        string $encoding = 'UTF-8'
    ): string {
        // init
        $longest_common_prefix = '';

        if ($encoding === 'UTF-8') {
            $max_length = (int) \min(
                \mb_strlen($str1),
                \mb_strlen($str2)
            );

            for ($i = 0; $i < $max_length; ++$i) {
                $char = \mb_substr($str1, $i, 1);

                if (
                    $char !== false /* @phpstan-ignore-line | old polyfill will return false, or? */
                    &&
                    $char === \mb_substr($str2, $i, 1)
                ) {
                    $longest_common_prefix .= $char;
                } else {
                    break;
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $max_length = (int) \min(
                self::strlen($str1, $encoding),
                self::strlen($str2, $encoding)
            );

            for ($i = 0; $i < $max_length; ++$i) {
                $char = self::substr($str1, $i, 1, $encoding);

                if (
                    $char !== false
                    &&
                    $char === self::substr($str2, $i, 1, $encoding)
                ) {
                    $longest_common_prefix .= $char;
                } else {
                    break;
                }
            }
        }

        return $longest_common_prefix;
    }

    /**
     * Returns the longest common substring between the $str1 and $str2.
     * In the case of ties, it returns that which occurs first.
     *
     * @param string $str1
     * @param string $str2     <p>Second string for comparison.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with its $str being the longest common substring.</p>
     */
    public static function str_longest_common_substring(
        string $str1,
        string $str2,
        string $encoding = 'UTF-8'
    ): string {
        if ($str1 === '' || $str2 === '') {
            return '';
        }

        // Uses dynamic programming to solve
        // http://en.wikipedia.org/wiki/Longest_common_substring_problem

        if ($encoding === 'UTF-8') {
            $str_length = (int) \mb_strlen($str1);
            $other_length = (int) \mb_strlen($str2);
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $str_length = (int) self::strlen($str1, $encoding);
            $other_length = (int) self::strlen($str2, $encoding);
        }

        // Return if either string is empty
        if ($str_length === 0 || $other_length === 0) {
            return '';
        }

        $len = 0;
        $end = 0;
        $table = \array_fill(
            0,
            $str_length + 1,
            \array_fill(0, $other_length + 1, 0)
        );

        if ($encoding === 'UTF-8') {
            for ($i = 1; $i <= $str_length; ++$i) {
                for ($j = 1; $j <= $other_length; ++$j) {
                    $str_char = \mb_substr($str1, $i - 1, 1);
                    $other_char = \mb_substr($str2, $j - 1, 1);

                    if ($str_char === $other_char) {
                        $table[$i][$j] = $table[$i - 1][$j - 1] + 1;
                        if ($table[$i][$j] > $len) {
                            $len = $table[$i][$j];
                            $end = $i;
                        }
                    } else {
                        $table[$i][$j] = 0;
                    }
                }
            }
        } else {
            for ($i = 1; $i <= $str_length; ++$i) {
                for ($j = 1; $j <= $other_length; ++$j) {
                    $str_char = self::substr($str1, $i - 1, 1, $encoding);
                    $other_char = self::substr($str2, $j - 1, 1, $encoding);

                    if ($str_char === $other_char) {
                        $table[$i][$j] = $table[$i - 1][$j - 1] + 1;
                        if ($table[$i][$j] > $len) {
                            $len = $table[$i][$j];
                            $end = $i;
                        }
                    } else {
                        $table[$i][$j] = 0;
                    }
                }
            }
        }

        if ($encoding === 'UTF-8') {
            return (string) \mb_substr($str1, $end - $len, $len);
        }

        return (string) self::substr($str1, $end - $len, $len, $encoding);
    }

    /**
     * Returns the longest common suffix between the $str1 and $str2.
     *
     * @param string $str1
     * @param string $str2     <p>Second string for comparison.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_longest_common_suffix(
        string $str1,
        string $str2,
        string $encoding = 'UTF-8'
    ): string {
        if ($str1 === '' || $str2 === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $max_length = (int) \min(
                \mb_strlen($str1, $encoding),
                \mb_strlen($str2, $encoding)
            );

            $longest_common_suffix = '';
            for ($i = 1; $i <= $max_length; ++$i) {
                $char = \mb_substr($str1, -$i, 1);

                if (
                    $char !== false /* @phpstan-ignore-line | old polyfill will return false, or? */
                    &&
                    $char === \mb_substr($str2, -$i, 1)
                ) {
                    $longest_common_suffix = $char . $longest_common_suffix;
                } else {
                    break;
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $max_length = (int) \min(
                self::strlen($str1, $encoding),
                self::strlen($str2, $encoding)
            );

            $longest_common_suffix = '';
            for ($i = 1; $i <= $max_length; ++$i) {
                $char = self::substr($str1, -$i, 1, $encoding);

                if (
                    $char !== false
                    &&
                    $char === self::substr($str2, -$i, 1, $encoding)
                ) {
                    $longest_common_suffix = $char . $longest_common_suffix;
                } else {
                    break;
                }
            }
        }

        return $longest_common_suffix;
    }

    /**
     * Returns true if $str matches the supplied pattern, false otherwise.
     *
     * @param string $str     <p>The input string.</p>
     * @param string $pattern <p>Regex pattern to match against.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str matches the pattern.</p>
     */
    public static function str_matches_pattern(string $str, string $pattern): bool
    {
        return (bool) \preg_match('/' . $pattern . '/u', $str);
    }

    /**
     * Returns whether or not a character exists at an index. Offsets may be
     * negative to count from the last character in the string. Implements
     * part of the ArrayAccess interface.
     *
     * @param string $str      <p>The input string.</p>
     * @param int    $offset   <p>The index to check.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not the index exists.</p>
     */
    public static function str_offset_exists(string $str, int $offset, string $encoding = 'UTF-8'): bool
    {
        // init
        $length = (int) self::strlen($str, $encoding);

        if ($offset >= 0) {
            return $length > $offset;
        }

        return $length >= \abs($offset);
    }

    /**
     * Returns the character at the given index. Offsets may be negative to
     * count from the last character in the string. Implements part of the
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
     * does not exist.
     *
     * @param string      $str      <p>The input string.</p>
     * @param int<1, max> $index    <p>The <strong>index</strong> from which to retrieve the char.</p>
     * @param string      $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @throws \OutOfBoundsException if the positive or negative offset does not exist
     *
     * @return string
     *                <p>The character at the specified index.</p>
     *
     * @psalm-pure
     */
    public static function str_offset_get(string $str, int $index, string $encoding = 'UTF-8'): string
    {
        // init
        $length = (int) self::strlen($str);

        if (
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            ($index >= 0 && $length <= $index)
            ||
            $length < \abs($index)
        ) {
            throw new \OutOfBoundsException('No character exists at the index');
        }

        return self::char_at($str, $index, $encoding);
    }

    /**
     * Pad a UTF-8 string to a given length with another string.
     *
     * EXAMPLE: <code>UTF8::str_pad('中文空白', 10, '_', STR_PAD_BOTH); // '___中文空白___'</code>
     *
     * @param string     $str        <p>The input string.</p>
     * @param int        $pad_length <p>The length of return string.</p>
     * @param string     $pad_string [optional] <p>String to use for padding the input string.</p>
     * @param int|string $pad_type   [optional] <p>
     *                               Can be <strong>STR_PAD_RIGHT</strong> (default), [or string "right"]<br>
     *                               <strong>STR_PAD_LEFT</strong> [or string "left"] or<br>
     *                               <strong>STR_PAD_BOTH</strong> [or string "both"]
     *                               </p>
     * @param string     $encoding   [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Returns the padded string.</p>
     */
    public static function str_pad(
        string $str,
        int $pad_length,
        string $pad_string = ' ',
        $pad_type = \STR_PAD_RIGHT,
        string $encoding = 'UTF-8'
    ): string {
        if ($pad_length === 0 || $pad_string === '') {
            return $str;
        }

        if ($pad_type !== (int) $pad_type) {
            if ($pad_type === 'left') {
                $pad_type = \STR_PAD_LEFT;
            } elseif ($pad_type === 'right') {
                $pad_type = \STR_PAD_RIGHT;
            } elseif ($pad_type === 'both') {
                $pad_type = \STR_PAD_BOTH;
            } else {
                throw new \InvalidArgumentException(
                    'Pad expects $pad_type to be "STR_PAD_*" or ' . "to be one of 'left', 'right' or 'both'"
                );
            }
        }

        if ($encoding === 'UTF-8') {
            $str_length = (int) \mb_strlen($str);

            if ($pad_length >= $str_length) {
                switch ($pad_type) {
                    case \STR_PAD_LEFT:
                        $ps_length = (int) \mb_strlen($pad_string);

                        $diff = ($pad_length - $str_length);

                        $pre = (string) \mb_substr(
                            \str_repeat($pad_string, (int) \ceil($diff / $ps_length)),
                            0,
                            $diff
                        );
                        $post = '';

                        break;

                    case \STR_PAD_BOTH:
                        $diff = ($pad_length - $str_length);

                        $ps_length_left = (int) \floor($diff / 2);

                        $ps_length_right = (int) \ceil($diff / 2);

                        $pre = (string) \mb_substr(
                            \str_repeat($pad_string, $ps_length_left),
                            0,
                            $ps_length_left
                        );
                        $post = (string) \mb_substr(
                            \str_repeat($pad_string, $ps_length_right),
                            0,
                            $ps_length_right
                        );

                        break;

                    case \STR_PAD_RIGHT:
                    default:
                        $ps_length = (int) \mb_strlen($pad_string);

                        $diff = ($pad_length - $str_length);

                        $post = (string) \mb_substr(
                            \str_repeat($pad_string, (int) \ceil($diff / $ps_length)),
                            0,
                            $diff
                        );
                        $pre = '';
                }

                return $pre . $str . $post;
            }

            return $str;
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        $str_length = (int) self::strlen($str, $encoding);

        if ($pad_length >= $str_length) {
            switch ($pad_type) {
                case \STR_PAD_LEFT:
                    $ps_length = (int) self::strlen($pad_string, $encoding);

                    $diff = ($pad_length - $str_length);

                    $pre = (string) self::substr(
                        \str_repeat($pad_string, (int) \ceil($diff / $ps_length)),
                        0,
                        $diff,
                        $encoding
                    );
                    $post = '';

                    break;

                case \STR_PAD_BOTH:
                    $diff = ($pad_length - $str_length);

                    $ps_length_left = (int) \floor($diff / 2);

                    $ps_length_right = (int) \ceil($diff / 2);

                    $pre = (string) self::substr(
                        \str_repeat($pad_string, $ps_length_left),
                        0,
                        $ps_length_left,
                        $encoding
                    );
                    $post = (string) self::substr(
                        \str_repeat($pad_string, $ps_length_right),
                        0,
                        $ps_length_right,
                        $encoding
                    );

                    break;

                case \STR_PAD_RIGHT:
                default:
                    $ps_length = (int) self::strlen($pad_string, $encoding);

                    $diff = ($pad_length - $str_length);

                    $post = (string) self::substr(
                        \str_repeat($pad_string, (int) \ceil($diff / $ps_length)),
                        0,
                        $diff,
                        $encoding
                    );
                    $pre = '';
            }

            return $pre . $str . $post;
        }

        return $str;
    }

    /**
     * Returns a new string of a given length such that both sides of the
     * string are padded. Alias for "UTF8::str_pad()" with a $pad_type of 'both'.
     *
     * @param string $str
     * @param int    $length   <p>Desired string length after padding.</p>
     * @param string $pad_str  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string with padding applied.</p>
     */
    public static function str_pad_both(
        string $str,
        int $length,
        string $pad_str = ' ',
        string $encoding = 'UTF-8'
    ): string {
        return self::str_pad(
            $str,
            $length,
            $pad_str,
            \STR_PAD_BOTH,
            $encoding
        );
    }

    /**
     * Returns a new string of a given length such that the beginning of the
     * string is padded. Alias for "UTF8::str_pad()" with a $pad_type of 'left'.
     *
     * @param string $str
     * @param int    $length   <p>Desired string length after padding.</p>
     * @param string $pad_str  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string with left padding.</p>
     */
    public static function str_pad_left(
        string $str,
        int $length,
        string $pad_str = ' ',
        string $encoding = 'UTF-8'
    ): string {
        return self::str_pad(
            $str,
            $length,
            $pad_str,
            \STR_PAD_LEFT,
            $encoding
        );
    }

    /**
     * Returns a new string of a given length such that the end of the string
     * is padded. Alias for "UTF8::str_pad()" with a $pad_type of 'right'.
     *
     * @param string $str
     * @param int    $length   <p>Desired string length after padding.</p>
     * @param string $pad_str  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string with right padding.</p>
     */
    public static function str_pad_right(
        string $str,
        int $length,
        string $pad_str = ' ',
        string $encoding = 'UTF-8'
    ): string {
        return self::str_pad(
            $str,
            $length,
            $pad_str,
            \STR_PAD_RIGHT,
            $encoding
        );
    }

    /**
     * Repeat a string.
     *
     * EXAMPLE: <code>UTF8::str_repeat("°~\xf0\x90\x28\xbc", 2); // '°~ð(¼°~ð(¼'</code>
     *
     * @param string      $str   <p>
     *                           The string to be repeated.
     *                           </p>
     * @param int<1, max> $multiplier <p>
     *                           Number of time the input string should be
     *                           repeated.
     *                           </p>
     *                           <p>
     *                           multiplier has to be greater than or equal to 0.
     *                           If the multiplier is set to 0, the function
     *                           will return an empty string.
     *                           </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The repeated string.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_repeat(string $str, int $multiplier): string
    {
        $str = self::filter($str);

        return \str_repeat($str, $multiplier);
    }

    /**
     * INFO: This is only a wrapper for "str_replace()"  -> the original functions is already UTF-8 safe.
     *
     * Replace all occurrences of the search string with the replacement string
     *
     * @see http://php.net/manual/en/function.str-replace.php
     *
     * @param string|string[] $search  <p>
     *                                 The value being searched for, otherwise known as the needle.
     *                                 An array may be used to designate multiple needles.
     *                                 </p>
     * @param string|string[] $replace <p>
     *                                 The replacement value that replaces found search
     *                                 values. An array may be used to designate multiple replacements.
     *                                 </p>
     * @param string|string[] $subject <p>
     *                                 The string or array of strings being searched and replaced on,
     *                                 otherwise known as the haystack.
     *                                 </p>
     *                                 <p>
     *                                 If subject is an array, then the search and
     *                                 replace is performed with every entry of
     *                                 subject, and the return value is an array as
     *                                 well.
     *                                 </p>
     * @param int|null        $count   [optional] <p>
     *                                 If passed, this will hold the number of matched and replaced needles.
     *                                 </p>
     *
     * @psalm-pure
     *
     * @return string|string[]
     *                         <p>This function returns a string or an array with the replaced values.</p>
     *
     * @template TStrReplaceSubject
     * @phpstan-param TStrReplaceSubject $subject
     * @phpstan-return TStrReplaceSubject
     *
     * @deprecated please use \str_replace() instead
     */
    public static function str_replace(
        $search,
        $replace,
        $subject,
        int &$count = null
    ) {
        /**
         * @psalm-suppress PossiblyNullArgument
         * @phpstan-var TStrReplaceSubject $return;
         */
        $return = \str_replace(
            $search,
            $replace,
            $subject,
            $count
        );

        return $return;
    }

    /**
     * Replaces $search from the beginning of string with $replacement.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string after the replacements.</p>
     */
    public static function str_replace_beginning(
        string $str,
        string $search,
        string $replacement
    ): string {
        if ($str === '') {
            if ($replacement === '') {
                return '';
            }

            if ($search === '') {
                return $replacement;
            }
        }

        if ($search === '') {
            return $str . $replacement;
        }

        $searchLength = \strlen($search);
        if (\strncmp($str, $search, $searchLength) === 0) {
            return $replacement . \substr($str, $searchLength);
        }

        return $str;
    }

    /**
     * Replaces $search from the ending of string with $replacement.
     *
     * @param string $str         <p>The input string.</p>
     * @param string $search      <p>The string to search for.</p>
     * @param string $replacement <p>The replacement.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string after the replacements.</p>
     */
    public static function str_replace_ending(
        string $str,
        string $search,
        string $replacement
    ): string {
        if ($str === '') {
            if ($replacement === '') {
                return '';
            }

            if ($search === '') {
                return $replacement;
            }
        }

        if ($search === '') {
            return $str . $replacement;
        }

        if (\strpos($str, $search, \strlen($str) - \strlen($search)) !== false) {
            $str = \substr($str, 0, -\strlen($search)) . $replacement;
        }

        return $str;
    }

    /**
     * Replace the first "$search"-term with the "$replace"-term.
     *
     * @param string $search
     * @param string $replace
     * @param string $subject
     *
     * @psalm-pure
     *
     * @return string
     *
     * @psalm-suppress InvalidReturnType
     */
    public static function str_replace_first(
        string $search,
        string $replace,
        string $subject
    ): string {
        $pos = self::strpos($subject, $search);

        if ($pos !== false) {
            /**
             * @psalm-suppress InvalidReturnStatement
             */
            return self::substr_replace(
                $subject,
                $replace,
                $pos,
                (int) self::strlen($search)
            );
        }

        return $subject;
    }

    /**
     * Replace the last "$search"-term with the "$replace"-term.
     *
     * @param string $search
     * @param string $replace
     * @param string $subject
     *
     * @psalm-pure
     *
     * @return string
     *
     * @psalm-suppress InvalidReturnType
     */
    public static function str_replace_last(
        string $search,
        string $replace,
        string $subject
    ): string {
        $pos = self::strrpos($subject, $search);
        if ($pos !== false) {
            /**
             * @psalm-suppress InvalidReturnStatement
             */
            return self::substr_replace(
                $subject,
                $replace,
                $pos,
                (int) self::strlen($search)
            );
        }

        return $subject;
    }

    /**
     * Shuffles all the characters in the string.
     *
     * INFO: uses random algorithm which is weak for cryptography purposes
     *
     * EXAMPLE: <code>UTF8::str_shuffle('fòô bàř fòô'); // 'àòôřb ffòô '</code>
     *
     * @param string $str      <p>The input string</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @return string
     *                <p>The shuffled string.</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function str_shuffle(string $str, string $encoding = 'UTF-8'): string
    {
        if ($encoding === 'UTF-8') {
            $indexes = \range(0, (int) \mb_strlen($str) - 1);
            \shuffle($indexes);

            // init
            $shuffled_str = '';

            foreach ($indexes as &$i) {
                $tmp_sub_str = \mb_substr($str, $i, 1);
                if ($tmp_sub_str !== false) { /* @phpstan-ignore-line | old polyfill will return false, or? */
                    $shuffled_str .= $tmp_sub_str;
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $indexes = \range(0, (int) self::strlen($str, $encoding) - 1);
            \shuffle($indexes);

            // init
            $shuffled_str = '';

            foreach ($indexes as &$i) {
                $tmp_sub_str = self::substr($str, $i, 1, $encoding);
                if ($tmp_sub_str !== false) {
                    $shuffled_str .= $tmp_sub_str;
                }
            }
        }

        return $shuffled_str;
    }

    /**
     * Returns the substring beginning at $start, and up to, but not including
     * the index specified by $end. If $end is omitted, the function extracts
     * the remaining string. If $end is negative, it is computed from the end
     * of the string.
     *
     * @param string   $str
     * @param int      $start    <p>Initial index from which to begin extraction.</p>
     * @param int|null $end      [optional] <p>Index at which to end extraction. Default: null</p>
     * @param string   $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The extracted substring.</p><p>If <i>str</i> is shorter than <i>start</i>
     *                      characters long, <b>FALSE</b> will be returned.
     */
    public static function str_slice(
        string $str,
        int $start,
        int $end = null,
        string $encoding = 'UTF-8'
    ) {
        if ($encoding === 'UTF-8') {
            if ($end === null) {
                $length = (int) \mb_strlen($str);
            } elseif ($end >= 0 && $end <= $start) {
                return '';
            } elseif ($end < 0) {
                $length = (int) \mb_strlen($str) + $end - $start;
            } else {
                $length = $end - $start;
            }

            return \mb_substr($str, $start, $length);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ($end === null) {
            $length = (int) self::strlen($str, $encoding);
        } elseif ($end >= 0 && $end <= $start) {
            return '';
        } elseif ($end < 0) {
            $length = (int) self::strlen($str, $encoding) + $end - $start;
        } else {
            $length = $end - $start;
        }

        return self::substr($str, $start, $length, $encoding);
    }

    /**
     * Convert a string to e.g.: "snake_case"
     *
     * @param string $str
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string in snake_case.</p>
     */
    public static function str_snakeize(string $str, string $encoding = 'UTF-8'): string
    {
        if ($str === '') {
            return '';
        }

        $str = \str_replace(
            '-',
            '_',
            self::normalize_whitespace($str)
        );

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        $str = (string) \preg_replace_callback(
            '/([\\p{N}|\\p{Lu}])/u',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                $match = $matches[1];
                $match_int = (int) $match;

                if ((string) $match_int === $match) {
                    return '_' . $match . '_';
                }

                if ($encoding === 'UTF-8') {
                    return '_' . \mb_strtolower($match);
                }

                return '_' . self::strtolower($match, $encoding);
            },
            $str
        );

        $str = (string) \preg_replace(
            [
                '/\\s+/u',        // convert spaces to "_"
                '/^\\s+|\\s+$/u', // trim leading & trailing spaces
                '/_+/',           // remove double "_"
            ],
            [
                '_',
                '',
                '_',
            ],
            $str
        );

        return \trim(\trim($str, '_')); // trim leading & trailing "_" + whitespace
    }

    /**
     * Sort all characters according to code points.
     *
     * EXAMPLE: <code>UTF8::str_sort('  -ABC-中文空白-  '); // '    ---ABC中文白空'</code>
     *
     * @param string $str    <p>A UTF-8 string.</p>
     * @param bool   $unique <p>Sort unique. If <strong>true</strong>, repeated characters are ignored.</p>
     * @param bool   $desc   <p>If <strong>true</strong>, will sort characters in reverse code point order.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string of sorted characters.</p>
     */
    public static function str_sort(string $str, bool $unique = false, bool $desc = false): string
    {
        /** @var int[] $array */
        $array = self::codepoints($str);

        if ($unique) {
            $array = \array_flip(\array_flip($array));
        }

        if ($desc) {
            \arsort($array);
        } else {
            \asort($array);
        }

        return self::string($array);
    }

    /**
     * Convert a string to an array of Unicode characters.
     *
     * EXAMPLE: <code>
     * UTF8::str_split_array(['中文空白', 'test'], 2); // [['中文', '空白'], ['te', 'st']]
     * </code>
     *
     * @param int[]|string[] $input                   <p>The string[] or int[] to split into array.</p>
     * @param int<1, max>    $length                  [optional] <p>Max character length of each array
     *                                                element.</p>
     * @param bool           $clean_utf8              [optional] <p>Remove non UTF-8 chars from the
     *                                                string.</p>
     * @param bool           $try_to_use_mb_functions [optional] <p>Set to false, if you don't want to use
     *                                                "mb_substr"</p>
     *
     * @psalm-pure
     *
     * @return list<list<string>>
     *                            <p>An array containing chunks of the input.</p>
     */
    public static function str_split_array(
        array $input,
        int $length = 1,
        bool $clean_utf8 = false,
        bool $try_to_use_mb_functions = true
    ): array {
        foreach ($input as &$v) {
            $v = self::str_split(
                $v,
                $length,
                $clean_utf8,
                $try_to_use_mb_functions
            );
        }

        /** @var list<list<string>> $input */
        return $input;
    }

    /**
     * Convert a string to an array of unicode characters.
     *
     * EXAMPLE: <code>UTF8::str_split('中文空白'); // array('中', '文', '空', '白')</code>
     *
     * @param int|string  $str                     <p>The string or int to split into array.</p>
     * @param int<1, max> $length                  [optional] <p>Max character length of each array
     *                                            element.</p>
     * @param bool        $clean_utf8              [optional] <p>Remove non UTF-8 chars from the
     *                                            string.</p>
     * @param bool        $try_to_use_mb_functions [optional] <p>Set to false, if you don't want to use
     *                                            "mb_substr"</p>
     *
     * @psalm-pure
     *
     * @return list<string>
     *                      <p>An array containing chunks of chars from the input.</p>
     */
    public static function str_split(
        $str,
        int $length = 1,
        bool $clean_utf8 = false,
        bool $try_to_use_mb_functions = true
    ): array {
        /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
        if ($length <= 0) {
            return [];
        }

        // this is only an old fallback
        /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
        /** @var int|int[]|string|string[] $str */
        $str = $str;
        if (\is_array($str)) {
            /** @psalm-suppress InvalidReturnStatement */
            /** @phpstan-ignore-next-line - old code :/ */
            return self::str_split_array(
                $str,
                $length,
                $clean_utf8,
                $try_to_use_mb_functions
            );
        }

        // init
        $str = (string) $str;

        if ($str === '') {
            return [];
        }

        if ($clean_utf8) {
            $str = self::clean($str);
        }

        if (
            $try_to_use_mb_functions
            &&
            self::$SUPPORT['mbstring'] === true
        ) {
            if (\function_exists('mb_str_split')) {
                try {
                    /**
                     * @psalm-suppress ImpureFunctionCall - why?
                     */
                    $return = \mb_str_split($str, $length);
                } catch (\Error $e) {
                    // PHP >= 8.0 : mb_str_split() will now throw ValueError on error. Previously, mb_str_split() returned false instead.
                    $return = false;
                }
                if ($return !== false) {
                    return $return;
                }
            }

            $i_max = \mb_strlen($str);
            if ($i_max <= 127) {
                $ret = [];
                for ($i = 0; $i < $i_max; ++$i) {
                    $ret[] = \mb_substr($str, $i, 1);
                }
            } else {
                $return_array = [];
                \preg_match_all('/./us', $str, $return_array);
                $ret = $return_array[0] ?? [];
            }
        } elseif (self::$SUPPORT['pcre_utf8'] === true) {
            $return_array = [];
            \preg_match_all('/./us', $str, $return_array);
            $ret = $return_array[0] ?? [];
        } else {

            // fallback

            $ret = [];
            $len = \strlen($str);

            for ($i = 0; $i < $len; ++$i) {
                if (($str[$i] & "\x80") === "\x00") {
                    $ret[] = $str[$i];
                } elseif (
                    isset($str[$i + 1])
                    &&
                    ($str[$i] & "\xE0") === "\xC0"
                ) {
                    if (($str[$i + 1] & "\xC0") === "\x80") {
                        $ret[] = $str[$i] . $str[$i + 1];

                        ++$i;
                    }
                } elseif (
                    isset($str[$i + 2])
                    &&
                    ($str[$i] & "\xF0") === "\xE0"
                ) {
                    if (
                        ($str[$i + 1] & "\xC0") === "\x80"
                        &&
                        ($str[$i + 2] & "\xC0") === "\x80"
                    ) {
                        $ret[] = $str[$i] . $str[$i + 1] . $str[$i + 2];

                        $i += 2;
                    }
                } elseif (
                    isset($str[$i + 3])
                    &&
                    ($str[$i] & "\xF8") === "\xF0"
                ) {
                    if (
                        ($str[$i + 1] & "\xC0") === "\x80"
                        &&
                        ($str[$i + 2] & "\xC0") === "\x80"
                        &&
                        ($str[$i + 3] & "\xC0") === "\x80"
                    ) {
                        $ret[] = $str[$i] . $str[$i + 1] . $str[$i + 2] . $str[$i + 3];

                        $i += 3;
                    }
                }
            }
        }

        if ($length > 1) {
            return \array_map(
                static function (array $item): string {
                    /* @phpstan-ignore-next-line | "array_map + array_chunk" is not supported by phpstan?! */
                    return \implode('', $item);
                },
                \array_chunk($ret, $length)
            );
        }

        if (isset($ret[0]) && $ret[0] === '') {
            return [];
        }

        return $ret;
    }

    /**
     * Splits the string with the provided regular expression, returning an
     * array of strings. An optional integer $limit will truncate the
     * results.
     *
     * @param string $str
     * @param string $pattern <p>The regex with which to split the string.</p>
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no limit</p>
     *
     * @psalm-pure
     *
     * @return string[]
     *                  <p>An array of strings.</p>
     */
    public static function str_split_pattern(string $str, string $pattern, int $limit = -1): array
    {
        if ($limit === 0) {
            return [];
        }

        if ($pattern === '') {
            return [$str];
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($limit >= 0) {
                $result_tmp = \mb_split($pattern, $str);
                if ($result_tmp === false) {
                    return [];
                }

                $result = [];
                foreach ($result_tmp as $item_tmp) {
                    if ($limit === 0) {
                        break;
                    }
                    --$limit;

                    $result[] = $item_tmp;
                }

                return $result;
            }

            $result = \mb_split($pattern, $str);
            if ($result === false) {
                return [];
            }

            return $result;
        }

        if ($limit > 0) {
            ++$limit;
        } else {
            $limit = -1;
        }

        $array = \preg_split('/' . \preg_quote($pattern, '/') . '/u', $str, $limit);
        if ($array === false) {
            return [];
        }

        if ($limit > 0 && \count($array) === $limit) {
            \array_pop($array);
        }

        return $array;
    }

    /**
     * Check if the string starts with the given substring.
     *
     * EXAMPLE: <code>
     * UTF8::str_starts_with('ΚόσμεMiddleEnd', 'Κόσμε'); // true
     * UTF8::str_starts_with('ΚόσμεMiddleEnd', 'κόσμε'); // false
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function str_starts_with(string $haystack, string $needle): bool
    {
        if ($needle === '') {
            return true;
        }

        if ($haystack === '') {
            return false;
        }

        if (\PHP_VERSION_ID >= 80000) {
            /** @phpstan-ignore-next-line - only for PHP8 */
            return \str_starts_with($haystack, $needle);
        }

        return \strncmp($haystack, $needle, \strlen($needle)) === 0;
    }

    /**
     * Returns true if the string begins with any of $substrings, false otherwise.
     *
     * - case-sensitive
     *
     * @param string   $str        <p>The input string.</p>
     * @param scalar[] $substrings <p>Substrings to look for.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>Whether or not $str starts with $substring.</p>
     */
    public static function str_starts_with_any(string $str, array $substrings): bool
    {
        if ($str === '') {
            return false;
        }

        if ($substrings === []) {
            return false;
        }

        foreach ($substrings as &$substring) {
            if (self::str_starts_with($str, (string) $substring)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Gets the substring after the first occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_after_first_separator(string $str, string $separator, string $encoding = 'UTF-8'): string
    {
        if ($separator === '' || $str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $offset = \mb_strpos($str, $separator);
            if ($offset === false) {
                return '';
            }

            return (string) \mb_substr(
                $str,
                $offset + (int) \mb_strlen($separator)
            );
        }

        $offset = self::strpos($str, $separator, 0, $encoding);
        if ($offset === false) {
            return '';
        }

        return (string) \mb_substr(
            $str,
            $offset + (int) self::strlen($separator, $encoding),
            null,
            $encoding
        );
    }

    /**
     * Gets the substring after the last occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_after_last_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $offset = \mb_strrpos($str, $separator);
            if ($offset === false) {
                return '';
            }

            return (string) \mb_substr(
                $str,
                $offset + (int) \mb_strlen($separator)
            );
        }

        $offset = self::strrpos($str, $separator, 0, $encoding);
        if ($offset === false) {
            return '';
        }

        return (string) self::substr(
            $str,
            $offset + (int) self::strlen($separator, $encoding),
            null,
            $encoding
        );
    }

    /**
     * Gets the substring before the first occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_before_first_separator(
        string $str,
        string $separator,
        string $encoding = 'UTF-8'
    ): string {
        if ($separator === '' || $str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $offset = \mb_strpos($str, $separator);
            if ($offset === false) {
                return '';
            }

            return (string) \mb_substr(
                $str,
                0,
                $offset
            );
        }

        $offset = self::strpos($str, $separator, 0, $encoding);
        if ($offset === false) {
            return '';
        }

        return (string) self::substr(
            $str,
            0,
            $offset,
            $encoding
        );
    }

    /**
     * Gets the substring before the last occurrence of a separator.
     *
     * @param string $str       <p>The input string.</p>
     * @param string $separator <p>The string separator.</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_before_last_separator(string $str, string $separator, string $encoding = 'UTF-8'): string
    {
        if ($separator === '' || $str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            $offset = \mb_strrpos($str, $separator);
            if ($offset === false) {
                return '';
            }

            return (string) \mb_substr(
                $str,
                0,
                $offset
            );
        }

        $offset = self::strrpos($str, $separator, 0, $encoding);
        if ($offset === false) {
            return '';
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        return (string) self::substr(
            $str,
            0,
            $offset,
            $encoding
        );
    }

    /**
     * Gets the substring after (or before via "$before_needle") the first occurrence of the "$needle".
     *
     * @param string $str           <p>The input string.</p>
     * @param string $needle        <p>The string to look for.</p>
     * @param bool   $before_needle [optional] <p>Default: false</p>
     * @param string $encoding      [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_first(
        string $str,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '' || $needle === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            if ($before_needle) {
                $part = \mb_strstr(
                    $str,
                    $needle,
                    $before_needle
                );
            } else {
                $part = \mb_strstr(
                    $str,
                    $needle
                );
            }
        } else {
            $part = self::strstr(
                $str,
                $needle,
                $before_needle,
                $encoding
            );
        }

        return $part === false ? '' : $part;
    }

    /**
     * Gets the substring after (or before via "$before_needle") the last occurrence of the "$needle".
     *
     * @param string $str           <p>The input string.</p>
     * @param string $needle        <p>The string to look for.</p>
     * @param bool   $before_needle [optional] <p>Default: false</p>
     * @param string $encoding      [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function str_substr_last(
        string $str,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '' || $needle === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            if ($before_needle) {
                $part = \mb_strrchr(
                    $str,
                    $needle,
                    $before_needle
                );
            } else {
                $part = \mb_strrchr(
                    $str,
                    $needle
                );
            }
        } else {
            $part = self::strrchr(
                $str,
                $needle,
                $before_needle,
                $encoding
            );
        }

        return $part === false ? '' : $part;
    }

    /**
     * Surrounds $str with the given substring.
     *
     * @param string $str
     * @param string $substring <p>The substring to add to both sides.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with the substring both prepended and appended.</p>
     *
     * @template T as string
     * @template TSub as string
     * @phpstan-param T $str
     * @phpstan-param TSub $substring
     * @phpstan-return (T is non-empty-string ? non-empty-string : (TSub is non-empty-string ? non-empty-string : string))
     */
    public static function str_surround(string $str, string $substring): string
    {
        return $substring . $str . $substring;
    }

    /**
     * Returns a trimmed string with the first letter of each word capitalized.
     * Also accepts an array, $ignore, allowing you to list words not to be
     * capitalized.
     *
     * @param string        $str
     * @param string[]|null $ignore                        [optional] <p>An array of words not to capitalize or
     *                                                     null. Default: null</p>
     * @param string        $encoding                      [optional] <p>Default: 'UTF-8'</p>
     * @param bool          $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the
     *                                                     string.</p>
     * @param string|null   $lang                          [optional] <p>Set the language for special cases: az,
     *                                                     el, lt, tr</p>
     * @param bool          $try_to_keep_the_string_length [optional] <p>true === try to keep the string length:
     *                                                     e.g. ẞ -> ß</p>
     * @param bool          $use_trim_first                [optional] <p>true === trim the input string,
     *                                                     first</p>
     * @param string|null   $word_define_chars             [optional] <p>An string of chars that will be used as
     *                                                     whitespace separator === words.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The titleized string.</p>
     */
    public static function str_titleize(
        string $str,
        array $ignore = null,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false,
        bool $use_trim_first = true,
        string $word_define_chars = null
    ): string {
        if ($str === '') {
            return '';
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($use_trim_first) {
            $str = \trim($str);
        }

        if ($clean_utf8) {
            $str = self::clean($str);
        }

        $use_mb_functions = $lang === null && !$try_to_keep_the_string_length;

        if ($word_define_chars) {
            $word_define_chars = \preg_quote($word_define_chars, '/');
        } else {
            $word_define_chars = '';
        }

        $str = (string) \preg_replace_callback(
            '/([^\\s' . $word_define_chars . ']+)/u',
            static function (array $match) use ($try_to_keep_the_string_length, $lang, $ignore, $use_mb_functions, $encoding): string {
                if ($ignore !== null && \in_array($match[0], $ignore, true)) {
                    return $match[0];
                }

                if ($use_mb_functions) {
                    if ($encoding === 'UTF-8') {
                        return \mb_strtoupper(\mb_substr($match[0], 0, 1))
                               . \mb_strtolower(\mb_substr($match[0], 1));
                    }

                    return \mb_strtoupper(\mb_substr($match[0], 0, 1, $encoding), $encoding)
                           . \mb_strtolower(\mb_substr($match[0], 1, null, $encoding), $encoding);
                }

                return self::ucfirst(
                    self::strtolower(
                        $match[0],
                        $encoding,
                        false,
                        $lang,
                        $try_to_keep_the_string_length
                    ),
                    $encoding,
                    false,
                    $lang,
                    $try_to_keep_the_string_length
                );
            },
            $str
        );

        return $str;
    }

    /**
     * Convert a string into a obfuscate string.
     *
     * EXAMPLE: <code>
     *
     * UTF8::str_obfuscate('lars@moelleken.org', 0.5, '*', ['@', '.']); // e.g. "l***@m**lleke*.*r*"
     * </code>
     *
     * @param string   $str
     * @param float    $percent
     * @param string   $obfuscateChar
     * @param string[] $keepChars
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The obfuscate string.</p>
     */
    public static function str_obfuscate(
        string $str,
        float $percent = 0.5,
        string $obfuscateChar = '*',
        array $keepChars = []
    ): string {
        $obfuscateCharHelper = "\u{2603}";
        $str = \str_replace($obfuscateChar, $obfuscateCharHelper, $str);

        $chars = self::chars($str);
        $charsMax = \count($chars);
        $charsMaxChange = \round($charsMax * $percent);
        $charsCounter = 0;
        $charKeyDone = [];

        while ($charsCounter < $charsMaxChange) {
            foreach ($chars as $charKey => $char) {
                if (isset($charKeyDone[$charKey])) {
                    continue;
                }

                if (\random_int(0, 100) > 50) {
                    continue;
                }

                if ($char === $obfuscateChar) {
                    continue;
                }

                ++$charsCounter;
                $charKeyDone[$charKey] = true;

                if ($charsCounter > $charsMaxChange) {
                    break;
                }

                if (\in_array($char, $keepChars, true)) {
                    continue;
                }

                $chars[$charKey] = $obfuscateChar;
            }
        }

        $str = \implode('', $chars);

        return \str_replace($obfuscateCharHelper, $obfuscateChar, $str);
    }

    /**
     * Returns a trimmed string in proper title case.
     *
     * Also accepts an array, $ignore, allowing you to list words not to be
     * capitalized.
     *
     * Adapted from John Gruber's script.
     *
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
     *
     * @param string   $str
     * @param string[] $ignore   <p>An array of words not to capitalize.</p>
     * @param string   $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The titleized string.</p>
     */
    public static function str_titleize_for_humans(
        string $str,
        array $ignore = [],
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '') {
            return '';
        }

        $small_words = [
            '(?<!q&)a',
            'an',
            'and',
            'as',
            'at(?!&t)',
            'but',
            'by',
            'en',
            'for',
            'if',
            'in',
            'of',
            'on',
            'or',
            'the',
            'to',
            'v[.]?',
            'via',
            'vs[.]?',
        ];

        if ($ignore !== []) {
            $small_words = \array_merge($small_words, $ignore);
        }

        $small_words_rx = \implode('|', $small_words);
        $apostrophe_rx = '(?x: [\'’] [[:lower:]]* )?';

        $str = \trim($str);

        if (!self::has_lowercase($str)) {
            $str = self::strtolower($str, $encoding);
        }

        // the main substitutions
        $str = (string) \preg_replace_callback(
            '~\\b (_*) (?:                                                                  # 1. Leading underscore and
                        ( (?<=[ ][/\\\\]) [[:alpha:]]+ [-_[:alpha:]/\\\\]+ |                # 2. file path or
                          [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ ' . $apostrophe_rx . ' )  #    URL, domain, or email
                        |                                                                   #
                        ( (?i: ' . $small_words_rx . ' ) ' . $apostrophe_rx . ' )           # 3. or small word (case-insensitive)
                        |                                                                   #
                        ( [[:alpha:]] [[:lower:]\'’()\[\]{}]* ' . $apostrophe_rx . ' )      # 4. or word w/o internal caps
                        |                                                                   #
                        ( [[:alpha:]] [[:alpha:]\'’()\[\]{}]* ' . $apostrophe_rx . ' )      # 5. or some other word
                      ) (_*) \\b                                                            # 6. With trailing underscore
                    ~ux',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                // preserve leading underscore
                $str = $matches[1];
                if ($matches[2]) {
                    // preserve URLs, domains, emails and file paths
                    $str .= $matches[2];
                } elseif ($matches[3]) {
                    // lower-case small words
                    $str .= self::strtolower($matches[3], $encoding);
                } elseif ($matches[4]) {
                    // capitalize word w/o internal caps
                    $str .= static::ucfirst($matches[4], $encoding);
                } else {
                    // preserve other kinds of word (iPhone)
                    $str .= $matches[5];
                }
                // preserve trailing underscore
                $str .= $matches[6];

                return $str;
            },
            $str
        );

        // Exceptions for small words: capitalize at start of title...
        $str = (string) \preg_replace_callback(
            '~(  \\A [[:punct:]]*            # start of title...
                      |  [:.;?!][ ]+                # or of subsentence...
                      |  [ ][\'"“‘(\[][ ]* )        # or of inserted subphrase...
                      ( ' . $small_words_rx . ' ) \\b # ...followed by small word
                     ~uxi',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                return $matches[1] . static::ucfirst($matches[2], $encoding);
            },
            $str
        );

        // ...and end of title
        $str = (string) \preg_replace_callback(
            '~\\b ( ' . $small_words_rx . ' ) # small word...
                      (?= [[:punct:]]* \Z          # ...at the end of the title...
                      |   [\'"’”)\]] [ ] )         # ...or of an inserted subphrase?
                     ~uxi',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                return static::ucfirst($matches[1], $encoding);
            },
            $str
        );

        // Exceptions for small words in hyphenated compound words.
        // e.g. "in-flight" -> In-Flight
        $str = (string) \preg_replace_callback(
            '~\\b
                        (?<! -)                   # Negative lookbehind for a hyphen; we do not want to match man-in-the-middle but do want (in-flight)
                        ( ' . $small_words_rx . ' )
                        (?= -[[:alpha:]]+)        # lookahead for "-someword"
                       ~uxi',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                return static::ucfirst($matches[1], $encoding);
            },
            $str
        );

        // e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point)
        $str = (string) \preg_replace_callback(
            '~\\b
                      (?<!…)                    # Negative lookbehind for a hyphen; we do not want to match man-in-the-middle but do want (stand-in)
                      ( [[:alpha:]]+- )         # $1 = first word and hyphen, should already be properly capped
                      ( ' . $small_words_rx . ' ) # ...followed by small word
                      (?!	- )                 # Negative lookahead for another -
                     ~uxi',
            /**
             * @param string[] $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches) use ($encoding): string {
                return $matches[1] . static::ucfirst($matches[2], $encoding);
            },
            $str
        );

        return $str;
    }

    /**
     * Get a binary representation of a specific string.
     *
     * EXAPLE: <code>UTF8::str_to_binary('😃'); // '11110000100111111001100010000011'</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>false on error</p>
     */
    public static function str_to_binary(string $str)
    {
        $value = \unpack('H*', $str);
        if ($value === false) {
            return false;
        }

        return \base_convert($value[1], 16, 2);
    }

    /**
     * @param string   $str
     * @param bool     $remove_empty_values <p>Remove empty values.</p>
     * @param int|null $remove_short_values <p>The min. string length or null to disable</p>
     *
     * @psalm-pure
     *
     * @return string[]
     */
    public static function str_to_lines(string $str, bool $remove_empty_values = false, int $remove_short_values = null): array
    {
        if ($str === '') {
            return $remove_empty_values ? [] : [''];
        }

        if (self::$SUPPORT['mbstring'] === true) {
            $return = \mb_split("[\r\n]{1,2}", $str);
        } else {
            $return = \preg_split("/[\r\n]{1,2}/u", $str);
        }

        if ($return === false) {
            return $remove_empty_values ? [] : [''];
        }

        if (
            $remove_short_values === null
            &&
            !$remove_empty_values
        ) {
            return $return;
        }

        return self::reduce_string_array(
            $return,
            $remove_empty_values,
            $remove_short_values
        );
    }

    /**
     * Convert a string into an array of words.
     *
     * EXAMPLE: <code>UTF8::str_to_words('中文空白 oöäü#s', '#') // array('', '中文空白', ' ', 'oöäü#s', '')</code>
     *
     * @param string   $str
     * @param string   $char_list           <p>Additional chars for the definition of "words".</p>
     * @param bool     $remove_empty_values <p>Remove empty values.</p>
     * @param int|null $remove_short_values <p>The min. string length or null to disable</p>
     *
     * @psalm-pure
     *
     * @return list<string>
     *
     * @phpstan-return ($remove_empty_values is true ? list<string> : non-empty-list<string>)
     */
    public static function str_to_words(
        string $str,
        string $char_list = '',
        bool $remove_empty_values = false,
        int $remove_short_values = null
    ): array {
        if ($str === '') {
            return $remove_empty_values ? [] : [''];
        }

        $char_list = self::rxClass($char_list, '\pL');

        $return = \preg_split("/({$char_list}+(?:[\p{Pd}’']{$char_list}+)*)/u", $str, -1, \PREG_SPLIT_DELIM_CAPTURE);
        if ($return === false) {
            return $remove_empty_values ? [] : [''];
        }

        if (
            $remove_short_values === null
            &&
            !$remove_empty_values
        ) {
            return $return;
        }

        $tmp_return = self::reduce_string_array(
            $return,
            $remove_empty_values,
            $remove_short_values
        );

        foreach ($tmp_return as &$item) {
            $item = (string) $item;
        }

        return $tmp_return;
    }

    /**
     * Truncates the string to a given length. If $substring is provided, and
     * truncating occurs, the string is further truncated so that the substring
     * may be appended without exceeding the desired length.
     *
     * @param string $str
     * @param int    $length    <p>Desired length of the truncated string.</p>
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
     * @param string $encoding  [optional] <p>Default: 'UTF-8'</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string after truncating.</p>
     */
    public static function str_truncate(
        string $str,
        int $length,
        string $substring = '',
        string $encoding = 'UTF-8'
    ): string {
        if ($str === '') {
            return '';
        }

        if ($encoding === 'UTF-8') {
            if ($length >= (int) \mb_strlen($str)) {
                return $str;
            }

            if ($substring !== '') {
                $length -= (int) \mb_strlen($substring);

                /** @noinspection UnnecessaryCastingInspection */
                return (string) \mb_substr($str, 0, $length) . $substring;
            }

            return (string) \mb_substr($str, 0, $length);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ($length >= (int) self::strlen($str, $encoding)) {
            return $str;
        }

        if ($substring !== '') {
            $length -= (int) self::strlen($substring, $encoding);
        }

        return (
               (string) self::substr(
                   $str,
                   0,
                   $length,
                   $encoding
               )
               ) . $substring;
    }

    /**
     * Truncates the string to a given length, while ensuring that it does not
     * split words. If $substring is provided, and truncating occurs, the
     * string is further truncated so that the substring may be appended without
     * exceeding the desired length.
     *
     * @param string $str
     * @param int    $length                                 <p>Desired length of the truncated string.</p>
     * @param string $substring                              [optional] <p>The substring to append if it can fit.
     *                                                       Default:
     *                                                       ''</p>
     * @param string $encoding                               [optional] <p>Default: 'UTF-8'</p>
     * @param bool   $ignore_do_not_split_words_for_one_word [optional] <p>Default: false</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string after truncating.</p>
     */
    public static function str_truncate_safe(
        string $str,
        int $length,
        string $substring = '',
        string $encoding = 'UTF-8',
        bool $ignore_do_not_split_words_for_one_word = false
    ): string {
        if ($str === '' || $length <= 0) {
            return $substring;
        }

        if ($encoding === 'UTF-8') {
            if ($length >= (int) \mb_strlen($str)) {
                return $str;
            }

            // need to further trim the string so we can append the substring
            $length -= (int) \mb_strlen($substring);
            if ($length <= 0) {
                return $substring;
            }

            /** @var false|string $truncated - needed for PhpStan (stubs error) */
            $truncated = \mb_substr($str, 0, $length);
            if ($truncated === false) {
                return '';
            }

            // if the last word was truncated
            $space_position = \mb_strpos($str, ' ', $length - 1);
            if ($space_position !== $length) {
                // find pos of the last occurrence of a space, get up to that
                $last_position = \mb_strrpos($truncated, ' ', 0);

                if (
                    $last_position !== false
                    ||
                    (
                        $space_position !== false
                        &&
                        !$ignore_do_not_split_words_for_one_word
                    )
                ) {
                    $truncated = (string) \mb_substr($truncated, 0, (int) $last_position);
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            if ($length >= (int) self::strlen($str, $encoding)) {
                return $str;
            }

            // need to further trim the string so we can append the substring
            $length -= (int) self::strlen($substring, $encoding);
            if ($length <= 0) {
                return $substring;
            }

            $truncated = self::substr($str, 0, $length, $encoding);

            if ($truncated === false) {
                return '';
            }

            // if the last word was truncated
            $space_position = self::strpos($str, ' ', $length - 1, $encoding);
            if ($space_position !== $length) {
                // find pos of the last occurrence of a space, get up to that
                $last_position = self::strrpos($truncated, ' ', 0, $encoding);

                if (
                    $last_position !== false
                    ||
                    (
                        $space_position !== false
                        &&
                        !$ignore_do_not_split_words_for_one_word
                    )
                ) {
                    $truncated = (string) self::substr($truncated, 0, (int) $last_position, $encoding);
                }
            }
        }

        return $truncated . $substring;
    }

    /**
     * Returns a lowercase and trimmed string separated by underscores.
     * Underscores are inserted before uppercase characters (with the exception
     * of the first character of the string), and in place of spaces as well as
     * dashes.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The underscored string.</p>
     */
    public static function str_underscored(string $str): string
    {
        return self::str_delimit($str, '_');
    }

    /**
     * Returns an UpperCamelCase version of the supplied string. It trims
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
     * and underscores, and removes spaces, dashes, underscores.
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string      $encoding                      [optional] <p>Default: 'UTF-8'</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string in UpperCamelCase.</p>
     */
    public static function str_upper_camelize(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        return self::ucfirst(self::str_camelize($str, $encoding), $encoding, $clean_utf8, $lang, $try_to_keep_the_string_length);
    }

    /**
     * Get the number of words in a specific string.
     *
     * EXAMPLES: <code>
     * // format: 0 -> return only word count (int)
     * //
     * UTF8::str_word_count('中文空白 öäü abc#c'); // 4
     * UTF8::str_word_count('中文空白 öäü abc#c', 0, '#'); // 3
     *
     * // format: 1 -> return words (array)
     * //
     * UTF8::str_word_count('中文空白 öäü abc#c', 1); // array('中文空白', 'öäü', 'abc', 'c')
     * UTF8::str_word_count('中文空白 öäü abc#c', 1, '#'); // array('中文空白', 'öäü', 'abc#c')
     *
     * // format: 2 -> return words with offset (array)
     * //
     * UTF8::str_word_count('中文空白 öäü ab#c', 2); // array(0 => '中文空白', 5 => 'öäü', 9 => 'abc', 13 => 'c')
     * UTF8::str_word_count('中文空白 öäü ab#c', 2, '#'); // array(0 => '中文空白', 5 => 'öäü', 9 => 'abc#c')
     * </code>
     *
     * @param string $str       <p>The input string.</p>
     * @param int    $format    [optional] <p>
     *                          <strong>0</strong> => return a number of words (default)<br>
     *                          <strong>1</strong> => return an array of words<br>
     *                          <strong>2</strong> => return an array of words with word-offset as key
     *                          </p>
     * @param string $char_list [optional] <p>Additional chars that contains to words and do not start a new word.</p>
     *
     * @psalm-pure
     *
     * @return int|string[]
     *                      <p>The number of words in the string.</p>
     *
     * @phpstan-param 0|1|2 $format
     * @phpstan-return ($format is 2 ? array<int, string> : ($format is 1 ? list<string> : 0|positive-int))
     */
    public static function str_word_count(string $str, int $format = 0, string $char_list = '')
    {
        $str_parts = self::str_to_words($str, $char_list);

        $len = \count($str_parts);

        if ($format === 1) {
            $number_of_words = [];
            for ($i = 1; $i < $len; $i += 2) {
                $number_of_words[] = $str_parts[$i];
            }

            return $number_of_words;
        }

        if ($format === 2) {
            $number_of_words = [];
            $offset = (int) self::strlen($str_parts[0]);
            for ($i = 1; $i < $len; $i += 2) {
                $number_of_words[$offset] = $str_parts[$i];
                $offset += (int) self::strlen($str_parts[$i]) + (int) self::strlen($str_parts[$i + 1]);
            }

            return $number_of_words;
        }

        $number_of_words = (int) (($len - 1) / 2);

        /* @phpstan-ignore-next-line | it should be 0|positive-int, maybe nested "phpstan-return" is not working? */
        return $number_of_words;
    }

    /**
     * Case-insensitive string comparison.
     *
     * INFO: Case-insensitive version of UTF8::strcmp()
     *
     * EXAMPLE: <code>UTF8::strcasecmp("iñtërnâtiôn\nàlizætiøn", "Iñtërnâtiôn\nàlizætiøn"); // 0</code>
     *
     * @param string $str1     <p>The first string.</p>
     * @param string $str2     <p>The second string.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if str1 is less than str2;<br>
     *             <strong>&gt; 0</strong> if str1 is greater than str2,<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strcasecmp(
        string $str1,
        string $str2,
        string $encoding = 'UTF-8'
    ): int {
        return self::strcmp(
            self::strtocasefold(
                $str1,
                true,
                false,
                $encoding,
                null,
                false
            ),
            self::strtocasefold(
                $str2,
                true,
                false,
                $encoding,
                null,
                false
            )
        );
    }

    /**
     * Case-sensitive string comparison.
     *
     * EXAMPLE: <code>UTF8::strcmp("iñtërnâtiôn\nàlizætiøn", "iñtërnâtiôn\nàlizætiøn"); // 0</code>
     *
     * @param string $str1 <p>The first string.</p>
     * @param string $str2 <p>The second string.</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if str1 is less than str2<br>
     *             <strong>&gt; 0</strong> if str1 is greater than str2<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strcmp(string $str1, string $str2): int
    {
        if ($str1 === $str2) {
            return 0;
        }

        return \strcmp(
            \Normalizer::normalize($str1, \Normalizer::NFD),
            \Normalizer::normalize($str2, \Normalizer::NFD)
        );
    }

    /**
     * Find length of initial segment not matching mask.
     *
     * @param string   $str
     * @param string   $char_list
     * @param int      $offset
     * @param int|null $length
     * @param string   $encoding  [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *
     * @phpstan-return 0|positive-int
     */
    public static function strcspn(
        string $str,
        string $char_list,
        int $offset = 0,
        int $length = null,
        string $encoding = 'UTF-8'
    ): int {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($char_list === '') {
            return (int) self::strlen($str, $encoding);
        }

        if ($offset || $length !== null) {
            if ($encoding === 'UTF-8') {
                if ($length === null) {
                    $str_tmp = \mb_substr($str, $offset);
                } else {
                    $str_tmp = \mb_substr($str, $offset, $length);
                }
            } else {
                $str_tmp = self::substr($str, $offset, $length, $encoding);
            }

            if ($str_tmp === false) {
                return 0;
            }

            $str = $str_tmp;
        }

        if ($str === '') {
            return 0;
        }

        $matches = [];
        if (\preg_match('/^(.*?)' . self::rxClass($char_list) . '/us', $str, $matches)) {
            $return = self::strlen($matches[1], $encoding);
            if ($return === false) {
                return 0;
            }

            return $return;
        }

        return (int) self::strlen($str, $encoding);
    }

    /**
     * Create a UTF-8 string from code points.
     *
     * INFO: opposite to UTF8::codepoints()
     *
     * EXAMPLE: <code>UTF8::string(array(246, 228, 252)); // 'öäü'</code>
     *
     * @param int|int[]|string|string[] $intOrHex <p>Integer or Hexadecimal codepoints.</p>
     *
     * @phpstan-param int[]|numeric-string[]|int|numeric-string $intOrHex
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A UTF-8 encoded string.</p>
     */
    public static function string($intOrHex): string
    {
        if ($intOrHex === []) {
            return '';
        }

        if (!\is_array($intOrHex)) {
            $intOrHex = [$intOrHex];
        }

        $str = '';
        foreach ($intOrHex as $strPart) {
            $str .= '&#' . (int) $strPart . ';';
        }

        // We cannot use html_entity_decode() here, as it will not return
        // characters for many values < 160.
        return mb_convert_encoding($str, 'UTF-8', 'HTML-ENTITIES');
    }

    /**
     * Checks if string starts with "BOM" (Byte Order Mark Character) character.
     *
     * EXAMPLE: <code>UTF8::string_has_bom("\xef\xbb\xbf foobar"); // true</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return bool
     *              <p>
     *              <strong>true</strong> if the string has BOM at the start,<br>
     *              <strong>false</strong> otherwise
     *              </p>
     */
    public static function string_has_bom(string $str): bool
    {
        foreach (self::$BOM as $bom_string => &$bom_byte_length) {
            if (\strncmp($str, $bom_string, $bom_byte_length) === 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * Strip HTML and PHP tags from a string + clean invalid UTF-8.
     *
     * EXAMPLE: <code>UTF8::strip_tags("<span>κόσμε\xa0\xa1</span>"); // 'κόσμε'</code>
     *
     * @see http://php.net/manual/en/function.strip-tags.php
     *
     * @param string      $str            <p>
     *                                    The input string.
     *                                    </p>
     * @param string|null $allowable_tags [optional] <p>
     *                                    You can use the optional second parameter to specify tags which should
     *                                    not be stripped.
     *                                    </p>
     *                                    <p>
     *                                    HTML comments and PHP tags are also stripped. This is hardcoded and
     *                                    can not be changed with allowable_tags.
     *                                    </p>
     * @param bool        $clean_utf8     [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The stripped string.</p>
     */
    public static function strip_tags(
        string $str,
        string $allowable_tags = null,
        bool $clean_utf8 = false
    ): string {
        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            $str = self::clean($str);
        }

        if ($allowable_tags === null) {
            return \strip_tags($str);
        }

        return \strip_tags($str, $allowable_tags);
    }

    /**
     * Strip all whitespace characters. This includes tabs and newline
     * characters, as well as multibyte whitespace such as the thin space
     * and ideographic space.
     *
     * EXAMPLE: <code>UTF8::strip_whitespace('   Ο     συγγραφέας  '); // 'Οσυγγραφέας'</code>
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function strip_whitespace(string $str): string
    {
        if ($str === '') {
            return '';
        }

        return (string) \preg_replace('/[[:space:]]+/u', '', $str);
    }

    /**
     * Find the position of the first occurrence of a substring in a string, case-insensitive.
     *
     * INFO: use UTF8::stripos_in_byte() for the byte-length
     *
     * EXAMPLE: <code>UTF8::stripos('aσσb', 'ΣΣ'); // 1</code> (σσ == ΣΣ)
     *
     * @see http://php.net/manual/en/function.mb-stripos.php
     *
     * @param string $haystack   <p>The string from which to get the position of the first occurrence of needle.</p>
     * @param string $needle     <p>The string to find in haystack.</p>
     * @param int    $offset     [optional] <p>The position in haystack to start searching.</p>
     * @param string $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   Return the <strong>(int)</strong> numeric position of the first occurrence of needle in the
     *                   haystack string,<br> or <strong>false</strong> if needle is not found
     *
     * @phpstan-return false|0|positive-int
     */
    public static function stripos(
        string $haystack,
        string $needle,
        int $offset = 0,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return 0;
            }

            return false;
        }

        if ($needle === '' && \PHP_VERSION_ID < 80000) {
            return false;
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $haystack = self::clean($haystack);
            $needle = self::clean($needle);
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_stripos($haystack, $needle, $offset);
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return \mb_stripos($haystack, $needle, $offset, $encoding);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_stripos()" can't handle other encodings
            &&
            $offset >= 0 // grapheme_stripos() can't handle negative offset
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_stripos($haystack, $needle, $offset);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($haystack . $needle)) {
            return \stripos($haystack, $needle, $offset);
        }

        //
        // fallback via vanilla php
        //

        $haystack = self::strtocasefold($haystack, true, false, $encoding, null, false);
        $needle = self::strtocasefold($needle, true, false, $encoding, null, false);

        return self::strpos($haystack, $needle, $offset, $encoding);
    }

    /**
     * Returns all of haystack starting from and including the first occurrence of needle to the end.
     *
     * EXAMPLE: <code>
     * $str = 'iñtërnâtiônàlizætiøn';
     * $search = 'NÂT';
     *
     * UTF8::stristr($str, $search)); // 'nâtiônàlizætiøn'
     * UTF8::stristr($str, $search, true)); // 'iñtër'
     * </code>
     *
     * @param string $haystack      <p>The input string. Must be valid UTF-8.</p>
     * @param string $needle        <p>The string to look for. Must be valid UTF-8.</p>
     * @param bool   $before_needle [optional] <p>
     *                              If <b>TRUE</b>, it returns the part of the
     *                              haystack before the first occurrence of the needle (excluding the needle).
     *                              </p>
     * @param string $encoding      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8    [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>A sub-string,<br>or <strong>false</strong> if needle is not found.</p>
     */
    public static function stristr(
        string $haystack,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return '';
            }

            return false;
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($needle === '') {
            if (\PHP_VERSION_ID >= 80000) {
                return $haystack;
            }

            return false;
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_stristr($haystack, $needle, $before_needle);
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return \mb_stristr($haystack, $needle, $before_needle, $encoding);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::stristr() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_stristr()" can't handle other encodings
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_stristr($haystack, $needle, $before_needle);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        if (ASCII::is_ascii($needle . $haystack)) {
            return \stristr($haystack, $needle, $before_needle);
        }

        \preg_match('/^(.*?)' . \preg_quote($needle, '/') . '/usi', $haystack, $match);

        if (!isset($match[1])) {
            return false;
        }

        if ($before_needle) {
            return $match[1];
        }

        return self::substr($haystack, (int) self::strlen($match[1], $encoding), null, $encoding);
    }

    /**
     * Get the string length, not the byte-length!
     *
     * INFO: use UTF8::strwidth() for the char-length
     *
     * EXAMPLE: <code>UTF8::strlen("Iñtërnâtiôn\xE9àlizætiøn")); // 20</code>
     *
     * @see http://php.net/manual/en/function.mb-strlen.php
     *
     * @param string $str        <p>The string being checked for length.</p>
     * @param string $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>
     *                   The number <strong>(int)</strong> of characters in the string $str having character encoding
     *                   $encoding.
     *                   (One multi-byte character counted as +1).
     *                   <br>
     *                   Can return <strong>false</strong>, if e.g. mbstring is not installed and we process invalid
     *                   chars.
     *                   </p>
     *
     * @phpstan-return false|0|positive-int
     */
    public static function strlen(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($str === '') {
            return 0;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($clean_utf8) {
            // "mb_strlen" and "\iconv_strlen" returns wrong length,
            // if invalid characters are found in $str
            $str = self::clean($str);
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                /** @noinspection PhpUsageOfSilenceOperatorInspection - ignore warnings, it's working anyway */
                return @\mb_strlen($str);
            }

            /** @noinspection PhpUsageOfSilenceOperatorInspection - ignore warnings, it's working anyway */
            return @\mb_strlen($str, $encoding);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            return \strlen($str);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
            &&
            self::$SUPPORT['iconv'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strlen() without mbstring / iconv cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via iconv
        //

        if (self::$SUPPORT['iconv'] === true) {
            $return_tmp = \iconv_strlen($str, $encoding);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback via intl
        //

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_strlen()" can't handle other encodings
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_strlen($str);
            /* @phpstan-ignore-next-line | "grapheme_strlen" will maybe return "null" for empty-strings and "false" on error */
            if ($return_tmp !== false && $return_tmp !== null) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($str)) {
            return \strlen($str);
        }

        //
        // fallback via vanilla php
        //

        \preg_match_all('/./us', $str, $parts);

        $return_tmp = \count($parts[0]);
        if ($return_tmp === 0) {
            return false;
        }

        return $return_tmp;
    }

    /**
     * Get string length in byte.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return int
     *
     * @phpstan-return 0|positive-int
     */
    public static function strlen_in_byte(string $str): int
    {
        if ($str === '') {
            return 0;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_strlen($str, 'CP850'); // 8-BIT
        }

        return \strlen($str);
    }

    /**
     * Case-insensitive string comparisons using a "natural order" algorithm.
     *
     * INFO: natural order version of UTF8::strcasecmp()
     *
     * EXAMPLES: <code>
     * UTF8::strnatcasecmp('2', '10Hello WORLD 中文空白!'); // -1
     * UTF8::strcasecmp('2Hello world 中文空白!', '10Hello WORLD 中文空白!'); // 1
     *
     * UTF8::strnatcasecmp('10Hello world 中文空白!', '2Hello WORLD 中文空白!'); // 1
     * UTF8::strcasecmp('10Hello world 中文空白!', '2Hello WORLD 中文空白!'); // -1
     * </code>
     *
     * @param string $str1     <p>The first string.</p>
     * @param string $str2     <p>The second string.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if str1 is less than str2<br>
     *             <strong>&gt; 0</strong> if str1 is greater than str2<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strnatcasecmp(string $str1, string $str2, string $encoding = 'UTF-8'): int
    {
        return self::strnatcmp(
            self::strtocasefold($str1, true, false, $encoding, null, false),
            self::strtocasefold($str2, true, false, $encoding, null, false)
        );
    }

    /**
     * String comparisons using a "natural order" algorithm
     *
     * INFO: natural order version of UTF8::strcmp()
     *
     * EXAMPLES: <code>
     * UTF8::strnatcmp('2Hello world 中文空白!', '10Hello WORLD 中文空白!'); // -1
     * UTF8::strcmp('2Hello world 中文空白!', '10Hello WORLD 中文空白!'); // 1
     *
     * UTF8::strnatcmp('10Hello world 中文空白!', '2Hello WORLD 中文空白!'); // 1
     * UTF8::strcmp('10Hello world 中文空白!', '2Hello WORLD 中文空白!'); // -1
     * </code>
     *
     * @see http://php.net/manual/en/function.strnatcmp.php
     *
     * @param string $str1 <p>The first string.</p>
     * @param string $str2 <p>The second string.</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if str1 is less than str2;<br>
     *             <strong>&gt; 0</strong> if str1 is greater than str2;<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strnatcmp(string $str1, string $str2): int
    {
        if ($str1 === $str2) {
            return 0;
        }

        return \strnatcmp(
            (string) self::strtonatfold($str1),
            (string) self::strtonatfold($str2)
        );
    }

    /**
     * Case-insensitive string comparison of the first n characters.
     *
     * EXAMPLE: <code>
     * UTF8::strcasecmp("iñtërnâtiôn\nàlizætiøn321", "iñtërnâtiôn\nàlizætiøn123", 5); // 0
     * </code>
     *
     * @see http://php.net/manual/en/function.strncasecmp.php
     *
     * @param string $str1     <p>The first string.</p>
     * @param string $str2     <p>The second string.</p>
     * @param int    $len      <p>The length of strings to be used in the comparison.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if <i>str1</i> is less than <i>str2</i>;<br>
     *             <strong>&gt; 0</strong> if <i>str1</i> is greater than <i>str2</i>;<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strncasecmp(
        string $str1,
        string $str2,
        int $len,
        string $encoding = 'UTF-8'
    ): int {
        return self::strncmp(
            self::strtocasefold($str1, true, false, $encoding, null, false),
            self::strtocasefold($str2, true, false, $encoding, null, false),
            $len
        );
    }

    /**
     * String comparison of the first n characters.
     *
     * EXAMPLE: <code>
     * UTF8::strncmp("Iñtërnâtiôn\nàlizætiøn321", "Iñtërnâtiôn\nàlizætiøn123", 5); // 0
     * </code>
     *
     * @see http://php.net/manual/en/function.strncmp.php
     *
     * @param string $str1     <p>The first string.</p>
     * @param string $str2     <p>The second string.</p>
     * @param int    $len      <p>Number of characters to use in the comparison.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if <i>str1</i> is less than <i>str2</i>;<br>
     *             <strong>&gt; 0</strong> if <i>str1</i> is greater than <i>str2</i>;<br>
     *             <strong>0</strong> if they are equal
     */
    public static function strncmp(
        string $str1,
        string $str2,
        int $len,
        string $encoding = 'UTF-8'
    ): int {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($encoding === 'UTF-8') {
            $str1 = (string) \mb_substr($str1, 0, $len);
            $str2 = (string) \mb_substr($str2, 0, $len);
        } else {
            $str1 = (string) self::substr($str1, 0, $len, $encoding);
            $str2 = (string) self::substr($str2, 0, $len, $encoding);
        }

        return self::strcmp($str1, $str2);
    }

    /**
     * Search a string for any of a set of characters.
     *
     * EXAMPLE: <code>UTF8::strpbrk('-中文空白-', '白'); // '白-'</code>
     *
     * @see http://php.net/manual/en/function.strpbrk.php
     *
     * @param string $haystack  <p>The string where char_list is looked for.</p>
     * @param string $char_list <p>This parameter is case-sensitive.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The string starting from the character found, or false if it is not found.</p>
     */
    public static function strpbrk(string $haystack, string $char_list)
    {
        if ($haystack === '' || $char_list === '') {
            return false;
        }

        if (\preg_match('/' . self::rxClass($char_list) . '/us', $haystack, $m)) {
            return \substr($haystack, (int) \strpos($haystack, $m[0]));
        }

        return false;
    }

    /**
     * Find the position of the first occurrence of a substring in a string.
     *
     * INFO: use UTF8::strpos_in_byte() for the byte-length
     *
     * EXAMPLE: <code>UTF8::strpos('ABC-ÖÄÜ-中文空白-中文空白', '中'); // 8</code>
     *
     * @see http://php.net/manual/en/function.mb-strpos.php
     *
     * @param string     $haystack   <p>The string from which to get the position of the first occurrence of needle.</p>
     * @param int|string $needle     <p>The string to find in haystack.<br>Or a code point as int.</p>
     * @param int        $offset     [optional] <p>The search offset. If it is not specified, 0 is used.</p>
     * @param string     $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool       $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   The <strong>(int)</strong> numeric position of the first occurrence of needle in the haystack
     *                   string.<br> If needle is not found it returns false.
     *
     * @phpstan-return false|0|positive-int
     */
    public static function strpos(
        string $haystack,
        $needle,
        int $offset = 0,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000) {
                if ($needle === '') {
                    return 0;
                }
            } else {
                return false;
            }
        }

        // iconv and mbstring do not support integer $needle
        if ((int) $needle === $needle) {
            $needle = (string) self::chr($needle);
        }
        $needle = (string) $needle;

        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return 0;
            }

            return false;
        }

        if ($needle === '' && \PHP_VERSION_ID < 80000) {
            return false;
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                /** @noinspection PhpUsageOfSilenceOperatorInspection - Offset not contained in string */
                return @\mb_strpos($haystack, $needle, $offset);
            }

            /** @noinspection PhpUsageOfSilenceOperatorInspection - Offset not contained in string */
            return @\mb_strpos($haystack, $needle, $offset, $encoding);
        }

        //
        // fallback for binary || ascii only
        //
        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            return \strpos($haystack, $needle, $offset);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['iconv'] === false
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strpos() without mbstring / iconv cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via intl
        //

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_strpos()" can't handle other encodings
            &&
            $offset >= 0 // grapheme_strpos() can't handle negative offset
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_strpos($haystack, $needle, $offset);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback via iconv
        //

        if (
            $offset >= 0 // iconv_strpos() can't handle negative offset
            &&
            self::$SUPPORT['iconv'] === true
        ) {
            // ignore invalid negative offset to keep compatibility
            // with php < 5.5.35, < 5.6.21, < 7.0.6
            $return_tmp = \iconv_strpos($haystack, $needle, $offset > 0 ? $offset : 0, $encoding);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($haystack . $needle)) {
            /** @noinspection PhpUsageOfSilenceOperatorInspection - Offset not contained in string */
            return @\strpos($haystack, $needle, $offset);
        }

        //
        // fallback via vanilla php
        //

        $haystack_tmp = self::substr($haystack, $offset, null, $encoding);
        if ($haystack_tmp === false) {
            $haystack_tmp = '';
        }
        $haystack = (string) $haystack_tmp;

        if ($offset < 0) {
            $offset = 0;
        }

        $pos = \strpos($haystack, $needle);
        if ($pos === false) {
            return false;
        }

        if ($pos) {
            return $offset + (int) self::strlen(\substr($haystack, 0, $pos), $encoding);
        }

        return $offset + 0;
    }

    /**
     * Find the position of the first occurrence of a substring in a string.
     *
     * @param string $haystack <p>
     *                         The string being checked.
     *                         </p>
     * @param string $needle   <p>
     *                         The position counted from the beginning of haystack.
     *                         </p>
     * @param int    $offset   [optional] <p>
     *                         The search offset. If it is not specified, 0 is used.
     *                         </p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The numeric position of the first occurrence of needle in the
     *                   haystack string. If needle is not found, it returns false.</p>
     *
     * @phpstan-return false|0|positive-int
     */
    public static function strpos_in_byte(string $haystack, string $needle, int $offset = 0)
    {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_strpos($haystack, $needle, $offset, 'CP850'); // 8-BIT
        }

        return \strpos($haystack, $needle, $offset);
    }

    /**
     * Find the position of the first occurrence of a substring in a string, case-insensitive.
     *
     * @param string $haystack <p>
     *                         The string being checked.
     *                         </p>
     * @param string $needle   <p>
     *                         The position counted from the beginning of haystack.
     *                         </p>
     * @param int    $offset   [optional] <p>
     *                         The search offset. If it is not specified, 0 is used.
     *                         </p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The numeric position of the first occurrence of needle in the
     *                   haystack string. If needle is not found, it returns false.</p>
     *
     * @phpstan-return false|0|positive-int
     */
    public static function stripos_in_byte(string $haystack, string $needle, int $offset = 0)
    {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_stripos($haystack, $needle, $offset, 'CP850'); // 8-BIT
        }

        return \stripos($haystack, $needle, $offset);
    }

    /**
     * Find the last occurrence of a character in a string within another.
     *
     * EXAMPLE: <code>UTF8::strrchr('κόσμεκόσμε-äöü', 'κόσμε'); // 'κόσμε-äöü'</code>
     *
     * @see http://php.net/manual/en/function.mb-strrchr.php
     *
     * @param string $haystack      <p>The string from which to get the last occurrence of needle.</p>
     * @param string $needle        <p>The string to find in haystack</p>
     * @param bool   $before_needle [optional] <p>
     *                              Determines which portion of haystack
     *                              this function returns.
     *                              If set to true, it returns all of haystack
     *                              from the beginning to the last occurrence of needle.
     *                              If set to false, it returns all of haystack
     *                              from the last occurrence of needle to the end,
     *                              </p>
     * @param string $encoding      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8    [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The portion of haystack or false if needle is not found.</p>
     */
    public static function strrchr(
        string $haystack,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strrchr($haystack, $needle, $before_needle);
            }

            return \mb_strrchr($haystack, $needle, $before_needle, $encoding);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            !$before_needle
            &&
            (
                $encoding === 'CP850'
                ||
                $encoding === 'ASCII'
            )
        ) {
            return \strrchr($haystack, $needle);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strrchr() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via iconv
        //

        if (self::$SUPPORT['iconv'] === true) {
            $needle_tmp = self::substr($needle, 0, 1, $encoding);
            if ($needle_tmp === false) {
                return false;
            }
            $needle = $needle_tmp;

            $pos = \iconv_strrpos($haystack, $needle, $encoding);
            if ($pos === false) {
                return false;
            }

            if ($before_needle) {
                return self::substr($haystack, 0, $pos, $encoding);
            }

            return self::substr($haystack, $pos, null, $encoding);
        }

        //
        // fallback via vanilla php
        //

        $needle_tmp = self::substr($needle, 0, 1, $encoding);
        if ($needle_tmp === false) {
            return false;
        }
        $needle = $needle_tmp;

        $pos = self::strrpos($haystack, $needle, 0, $encoding);
        if ($pos === false) {
            return false;
        }

        if ($before_needle) {
            return self::substr($haystack, 0, $pos, $encoding);
        }

        return self::substr($haystack, $pos, null, $encoding);
    }

    /**
     * Reverses characters order in the string.
     *
     * EXAMPLE: <code>UTF8::strrev('κ-öäü'); // 'üäö-κ'</code>
     *
     * @param string $str      <p>The input string.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The string with characters in the reverse sequence.</p>
     */
    public static function strrev(string $str, string $encoding = 'UTF-8'): string
    {
        if ($str === '') {
            return '';
        }

        // init
        $reversed = '';

        $str = self::emoji_encode($str, true);

        if ($encoding === 'UTF-8') {
            if (self::$SUPPORT['intl'] === true) {
                // try "grapheme" first: https://stackoverflow.com/questions/17496493/strrev-dosent-support-utf-8
                $i = (int) \grapheme_strlen($str);
                while ($i--) {
                    $reversed_tmp = \grapheme_substr($str, $i, 1);
                    if ($reversed_tmp !== false) {
                        $reversed .= $reversed_tmp;
                    }
                }
            } else {
                $i = (int) \mb_strlen($str);
                while ($i--) {
                    $reversed_tmp = \mb_substr($str, $i, 1);
                    if ($reversed_tmp !== false) { /* @phpstan-ignore-line | old polyfill will return false, or? */
                        $reversed .= $reversed_tmp;
                    }
                }
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $i = (int) self::strlen($str, $encoding);
            while ($i--) {
                $reversed_tmp = self::substr($str, $i, 1, $encoding);
                if ($reversed_tmp !== false) {
                    $reversed .= $reversed_tmp;
                }
            }
        }

        return self::emoji_decode($reversed, true);
    }

    /**
     * Find the last occurrence of a character in a string within another, case-insensitive.
     *
     * EXAMPLE: <code>UTF8::strrichr('Aκόσμεκόσμε-äöü', 'aκόσμε'); // 'Aκόσμεκόσμε-äöü'</code>
     *
     * @see http://php.net/manual/en/function.mb-strrichr.php
     *
     * @param string $haystack      <p>The string from which to get the last occurrence of needle.</p>
     * @param string $needle        <p>The string to find in haystack.</p>
     * @param bool   $before_needle [optional] <p>
     *                              Determines which portion of haystack
     *                              this function returns.
     *                              If set to true, it returns all of haystack
     *                              from the beginning to the last occurrence of needle.
     *                              If set to false, it returns all of haystack
     *                              from the last occurrence of needle to the end,
     *                              </p>
     * @param string $encoding      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8    [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The portion of haystack or<br>false if needle is not found.</p>
     */
    public static function strrichr(
        string $haystack,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strrichr($haystack, $needle, $before_needle);
            }

            return \mb_strrichr($haystack, $needle, $before_needle, $encoding);
        }

        //
        // fallback via vanilla php
        //

        $needle_tmp = self::substr($needle, 0, 1, $encoding);
        if ($needle_tmp === false) {
            return false;
        }
        $needle = $needle_tmp;

        $pos = self::strripos($haystack, $needle, 0, $encoding);
        if ($pos === false) {
            return false;
        }

        if ($before_needle) {
            return self::substr($haystack, 0, $pos, $encoding);
        }

        return self::substr($haystack, $pos, null, $encoding);
    }

    /**
     * Find the position of the last occurrence of a substring in a string, case-insensitive.
     *
     * EXAMPLE: <code>UTF8::strripos('ABC-ÖÄÜ-中文空白-中文空白', '中'); // 13</code>
     *
     * @param string     $haystack   <p>The string to look in.</p>
     * @param int|string $needle     <p>The string to look for.</p>
     * @param int        $offset     [optional] <p>Number of characters to ignore in the beginning or end.</p>
     * @param string     $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool       $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The <strong>(int)</strong> numeric position of the last occurrence of needle in the haystack
     *                   string.<br>If needle is not found, it returns false.</p>
     */
    public static function strripos(
        string $haystack,
        $needle,
        int $offset = 0,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000) {
                if ($needle === '') {
                    return 0;
                }
            } else {
                return false;
            }
        }

        // iconv and mbstring do not support integer $needle
        if ((int) $needle === $needle && $needle >= 0) {
            $needle = (string) self::chr($needle);
        }
        $needle = (string) $needle;

        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return 0;
            }

            return false;
        }

        if ($needle === '' && \PHP_VERSION_ID < 80000) {
            return false;
        }

        if ($clean_utf8) {
            // mb_strripos() && iconv_strripos() is not tolerant to invalid characters
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        //
        // fallback via mbstrig
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strripos($haystack, $needle, $offset);
            }

            return \mb_strripos($haystack, $needle, $offset, $encoding);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            return \strripos($haystack, $needle, $offset);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strripos() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via intl
        //

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_strripos()" can't handle other encodings
            &&
            $offset >= 0 // grapheme_strripos() can't handle negative offset
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_strripos($haystack, $needle, $offset);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($haystack . $needle)) {
            return \strripos($haystack, $needle, $offset);
        }

        //
        // fallback via vanilla php
        //

        $haystack = self::strtocasefold($haystack, true, false, $encoding);
        $needle = self::strtocasefold($needle, true, false, $encoding);

        return self::strrpos($haystack, $needle, $offset, $encoding, $clean_utf8);
    }

    /**
     * Finds position of last occurrence of a string within another, case-insensitive.
     *
     * @param string $haystack <p>
     *                         The string from which to get the position of the last occurrence
     *                         of needle.
     *                         </p>
     * @param string $needle   <p>
     *                         The string to find in haystack.
     *                         </p>
     * @param int    $offset   [optional] <p>
     *                         The position in haystack
     *                         to start searching.
     *                         </p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>eturn the numeric position of the last occurrence of needle in the
     *                   haystack string, or false if needle is not found.</p>
     */
    public static function strripos_in_byte(string $haystack, string $needle, int $offset = 0)
    {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_strripos($haystack, $needle, $offset, 'CP850'); // 8-BIT
        }

        return \strripos($haystack, $needle, $offset);
    }

    /**
     * Find the position of the last occurrence of a substring in a string.
     *
     * EXAMPLE: <code>UTF8::strrpos('ABC-ÖÄÜ-中文空白-中文空白', '中'); // 13</code>
     *
     * @see http://php.net/manual/en/function.mb-strrpos.php
     *
     * @param string     $haystack   <p>The string being checked, for the last occurrence of needle</p>
     * @param int|string $needle     <p>The string to find in haystack.<br>Or a code point as int.</p>
     * @param int        $offset     [optional] <p>May be specified to begin searching an arbitrary number of characters
     *                               into the string. Negative values will stop searching at an arbitrary point prior to
     *                               the end of the string.
     *                               </p>
     * @param string     $encoding   [optional] <p>Set the charset.</p>
     * @param bool       $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The <strong>(int)</strong> numeric position of the last occurrence of needle in the haystack
     *                   string.<br>If needle is not found, it returns false.</p>
     */
    public static function strrpos(
        string $haystack,
        $needle,
        int $offset = 0,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000) {
                if ($needle === '') {
                    return 0;
                }
            } else {
                return false;
            }
        }

        // iconv and mbstring do not support integer $needle
        if ((int) $needle === $needle && $needle >= 0) {
            $needle = (string) self::chr($needle);
        }
        $needle = (string) $needle;

        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return 0;
            }

            return false;
        }

        if ($needle === '' && \PHP_VERSION_ID < 80000) {
            return false;
        }

        if ($clean_utf8) {
            // mb_strrpos && iconv_strrpos is not tolerant to invalid characters
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strrpos($haystack, $needle, $offset);
            }

            return \mb_strrpos($haystack, $needle, $offset, $encoding);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            return \strrpos($haystack, $needle, $offset);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strrpos() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via intl
        //

        if (
            $offset >= 0 // grapheme_strrpos() can't handle negative offset
            &&
            $encoding === 'UTF-8' // INFO: "grapheme_strrpos()" can't handle other encodings
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_strrpos($haystack, $needle, $offset);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($haystack . $needle)) {
            return \strrpos($haystack, $needle, $offset);
        }

        //
        // fallback via vanilla php
        //

        $haystack_tmp = null;
        if ($offset > 0) {
            $haystack_tmp = self::substr($haystack, $offset);
        } elseif ($offset < 0) {
            $haystack_tmp = self::substr($haystack, 0, $offset);
            $offset = 0;
        }

        if ($haystack_tmp !== null) {
            if ($haystack_tmp === false) {
                $haystack_tmp = '';
            }
            $haystack = (string) $haystack_tmp;
        }

        $pos = \strrpos($haystack, $needle);
        if ($pos === false) {
            return false;
        }

        /** @var false|string $str_tmp - needed for PhpStan (stubs error) */
        $str_tmp = \substr($haystack, 0, $pos);
        if ($str_tmp === false) {
            return false;
        }

        return $offset + (int) self::strlen($str_tmp);
    }

    /**
     * Find the position of the last occurrence of a substring in a string.
     *
     * @param string $haystack <p>
     *                         The string being checked, for the last occurrence
     *                         of needle.
     *                         </p>
     * @param string $needle   <p>
     *                         The string to find in haystack.
     *                         </p>
     * @param int    $offset   [optional] <p>May be specified to begin searching an arbitrary number of characters into
     *                         the string. Negative values will stop searching at an arbitrary point
     *                         prior to the end of the string.
     *                         </p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The numeric position of the last occurrence of needle in the
     *                   haystack string. If needle is not found, it returns false.</p>
     */
    public static function strrpos_in_byte(string $haystack, string $needle, int $offset = 0)
    {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_strrpos($haystack, $needle, $offset, 'CP850'); // 8-BIT
        }

        return \strrpos($haystack, $needle, $offset);
    }

    /**
     * Finds the length of the initial segment of a string consisting entirely of characters contained within a given
     * mask.
     *
     * EXAMPLE: <code>UTF8::strspn('iñtërnâtiônàlizætiøn', 'itñ'); // '3'</code>
     *
     * @param string   $str      <p>The input string.</p>
     * @param string   $mask     <p>The mask of chars</p>
     * @param int      $offset   [optional]
     * @param int|null $length   [optional]
     * @param string   $encoding [optional] <p>Set the charset.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     */
    public static function strspn(
        string $str,
        string $mask,
        int $offset = 0,
        int $length = null,
        string $encoding = 'UTF-8'
    ) {
        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($offset || $length !== null) {
            if ($encoding === 'UTF-8') {
                if ($length === null) {
                    $str = (string) \mb_substr($str, $offset);
                } else {
                    $str = (string) \mb_substr($str, $offset, $length);
                }
            } else {
                $str = (string) self::substr($str, $offset, $length, $encoding);
            }
        }

        if ($str === '' || $mask === '') {
            return 0;
        }

        $matches = [];

        return \preg_match('/^' . self::rxClass($mask) . '+/u', $str, $matches) ? (int) self::strlen($matches[0], $encoding) : 0;
    }

    /**
     * Returns part of haystack string from the first occurrence of needle to the end of haystack.
     *
     * EXAMPLE: <code>
     * $str = 'iñtërnâtiônàlizætiøn';
     * $search = 'nât';
     *
     * UTF8::strstr($str, $search)); // 'nâtiônàlizætiøn'
     * UTF8::strstr($str, $search, true)); // 'iñtër'
     * </code>
     *
     * @param string $haystack      <p>The input string. Must be valid UTF-8.</p>
     * @param string $needle        <p>The string to look for. Must be valid UTF-8.</p>
     * @param bool   $before_needle [optional] <p>
     *                              If <b>TRUE</b>, strstr() returns the part of the
     *                              haystack before the first occurrence of the needle (excluding the needle).
     *                              </p>
     * @param string $encoding      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8    [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>A sub-string,<br>or <strong>false</strong> if needle is not found.</p>
     */
    public static function strstr(
        string $haystack,
        string $needle,
        bool $before_needle = false,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($haystack === '') {
            if (\PHP_VERSION_ID >= 80000 && $needle === '') {
                return '';
            }

            return false;
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($needle === '') {
            if (\PHP_VERSION_ID >= 80000) {
                return $haystack;
            }

            return false;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strstr($haystack, $needle, $before_needle);
            }

            return \mb_strstr($haystack, $needle, $before_needle, $encoding);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            return \strstr($haystack, $needle, $before_needle);
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strstr() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via intl
        //

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_strstr()" can't handle other encodings
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_strstr($haystack, $needle, $before_needle);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($haystack . $needle)) {
            return \strstr($haystack, $needle, $before_needle);
        }

        //
        // fallback via vanilla php
        //

        \preg_match('/^(.*?)' . \preg_quote($needle, '/') . '/us', $haystack, $match);

        if (!isset($match[1])) {
            return false;
        }

        if ($before_needle) {
            return $match[1];
        }

        return self::substr($haystack, (int) self::strlen($match[1]));
    }

    /**
     * Finds first occurrence of a string within another.
     *
     * @param string $haystack      <p>
     *                              The string from which to get the first occurrence
     *                              of needle.
     *                              </p>
     * @param string $needle        <p>
     *                              The string to find in haystack.
     *                              </p>
     * @param bool   $before_needle [optional] <p>
     *                              Determines which portion of haystack
     *                              this function returns.
     *                              If set to true, it returns all of haystack
     *                              from the beginning to the first occurrence of needle.
     *                              If set to false, it returns all of haystack
     *                              from the first occurrence of needle to the end,
     *                              </p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The portion of haystack,
     *                      or false if needle is not found.</p>
     */
    public static function strstr_in_byte(
        string $haystack,
        string $needle,
        bool $before_needle = false
    ) {
        if ($haystack === '' || $needle === '') {
            return false;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_strstr($haystack, $needle, $before_needle, 'CP850'); // 8-BIT
        }

        return \strstr($haystack, $needle, $before_needle);
    }

    /**
     * Unicode transformation for case-less matching.
     *
     * EXAMPLE: <code>UTF8::strtocasefold('ǰ◌̱'); // 'ǰ◌̱'</code>
     *
     * @see http://unicode.org/reports/tr21/tr21-5.html
     *
     * @param string      $str        <p>The input string.</p>
     * @param bool        $full       [optional] <p>
     *                                <b>true</b>, replace full case folding chars (default)<br>
     *                                <b>false</b>, use only limited static array [UTF8::$COMMON_CASE_FOLD]
     *                                </p>
     * @param bool        $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string      $encoding   [optional] <p>Set the charset.</p>
     * @param string|null $lang       [optional] <p>Set the language for special cases: az, el, lt, tr</p>
     * @param bool        $lower      [optional] <p>Use lowercase string, otherwise use uppercase string. PS: uppercase
     *                                is for some languages better ...</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function strtocasefold(
        string $str,
        bool $full = true,
        bool $clean_utf8 = false,
        string $encoding = 'UTF-8',
        string $lang = null,
        bool $lower = true
    ): string {
        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        $str = self::fixStrCaseHelper($str, $lower, $full);

        if ($lang === null && $encoding === 'UTF-8') {
            if ($lower) {
                return \mb_strtolower($str);
            }

            return \mb_strtoupper($str);
        }

        if ($lower) {
            return self::strtolower($str, $encoding, false, $lang);
        }

        return self::strtoupper($str, $encoding, false, $lang);
    }

    /**
     * Make a string lowercase.
     *
     * EXAMPLE: <code>UTF8::strtolower('DÉJÀ Σσς Iıİi'); // 'déjà σσς iıii'</code>
     *
     * @see http://php.net/manual/en/function.mb-strtolower.php
     *
     * @param string      $str                           <p>The string being lowercased.</p>
     * @param string      $encoding                      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>String with all alphabetic characters converted to lowercase.</p>
     */
    public static function strtolower(
        $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        // init
        $str = (string) $str;

        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        // hack for old php version or for the polyfill ...
        if ($try_to_keep_the_string_length) {
            $str = self::fixStrCaseHelper($str, true);
        }

        if ($lang === null && $encoding === 'UTF-8') {
            return \mb_strtolower($str);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ($lang !== null) {
            if (self::$SUPPORT['intl'] === true) {
                if (self::$INTL_TRANSLITERATOR_LIST === null) {
                    self::$INTL_TRANSLITERATOR_LIST = self::getData('transliterator_list');
                }

                $language_code = $lang . '-Lower';
                if (!\in_array($language_code, self::$INTL_TRANSLITERATOR_LIST, true)) {
                    /**
                     * @psalm-suppress ImpureFunctionCall - this is only a warning
                     */
                    \trigger_error('UTF8::strtolower() cannot handle special language: ' . $lang . ' | supported: ' . \print_r(self::$INTL_TRANSLITERATOR_LIST, true), \E_USER_WARNING);

                    $language_code = 'Any-Lower';
                }

                return (string) \transliterator_transliterate($language_code, $str);
            }

            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strtolower() without intl cannot handle the "lang" parameter: ' . $lang, \E_USER_WARNING);
        }

        // always fallback via symfony polyfill
        return \mb_strtolower($str, $encoding);
    }

    /**
     * Make a string uppercase.
     *
     * EXAMPLE: <code>UTF8::strtoupper('Déjà Σσς Iıİi'); // 'DÉJÀ ΣΣΣ IIİI'</code>
     *
     * @see http://php.net/manual/en/function.mb-strtoupper.php
     *
     * @param string      $str                           <p>The string being uppercased.</p>
     * @param string      $encoding                      [optional] <p>Set the charset.</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>String with all alphabetic characters converted to uppercase.</p>
     */
    public static function strtoupper(
        $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        // init
        $str = (string) $str;

        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        // hack for old php version or for the polyfill ...
        if ($try_to_keep_the_string_length) {
            $str = self::fixStrCaseHelper($str);
        }

        if ($lang === null && $encoding === 'UTF-8') {
            return \mb_strtoupper($str);
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ($lang !== null) {
            if (self::$SUPPORT['intl'] === true) {
                if (self::$INTL_TRANSLITERATOR_LIST === null) {
                    self::$INTL_TRANSLITERATOR_LIST = self::getData('transliterator_list');
                }

                $language_code = $lang . '-Upper';
                if (!\in_array($language_code, self::$INTL_TRANSLITERATOR_LIST, true)) {
                    /**
                     * @psalm-suppress ImpureFunctionCall - this is only a warning
                     */
                    \trigger_error('UTF8::strtoupper() without intl for special language: ' . $lang, \E_USER_WARNING);

                    $language_code = 'Any-Upper';
                }

                return (string) \transliterator_transliterate($language_code, $str);
            }

            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::strtolower() without intl cannot handle the "lang"-parameter: ' . $lang, \E_USER_WARNING);
        }

        // always fallback via symfony polyfill
        return \mb_strtoupper($str, $encoding);
    }

    /**
     * Translate characters or replace sub-strings.
     *
     * EXAMPLE:
     * <code>
     * $array = [
     *     'Hello'   => '○●◎',
     *     '中文空白' => 'earth',
     * ];
     * UTF8::strtr('Hello 中文空白', $array); // '○●◎ earth'
     * </code>
     *
     * @see http://php.net/manual/en/function.strtr.php
     *
     * @param string          $str  <p>The string being translated.</p>
     * @param string|string[] $from <p>The string replacing from.</p>
     * @param string|string[] $to   [optional] <p>The string being translated to to.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>This function returns a copy of str, translating all occurrences of each character in "from"
     *                to the corresponding character in "to".</p>
     */
    public static function strtr(string $str, $from, $to = ''): string
    {
        if ($str === '') {
            return '';
        }

        if ($from === $to) {
            return $str;
        }

        if ($to !== '') {
            if (!\is_array($from)) {
                $from = self::str_split($from);
            }

            if (!\is_array($to)) {
                $to = self::str_split($to);
            }

            $count_from = \count($from);
            $count_to = \count($to);

            if ($count_from !== $count_to) {
                if ($count_from > $count_to) {
                    $from = \array_slice($from, 0, $count_to);
                } elseif ($count_from < $count_to) {
                    $to = \array_slice($to, 0, $count_from);
                }
            }

            try {
                $from = \array_combine($from, $to);
            } catch (\Error $e) {
                // PHP >= 8.0 : array_combine() will now throw a ValueError if the number of elements for each array is not equal; previously this function returned false instead.
                $from = false;
            }
            if ($from === false) {
                throw new \InvalidArgumentException('The number of elements for each array isn\'t equal or the arrays are empty: (from: ' . \print_r($from, true) . ' | to: ' . \print_r($to, true) . ')');
            }
        }

        if (\is_string($from)) {
            return \str_replace($from, $to, $str);
        }

        return \strtr($str, $from);
    }

    /**
     * Return the width of a string.
     *
     * INFO: use UTF8::strlen() for the byte-length
     *
     * EXAMPLE: <code>UTF8::strwidth("Iñtërnâtiôn\xE9àlizætiøn")); // 21</code>
     *
     * @param string $str        <p>The input string.</p>
     * @param string $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return int
     *
     * @phpstan-return 0|positive-int
     */
    public static function strwidth(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ): int {
        if ($str === '') {
            return 0;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($clean_utf8) {
            // iconv and mbstring are not tolerant to invalid encoding
            // further, their behaviour is inconsistent with that of PHP's substr
            $str = self::clean($str);
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_strwidth($str);
            }

            return \mb_strwidth($str, $encoding);
        }

        //
        // fallback via vanilla php
        //

        if ($encoding !== 'UTF-8') {
            $str = self::encode('UTF-8', $str, false, $encoding);
        }

        $wide = 0;
        $str = (string) \preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $str, -1, $wide);

        /* @phpstan-ignore-next-line | should return 0|positive-int */
        return ($wide << 1) + (int) self::strlen($str);
    }

    /**
     * Get part of a string.
     *
     * EXAMPLE: <code>UTF8::substr('中文空白', 1, 2); // '文空'</code>
     *
     * @see http://php.net/manual/en/function.mb-substr.php
     *
     * @param string   $str        <p>The string being checked.</p>
     * @param int      $offset     <p>The first position used in str.</p>
     * @param int|null $length     [optional] <p>The maximum length of the returned string.</p>
     * @param string   $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool     $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      The portion of <i>str</i> specified by the <i>offset</i> and
     *                      <i>length</i> parameters.</p><p>If <i>str</i> is shorter than <i>offset</i>
     *                      characters long, <b>FALSE</b> will be returned.
     */
    public static function substr(
        string $str,
        int $offset = 0,
        int $length = null,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        // empty string
        if ($str === '' || $length === 0) {
            return '';
        }

        if ($clean_utf8) {
            // iconv and mbstring are not tolerant to invalid encoding
            // further, their behaviour is inconsistent with that of PHP's substr
            $str = self::clean($str);
        }

        // whole string
        if (!$offset && $length === null) {
            return $str;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        //
        // fallback via mbstring
        //

        if (self::$SUPPORT['mbstring'] === true && $encoding === 'UTF-8') {
            if ($length === null) {
                return \mb_substr($str, $offset);
            }

            return \mb_substr($str, $offset, $length);
        }

        //
        // fallback for binary || ascii only
        //

        if (
            $encoding === 'CP850'
            ||
            $encoding === 'ASCII'
        ) {
            if ($length === null) {
                return \substr($str, $offset);
            }

            return \substr($str, $offset, $length);
        }

        // otherwise we need the string-length
        $str_length = 0;
        if (
            $offset
            ||
            $length === null /* @phpstan-ignore-line | can be NULL here?! */
        ) {
            $str_length = self::strlen($str, $encoding);
        }

        // e.g.: invalid chars + mbstring not installed
        if ($str_length === false) {
            return false;
        }

        // empty string
        if ($offset === $str_length && !$length) {
            return '';
        }

        // impossible
        if ($offset && $offset > $str_length) {
            return '';
        }

        $length = $length ?? $str_length;

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::substr() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        //
        // fallback via intl
        //

        if (
            $encoding === 'UTF-8' // INFO: "grapheme_substr()" can't handle other encodings
            &&
            $offset >= 0 // grapheme_substr() can't handle negative offset
            &&
            self::$SUPPORT['intl'] === true
        ) {
            $return_tmp = \grapheme_substr($str, $offset, $length);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback via iconv
        //

        if (
            $length >= 0 // "iconv_substr()" can't handle negative length
            &&
            self::$SUPPORT['iconv'] === true
        ) {
            $return_tmp = \iconv_substr($str, $offset, $length);
            if ($return_tmp !== false) {
                return $return_tmp;
            }
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($str)) {
            return \substr($str, $offset, $length);
        }

        //
        // fallback via vanilla php
        //

        // split to array, and remove invalid characters
        // &&
        // extract relevant part, and join to make sting again
        return \implode('', \array_slice(self::str_split($str), $offset, $length));
    }

    /**
     * Binary-safe comparison of two strings from an offset, up to a length of characters.
     *
     * EXAMPLE: <code>
     * UTF8::substr_compare("○●◎\r", '●◎', 0, 2); // -1
     * UTF8::substr_compare("○●◎\r", '◎●', 1, 2); // 1
     * UTF8::substr_compare("○●◎\r", '●◎', 1, 2); // 0
     * </code>
     *
     * @param string   $str1               <p>The main string being compared.</p>
     * @param string   $str2               <p>The secondary string being compared.</p>
     * @param int      $offset             [optional] <p>The start position for the comparison. If negative, it starts
     *                                     counting from the end of the string.</p>
     * @param int|null $length             [optional] <p>The length of the comparison. The default value is the largest
     *                                     of the length of the str compared to the length of main_str less the
     *                                     offset.</p>
     * @param bool     $case_insensitivity [optional] <p>If case_insensitivity is TRUE, comparison is case
     *                                     insensitive.</p>
     * @param string   $encoding           [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *             <strong>&lt; 0</strong> if str1 is less than str2;<br>
     *             <strong>&gt; 0</strong> if str1 is greater than str2,<br>
     *             <strong>0</strong> if they are equal
     */
    public static function substr_compare(
        string $str1,
        string $str2,
        int $offset = 0,
        int $length = null,
        bool $case_insensitivity = false,
        string $encoding = 'UTF-8'
    ): int {
        if (
            $offset !== 0
            ||
            $length !== null
        ) {
            if ($encoding === 'UTF-8') {
                if ($length === null) {
                    $str1 = (string) \mb_substr($str1, $offset);
                } else {
                    $str1 = (string) \mb_substr($str1, $offset, $length);
                }
                $str2 = (string) \mb_substr($str2, 0, (int) self::strlen($str1));
            } else {
                $encoding = self::normalize_encoding($encoding, 'UTF-8');

                $str1 = (string) self::substr($str1, $offset, $length, $encoding);
                $str2 = (string) self::substr($str2, 0, (int) self::strlen($str1), $encoding);
            }
        }

        if ($case_insensitivity) {
            return self::strcasecmp($str1, $str2, $encoding);
        }

        return self::strcmp($str1, $str2);
    }

    /**
     * Count the number of substring occurrences.
     *
     * EXAMPLE: <code>UTF8::substr_count('中文空白', '文空', 1, 2); // 1</code>
     *
     * @see http://php.net/manual/en/function.substr-count.php
     *
     * @param string   $haystack   <p>The string to search in.</p>
     * @param string   $needle     <p>The substring to search for.</p>
     * @param int      $offset     [optional] <p>The offset where to start counting.</p>
     * @param int|null $length     [optional] <p>
     *                             The maximum length after the specified offset to search for the
     *                             substring. It outputs a warning if the offset plus the length is
     *                             greater than the haystack length.
     *                             </p>
     * @param string   $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool     $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>This functions returns an integer or false if there isn't a string.</p>
     */
    public static function substr_count(
        string $haystack,
        string $needle,
        int $offset = 0,
        int $length = null,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ) {
        if ($needle === '') {
            return false;
        }

        if ($haystack === '' || $length === 0) {
            return 0;
        }

        if ($encoding !== 'UTF-8' && $encoding !== 'CP850') {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $needle = self::clean($needle);
            $haystack = self::clean($haystack);
        }

        if ($offset || $length > 0) {
            if ($length === null) {
                $length_tmp = self::strlen($haystack, $encoding);
                if ($length_tmp === false) {
                    return false;
                }
                $length = $length_tmp;
            }

            if ($encoding === 'UTF-8') {
                $haystack = (string) \mb_substr($haystack, $offset, $length);
            } else {
                $haystack = (string) \mb_substr($haystack, $offset, $length, $encoding);
            }
        }

        if (
            $encoding !== 'UTF-8'
            &&
            self::$SUPPORT['mbstring'] === false
        ) {
            /**
             * @psalm-suppress ImpureFunctionCall - this is only a warning
             */
            \trigger_error('UTF8::substr_count() without mbstring cannot handle "' . $encoding . '" encoding', \E_USER_WARNING);
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($encoding === 'UTF-8') {
                return \mb_substr_count($haystack, $needle);
            }

            return \mb_substr_count($haystack, $needle, $encoding);
        }

        \preg_match_all('/' . \preg_quote($needle, '/') . '/us', $haystack, $matches, \PREG_SET_ORDER);

        return \count($matches);
    }

    /**
     * Count the number of substring occurrences.
     *
     * @param string   $haystack <p>
     *                           The string being checked.
     *                           </p>
     * @param string   $needle   <p>
     *                           The string being found.
     *                           </p>
     * @param int      $offset   [optional] <p>
     *                           The offset where to start counting
     *                           </p>
     * @param int|null $length   [optional] <p>
     *                           The maximum length after the specified offset to search for the
     *                           substring. It outputs a warning if the offset plus the length is
     *                           greater than the haystack length.
     *                           </p>
     *
     * @psalm-pure
     *
     * @return false|int
     *                   <p>The number of times the
     *                   needle substring occurs in the
     *                   haystack string.</p>
     */
    public static function substr_count_in_byte(
        string $haystack,
        string $needle,
        int $offset = 0,
        int $length = null
    ) {
        if ($haystack === '' || $needle === '') {
            return 0;
        }

        if (
            ($offset || $length !== null)
            &&
            self::$SUPPORT['mbstring_func_overload'] === true
        ) {
            if ($length === null) {
                $length_tmp = self::strlen($haystack);
                if ($length_tmp === false) {
                    return false;
                }
                $length = $length_tmp;
            }

            if (
                (
                    $length !== 0
                    &&
                    $offset !== 0
                )
                &&
                ($length + $offset) <= 0
                &&
                \PHP_VERSION_ID < 71000 // output from "substr_count()" have changed in PHP 7.1
            ) {
                return false;
            }

            /** @var false|string $haystack_tmp - needed for PhpStan (stubs error) */
            $haystack_tmp = \substr($haystack, $offset, $length);
            if ($haystack_tmp === false) {
                $haystack_tmp = '';
            }
            $haystack = (string) $haystack_tmp;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_substr_count($haystack, $needle, 'CP850'); // 8-BIT
        }

        if ($length === null) {
            return \substr_count($haystack, $needle, $offset);
        }

        return \substr_count($haystack, $needle, $offset, $length);
    }

    /**
     * Returns the number of occurrences of $substring in the given string.
     * By default, the comparison is case-sensitive, but can be made insensitive
     * by setting $case_sensitive to false.
     *
     * @param string $str            <p>The input string.</p>
     * @param string $substring      <p>The substring to search for.</p>
     * @param bool   $case_sensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
     * @param string $encoding       [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return int
     *
     * @phpstan-return 0|positive-int
     */
    public static function substr_count_simple(
        string $str,
        string $substring,
        bool $case_sensitive = true,
        string $encoding = 'UTF-8'
    ): int {
        if ($str === '' || $substring === '') {
            return 0;
        }

        if ($encoding === 'UTF-8') {
            if ($case_sensitive) {
                return (int) \mb_substr_count($str, $substring);
            }

            return (int) \mb_substr_count(
                \mb_strtoupper($str),
                \mb_strtoupper($substring)
            );
        }

        $encoding = self::normalize_encoding($encoding, 'UTF-8');

        if ($case_sensitive) {
            return (int) \mb_substr_count($str, $substring, $encoding);
        }

        return (int) \mb_substr_count(
            self::strtocasefold($str, true, false, $encoding, null, false),
            self::strtocasefold($substring, true, false, $encoding, null, false),
            $encoding
        );
    }

    /**
     * Removes a prefix ($needle) from the beginning of the string ($haystack), case-insensitive.
     *
     * EXMAPLE: <code>
     * UTF8::substr_ileft('ΚόσμεMiddleEnd', 'Κόσμε'); // 'MiddleEnd'
     * UTF8::substr_ileft('ΚόσμεMiddleEnd', 'κόσμε'); // 'MiddleEnd'
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Return the sub-string.</p>
     */
    public static function substr_ileft(string $haystack, string $needle): string
    {
        if ($haystack === '') {
            return '';
        }

        if ($needle === '') {
            return $haystack;
        }

        if (self::str_istarts_with($haystack, $needle)) {
            $haystack = (string) \mb_substr($haystack, (int) self::strlen($needle));
        }

        return $haystack;
    }

    /**
     * Get part of a string process in bytes.
     *
     * @param string   $str    <p>The string being checked.</p>
     * @param int      $offset <p>The first position used in str.</p>
     * @param int|null $length [optional] <p>The maximum length of the returned string.</p>
     *
     * @psalm-pure
     *
     * @return false|string
     *                      <p>The portion of <i>str</i> specified by the <i>offset</i> and
     *                      <i>length</i> parameters.</p><p>If <i>str</i> is shorter than <i>offset</i>
     *                      characters long, <b>FALSE</b> will be returned.</p>
     */
    public static function substr_in_byte(string $str, int $offset = 0, int $length = null)
    {
        // empty string
        if ($str === '' || $length === 0) {
            return '';
        }

        // whole string
        if (!$offset && $length === null) {
            return $str;
        }

        if (self::$SUPPORT['mbstring_func_overload'] === true) {
            // "mb_" is available if overload is used, so use it ...
            return \mb_substr($str, $offset, $length, 'CP850'); // 8-BIT
        }

        return \substr($str, $offset, $length ?? 2147483647);
    }

    /**
     * Removes a suffix ($needle) from the end of the string ($haystack), case-insensitive.
     *
     * EXAMPLE: <code>
     * UTF8::substr_iright('BeginMiddleΚόσμε', 'Κόσμε'); // 'BeginMiddle'
     * UTF8::substr_iright('BeginMiddleΚόσμε', 'κόσμε'); // 'BeginMiddle'
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Return the sub-string.<p>
     */
    public static function substr_iright(string $haystack, string $needle): string
    {
        if ($haystack === '') {
            return '';
        }

        if ($needle === '') {
            return $haystack;
        }

        if (self::str_iends_with($haystack, $needle)) {
            $haystack = (string) \mb_substr($haystack, 0, (int) self::strlen($haystack) - (int) self::strlen($needle));
        }

        return $haystack;
    }

    /**
     * Removes a prefix ($needle) from the beginning of the string ($haystack).
     *
     * EXAMPLE: <code>
     * UTF8::substr_left('ΚόσμεMiddleEnd', 'Κόσμε'); // 'MiddleEnd'
     * UTF8::substr_left('ΚόσμεMiddleEnd', 'κόσμε'); // 'ΚόσμεMiddleEnd'
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Return the sub-string.</p>
     */
    public static function substr_left(string $haystack, string $needle): string
    {
        if ($haystack === '') {
            return '';
        }

        if ($needle === '') {
            return $haystack;
        }

        if (self::str_starts_with($haystack, $needle)) {
            $haystack = (string) \mb_substr($haystack, (int) self::strlen($needle));
        }

        return $haystack;
    }

    /**
     * Replace text within a portion of a string.
     *
     * EXAMPLE: <code>UTF8::substr_replace(array('Iñtërnâtiônàlizætiøn', 'foo'), 'æ', 1); // array('Iæñtërnâtiônàlizætiøn', 'fæoo')</code>
     *
     * source: https://gist.github.com/stemar/8287074
     *
     * @param string|string[] $str         <p>The input string or an array of stings.</p>
     * @param string|string[] $replacement <p>The replacement string or an array of stings.</p>
     * @param int|int[]       $offset      <p>
     *                                     If start is positive, the replacing will begin at the start'th offset
     *                                     into string.
     *                                     <br><br>
     *                                     If start is negative, the replacing will begin at the start'th character
     *                                     from the end of string.
     *                                     </p>
     * @param int|int[]|null  $length      [optional] <p>If given and is positive, it represents the length of the
     *                                     portion of string which is to be replaced. If it is negative, it
     *                                     represents the number of characters from the end of string at which to
     *                                     stop replacing. If it is not given, then it will default to strlen(
     *                                     string ); i.e. end the replacing at the end of string. Of course, if
     *                                     length is zero then this function will have the effect of inserting
     *                                     replacement into string at the given start offset.</p>
     * @param string          $encoding    [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string|string[]
     *                         <p>The result string is returned. If string is an array then array is returned.</p>
     *
     * @template TSubstrReplace string|string[]
     * @phpstan-param TSubstrReplace $str
     * @phpstan-return TSubstrReplace
     */
    public static function substr_replace(
        $str,
        $replacement,
        $offset,
        $length = null,
        string $encoding = 'UTF-8'
    ) {
        if (\is_array($str)) {
            $num = \count($str);

            // the replacement
            if (\is_array($replacement)) {
                $replacement = \array_slice($replacement, 0, $num);
            } else {
                $replacement = \array_pad([$replacement], $num, $replacement);
            }

            // the offset
            if (\is_array($offset)) {
                $offset = \array_slice($offset, 0, $num);
                foreach ($offset as &$value_tmp) {
                    $value_tmp = (int) $value_tmp === $value_tmp ? $value_tmp : 0;
                }
                unset($value_tmp);
            } else {
                $offset = \array_pad([$offset], $num, $offset);
            }

            // the length
            if ($length === null) {
                $length = \array_fill(0, $num, 0);
            } elseif (\is_array($length)) {
                $length = \array_slice($length, 0, $num);
                foreach ($length as &$value_tmp_V2) {
                    $value_tmp_V2 = (int) $value_tmp_V2 === $value_tmp_V2 ? $value_tmp_V2 : $num;
                }
                unset($value_tmp_V2);
            } else {
                $length = \array_pad([$length], $num, $length);
            }

            // recursive call
            /** @phpstan-ignore-next-line - phpstan currently can't handle recursive calls */
            return \array_map([self::class, 'substr_replace'], $str, $replacement, $offset, $length);
        }

        if (\is_array($replacement)) {
            if ($replacement !== []) {
                $replacement = $replacement[0];
            } else {
                $replacement = '';
            }
        }

        // init
        $str = (string) $str;
        $replacement = (string) $replacement;

        if (\is_array($length)) {
            throw new \InvalidArgumentException('Parameter "$length" can only be an array, if "$str" is also an array.');
        }

        if (\is_array($offset)) {
            throw new \InvalidArgumentException('Parameter "$offset" can only be an array, if "$str" is also an array.');
        }

        if ($str === '') {
            return $replacement;
        }

        if (self::$SUPPORT['mbstring'] === true) {
            $string_length = (int) self::strlen($str, $encoding);

            if ($offset < 0) {
                $offset = (int) \max(0, $string_length + $offset);
            } elseif ($offset > $string_length) {
                $offset = $string_length;
            }

            if ($length !== null && $length < 0) {
                $length = (int) \max(0, $string_length - $offset + $length);
            } elseif ($length === null || $length > $string_length) {
                $length = $string_length;
            }

            if (($offset + $length) > $string_length) {
                $length = $string_length - $offset;
            }

            return ((string) \mb_substr($str, 0, $offset, $encoding)) .
                   $replacement .
                   ((string) \mb_substr($str, $offset + $length, $string_length - $offset - $length, $encoding));
        }

        //
        // fallback for ascii only
        //

        if (ASCII::is_ascii($str)) {
            return ($length === null) ?
                \substr_replace($str, $replacement, $offset) :
                \substr_replace($str, $replacement, $offset, $length);
        }

        //
        // fallback via vanilla php
        //

        \preg_match_all('/./us', $str, $str_matches);
        \preg_match_all('/./us', $replacement, $replacement_matches);

        if ($length === null) {
            $length_tmp = self::strlen($str, $encoding);
            if ($length_tmp === false) {
                // e.g.: non mbstring support + invalid chars
                return '';
            }
            $length = $length_tmp;
        }

        \array_splice($str_matches[0], $offset, $length, $replacement_matches[0]);

        return \implode('', $str_matches[0]);
    }

    /**
     * Removes a suffix ($needle) from the end of the string ($haystack).
     *
     * EXAMPLE: <code>
     * UTF8::substr_right('BeginMiddleΚόσμε', 'Κόσμε'); // 'BeginMiddle'
     * UTF8::substr_right('BeginMiddleΚόσμε', 'κόσμε'); // 'BeginMiddleΚόσμε'
     * </code>
     *
     * @param string $haystack <p>The string to search in.</p>
     * @param string $needle   <p>The substring to search for.</p>
     * @param string $encoding [optional] <p>Set the charset for e.g. "mb_" function</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Return the sub-string.</p>
     */
    public static function substr_right(
        string $haystack,
        string $needle,
        string $encoding = 'UTF-8'
    ): string {
        if ($haystack === '') {
            return '';
        }

        if ($needle === '') {
            return $haystack;
        }

        if (
            $encoding === 'UTF-8'
            &&
            \substr($haystack, -\strlen($needle)) === $needle
        ) {
            return (string) \mb_substr($haystack, 0, (int) \mb_strlen($haystack) - (int) \mb_strlen($needle));
        }

        if (\substr($haystack, -\strlen($needle)) === $needle) {
            return (string) self::substr(
                $haystack,
                0,
                (int) self::strlen($haystack, $encoding) - (int) self::strlen($needle, $encoding),
                $encoding
            );
        }

        return $haystack;
    }

    /**
     * Returns a case swapped version of the string.
     *
     * EXAMPLE: <code>UTF8::swapCase('déJÀ σσς iıII'); // 'DÉjà ΣΣΣ IIii'</code>
     *
     * @param string $str        <p>The input string.</p>
     * @param string $encoding   [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool   $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>Each character's case swapped.</p>
     */
    public static function swapCase(string $str, string $encoding = 'UTF-8', bool $clean_utf8 = false): string
    {
        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        if ($encoding === 'UTF-8') {
            return (string) (\mb_strtolower($str) ^ \mb_strtoupper($str) ^ $str);
        }

        return (string) (self::strtolower($str, $encoding) ^ self::strtoupper($str, $encoding) ^ $str);
    }

    /**
     * Checks whether symfony-polyfills are used.
     *
     * @psalm-pure
     *
     * @return bool
     *              <p><strong>true</strong> if in use, <strong>false</strong> otherwise</p>
     *
     * @internal <p>Please do not use it anymore, we will make is private in next major version.</p>
     */
    public static function symfony_polyfill_used(): bool
    {
        // init
        $return = false;

        $return_tmp = \extension_loaded('mbstring');
        if (!$return_tmp && \function_exists('mb_strlen')) {
            $return = true;
        }

        $return_tmp = \extension_loaded('iconv');
        if (!$return_tmp && \function_exists('iconv')) {
            $return = true;
        }

        return $return;
    }

    /**
     * @param string $str
     * @param int    $tab_length
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function tabs_to_spaces(string $str, int $tab_length = 4): string
    {
        if ($tab_length === 4) {
            $spaces = '    ';
        } elseif ($tab_length === 2) {
            $spaces = '  ';
        } else {
            $spaces = \str_repeat(' ', $tab_length);
        }

        return \str_replace("\t", $spaces, $str);
    }

    /**
     * Converts the first character of each word in the string to uppercase
     * and all other chars to lowercase.
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string      $encoding                      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>A string with all characters of $str being title-cased.</p>
     */
    public static function titlecase(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        if (
            $lang === null
            &&
            !$try_to_keep_the_string_length
        ) {
            if ($encoding === 'UTF-8') {
                return \mb_convert_case($str, \MB_CASE_TITLE);
            }

            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            return \mb_convert_case($str, \MB_CASE_TITLE, $encoding);
        }

        return self::str_titleize(
            $str,
            null,
            $encoding,
            false,
            $lang,
            $try_to_keep_the_string_length,
            false
        );
    }

    /**
     * Convert a string into ASCII.
     *
     * EXAMPLE: <code>UTF8::to_ascii('déjà σσς iıii'); // 'deja sss iiii'</code>
     *
     * @param string $str     <p>The input string.</p>
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
     *                        performance</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function to_ascii(
        string $str,
        string $unknown = '?',
        bool $strict = false
    ): string {
        return ASCII::to_transliterate($str, $unknown, $strict);
    }

    /**
     * @param bool|float|int|string $str
     *
     * @psalm-pure
     *
     * @return bool
     */
    public static function to_boolean($str): bool
    {
        // init
        $str = (string) $str;

        if ($str === '') {
            return false;
        }

        // Info: http://php.net/manual/en/filter.filters.validate.php
        $map = [
            'true'  => true,
            '1'     => true,
            'on'    => true,
            'yes'   => true,
            'false' => false,
            '0'     => false,
            'off'   => false,
            'no'    => false,
        ];

        if (isset($map[$str])) {
            return $map[$str];
        }

        $key = \strtolower($str);
        if (isset($map[$key])) {
            return $map[$key];
        }

        if (\is_numeric($str)) {
            return ((float) $str) > 0;
        }

        return (bool) \trim($str);
    }

    /**
     * Convert given string to safe filename (and keep string case).
     *
     * @param string $str
     * @param bool   $use_transliterate No transliteration, conversion etc. is done by default - unsafe characters are
     *                                  simply replaced with hyphen.
     * @param string $fallback_char
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function to_filename(
        string $str,
        bool $use_transliterate = false,
        string $fallback_char = '-'
    ): string {
        return ASCII::to_filename(
            $str,
            $use_transliterate,
            $fallback_char
        );
    }

    /**
     * Convert a string into "ISO-8859"-encoding (Latin-1).
     *
     * EXAMPLE: <code>UTF8::to_utf8(UTF8::to_iso8859('  -ABC-中文空白-  ')); // '  -ABC-????-  '</code>
     *
     * @param string|string[] $str
     *
     * @psalm-pure
     *
     * @return string|string[]
     *
     * @template TToIso8859 as string|string[]
     * @phpstan-param TToIso8859 $str
     * @phpstan-return (TToIso8859 is string ? string : string[])
     */
    public static function to_iso8859($str)
    {
        if (\is_array($str)) {
            foreach ($str as &$v) {
                $v = self::to_iso8859($v);
            }

            return $str;
        }

        /* @phpstan-ignore-next-line | FP? -> "Cannot cast TToIso8859 of array<string>|string to string." it's a string here */
        $str = (string) $str;
        if ($str === '') {
            return '';
        }

        return self::utf8_decode($str);
    }

    /**
     * This function leaves UTF-8 characters alone, while converting almost all non-UTF8 to UTF8.
     *
     * <ul>
     * <li>It decode UTF-8 codepoints and Unicode escape sequences.</li>
     * <li>It assumes that the encoding of the original string is either WINDOWS-1252 or ISO-8859.</li>
     * <li>WARNING: It does not remove invalid UTF-8 characters, so you maybe need to use "UTF8::clean()" for this
     * case.</li>
     * </ul>
     *
     * EXAMPLE: <code>UTF8::to_utf8(["\u0063\u0061\u0074"]); // array('cat')</code>
     *
     * @param string|string[] $str                        <p>Any string or array of strings.</p>
     * @param bool            $decode_html_entity_to_utf8 <p>Set to true, if you need to decode html-entities.</p>
     *
     * @psalm-pure
     *
     * @return string|string[]
     *                         <p>The UTF-8 encoded string</p>
     *
     * @template TToUtf8 as string|string[]
     * @phpstan-param TToUtf8 $str
     * @phpstan-return (TToUtf8 is string ? string : string[])
     */
    public static function to_utf8($str, bool $decode_html_entity_to_utf8 = false)
    {
        if (\is_array($str)) {
            foreach ($str as &$v) {
                $v = self::to_utf8_string($v, $decode_html_entity_to_utf8);
            }

            /** @phpstan-var TToUtf8 $str */
            return $str;
        }

        \assert(\is_string($str));

        $str = self::to_utf8_string($str, $decode_html_entity_to_utf8);

        /** @phpstan-var TToUtf8 $str */
        return $str;
    }

    /**
     * This function leaves UTF-8 characters alone, while converting almost all non-UTF8 to UTF8.
     *
     * <ul>
     * <li>It decode UTF-8 codepoints and Unicode escape sequences.</li>
     * <li>It assumes that the encoding of the original string is either WINDOWS-1252 or ISO-8859.</li>
     * <li>WARNING: It does not remove invalid UTF-8 characters, so you maybe need to use "UTF8::clean()" for this
     * case.</li>
     * </ul>
     *
     * EXAMPLE: <code>UTF8::to_utf8_string("\u0063\u0061\u0074"); // 'cat'</code>
     *
     * @param string $str                        <p>Any string.</p>
     * @param bool   $decode_html_entity_to_utf8 <p>Set to true, if you need to decode html-entities.</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The UTF-8 encoded string</p>
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function to_utf8_string(string $str, bool $decode_html_entity_to_utf8 = false): string
    {
        if ($str === '') {
            return $str;
        }

        $max = \strlen($str);
        $buf = '';

        for ($i = 0; $i < $max; ++$i) {
            $c1 = $str[$i];

            if ($c1 >= "\xC0") { // should be converted to UTF8, if it's not UTF8 already

                if ($c1 <= "\xDF") { // looks like 2 bytes UTF8

                    $c2 = $i + 1 >= $max ? "\x00" : $str[$i + 1];

                    if ($c2 >= "\x80" && $c2 <= "\xBF") { // yeah, almost sure it's UTF8 already
                        $buf .= $c1 . $c2;
                        ++$i;
                    } else { // not valid UTF8 - convert it
                        $buf .= self::to_utf8_convert_helper($c1);
                    }
                } elseif ($c1 >= "\xE0" && $c1 <= "\xEF") { // looks like 3 bytes UTF8

                    $c2 = $i + 1 >= $max ? "\x00" : $str[$i + 1];
                    $c3 = $i + 2 >= $max ? "\x00" : $str[$i + 2];

                    if ($c2 >= "\x80" && $c2 <= "\xBF" && $c3 >= "\x80" && $c3 <= "\xBF") { // yeah, almost sure it's UTF8 already
                        $buf .= $c1 . $c2 . $c3;
                        $i += 2;
                    } else { // not valid UTF8 - convert it
                        $buf .= self::to_utf8_convert_helper($c1);
                    }
                } elseif ($c1 >= "\xF0" && $c1 <= "\xF7") { // looks like 4 bytes UTF8

                    $c2 = $i + 1 >= $max ? "\x00" : $str[$i + 1];
                    $c3 = $i + 2 >= $max ? "\x00" : $str[$i + 2];
                    $c4 = $i + 3 >= $max ? "\x00" : $str[$i + 3];

                    if ($c2 >= "\x80" && $c2 <= "\xBF" && $c3 >= "\x80" && $c3 <= "\xBF" && $c4 >= "\x80" && $c4 <= "\xBF") { // yeah, almost sure it's UTF8 already
                        $buf .= $c1 . $c2 . $c3 . $c4;
                        $i += 3;
                    } else { // not valid UTF8 - convert it
                        $buf .= self::to_utf8_convert_helper($c1);
                    }
                } else { // doesn't look like UTF8, but should be converted

                    $buf .= self::to_utf8_convert_helper($c1);
                }
            } elseif (($c1 & "\xC0") === "\x80") { // needs conversion

                $buf .= self::to_utf8_convert_helper($c1);
            } else { // it doesn't need conversion

                $buf .= $c1;
            }
        }

        // decode unicode escape sequences + unicode surrogate pairs
        $buf = \preg_replace_callback(
            '/\\\\u([dD][89abAB][0-9a-fA-F]{2})\\\\u([dD][cdefCDEF][\da-fA-F]{2})|\\\\u([0-9a-fA-F]{4})/',
            /**
             * @param array $matches
             *
             * @psalm-pure
             *
             * @return string
             */
            static function (array $matches): string {
                if (isset($matches[3])) {
                    $cp = (int) \hexdec($matches[3]);
                } else {
                    // http://unicode.org/faq/utf_bom.html#utf16-4
                    $cp = ((int) \hexdec($matches[1]) << 10)
                          + (int) \hexdec($matches[2])
                          + 0x10000
                          - (0xD800 << 10)
                          - 0xDC00;
                }

                // https://github.com/php/php-src/blob/php-7.3.2/ext/standard/html.c#L471
                //
                // php_utf32_utf8(unsigned char *buf, unsigned k)

                if ($cp < 0x80) {
                    return (string) self::chr($cp);
                }

                if ($cp < 0xA0) {
                    /** @noinspection UnnecessaryCastingInspection */
                    return (string) self::chr(0xC0 | $cp >> 6) . (string) self::chr(0x80 | $cp & 0x3F);
                }

                return self::decimal_to_chr($cp);
            },
            $buf
        );

        if ($buf === null) {
            return '';
        }

        // decode UTF-8 codepoints
        if ($decode_html_entity_to_utf8) {
            $buf = self::html_entity_decode($buf);
        }

        return $buf;
    }

    /**
     * Returns the given string as an integer, or null if the string isn't numeric.
     *
     * @param string $str
     *
     * @psalm-pure
     *
     * @return int|null
     *                  <p>null if the string isn't numeric</p>
     */
    public static function to_int(string $str)
    {
        if (\is_numeric($str)) {
            return (int) $str;
        }

        return null;
    }

    /**
     * Returns the given input as string, or null if the input isn't int|float|string
     * and do not implement the "__toString()" method.
     *
     * @param float|int|object|string|null $input
     *
     * @psalm-pure
     *
     * @return string|null
     *                     <p>null if the input isn't int|float|string and has no "__toString()" method</p>
     */
    public static function to_string($input)
    {
        if ($input === null) {
            return null;
        }

        $input_type = \gettype($input);

        if (
            $input_type === 'string'
            ||
            $input_type === 'integer'
            ||
            $input_type === 'float'
            ||
            $input_type === 'double'
        ) {
            /* @phpstan-ignore-next-line | "gettype" is not supported by phpstan?! */
            return (string) $input;
        }

        /** @phpstan-ignore-next-line - "gettype": FP? */
        if ($input_type === 'object' && \method_exists($input, '__toString')) {
            return (string) $input;
        }

        return null;
    }

    /**
     * Strip whitespace or other characters from the beginning and end of a UTF-8 string.
     *
     * INFO: This is slower then "trim()"
     *
     * We can only use the original-function, if we use <= 7-Bit in the string / chars
     * but the check for ASCII (7-Bit) cost more time, then we can safe here.
     *
     * EXAMPLE: <code>UTF8::trim('   -ABC-中文空白-  '); // '-ABC-中文空白-'</code>
     *
     * @param string      $str   <p>The string to be trimmed</p>
     * @param string|null $chars [optional] <p>Optional characters to be stripped</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The trimmed string.</p>
     */
    public static function trim(string $str = '', string $chars = null): string
    {
        if ($str === '') {
            return '';
        }

        if (self::$SUPPORT['mbstring'] === true) {
            if ($chars !== null) {
                /** @noinspection PregQuoteUsageInspection */
                $chars = \preg_quote($chars);
                $pattern = "^[{$chars}]+|[{$chars}]+\$";
            } else {
                $pattern = '^[\\s]+|[\\s]+$';
            }

            return (string) \mb_ereg_replace($pattern, '', $str);
        }

        if ($chars !== null) {
            $chars = \preg_quote($chars, '/');
            $pattern = "^[{$chars}]+|[{$chars}]+\$";
        } else {
            $pattern = '^[\\s]+|[\\s]+$';
        }

        return self::regex_replace($str, $pattern, '');
    }

    /**
     * Makes string's first char uppercase.
     *
     * EXAMPLE: <code>UTF8::ucfirst('ñtërnâtiônàlizætiøn foo'); // 'Ñtërnâtiônàlizætiøn foo'</code>
     *
     * @param string      $str                           <p>The input string.</p>
     * @param string      $encoding                      [optional] <p>Set the charset for e.g. "mb_" function</p>
     * @param bool        $clean_utf8                    [optional] <p>Remove non UTF-8 chars from the string.</p>
     * @param string|null $lang                          [optional] <p>Set the language for special cases: az, el, lt,
     *                                                   tr</p>
     * @param bool        $try_to_keep_the_string_length [optional] <p>true === try to keep the string length: e.g. ẞ
     *                                                   -> ß</p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The resulting string with with char uppercase.</p>
     */
    public static function ucfirst(
        string $str,
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false,
        string $lang = null,
        bool $try_to_keep_the_string_length = false
    ): string {
        if ($str === '') {
            return '';
        }

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        $use_mb_functions = $lang === null && !$try_to_keep_the_string_length;

        if ($encoding === 'UTF-8') {
            $str_part_two = (string) \mb_substr($str, 1);

            if ($use_mb_functions) {
                $str_part_one = \mb_strtoupper(
                    (string) \mb_substr($str, 0, 1)
                );
            } else {
                $str_part_one = self::strtoupper(
                    (string) \mb_substr($str, 0, 1),
                    $encoding,
                    false,
                    $lang,
                    $try_to_keep_the_string_length
                );
            }
        } else {
            $encoding = self::normalize_encoding($encoding, 'UTF-8');

            $str_part_two = (string) self::substr($str, 1, null, $encoding);

            if ($use_mb_functions) {
                $str_part_one = \mb_strtoupper(
                    (string) \mb_substr($str, 0, 1, $encoding),
                    $encoding
                );
            } else {
                $str_part_one = self::strtoupper(
                    (string) self::substr($str, 0, 1, $encoding),
                    $encoding,
                    false,
                    $lang,
                    $try_to_keep_the_string_length
                );
            }
        }

        return $str_part_one . $str_part_two;
    }

    /**
     * Uppercase for all words in the string.
     *
     * EXAMPLE: <code>UTF8::ucwords('iñt ërn âTi ônà liz æti øn'); // 'Iñt Ërn ÂTi Ônà Liz Æti Øn'</code>
     *
     * @param string   $str        <p>The input string.</p>
     * @param string[] $exceptions [optional] <p>Exclusion for some words.</p>
     * @param string   $char_list  [optional] <p>Additional chars that contains to words and do not start a new
     *                             word.</p>
     * @param string   $encoding   [optional] <p>Set the charset.</p>
     * @param bool     $clean_utf8 [optional] <p>Remove non UTF-8 chars from the string.</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function ucwords(
        string $str,
        array $exceptions = [],
        string $char_list = '',
        string $encoding = 'UTF-8',
        bool $clean_utf8 = false
    ): string {
        if (!$str) {
            return '';
        }

        // INFO: mb_convert_case($str, MB_CASE_TITLE);
        // -> MB_CASE_TITLE didn't only uppercase the first letter, it also lowercase all other letters

        if ($clean_utf8) {
            // "mb_strpos()" and "iconv_strpos()" returns wrong position,
            // if invalid characters are found in $haystack before $needle
            $str = self::clean($str);
        }

        $use_php_default_functions = !(bool) ($char_list . \implode('', $exceptions));

        if (
            $use_php_default_functions
            &&
            ASCII::is_ascii($str)
        ) {
            return \ucwords($str);
        }

        $words = self::str_to_words($str, $char_list);
        $use_exceptions = $exceptions !== [];

        $words_str = '';
        foreach ($words as &$word) {
            if (!$word) {
                continue;
            }

            if (
                !$use_exceptions
                ||
                !\in_array($word, $exceptions, true)
            ) {
                $words_str .= self::ucfirst($word, $encoding);
            } else {
                $words_str .= $word;
            }
        }

        return $words_str;
    }

    /**
     * Multi decode HTML entity + fix urlencoded-win1252-chars.
     *
     * EXAMPLE: <code>UTF8::urldecode('tes%20öäü%20\u00edtest+test'); // 'tes öäü ítest test'</code>
     *
     * e.g:
     * 'test+test'                     => 'test test'
     * 'D&#252;sseldorf'               => 'Düsseldorf'
     * 'D%FCsseldorf'                  => 'Düsseldorf'
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
     * 'DÃ¼sseldorf'                   => 'Düsseldorf'
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
     *
     * @param string $str          <p>The input string.</p>
     * @param bool   $multi_decode <p>Decode as often as possible.</p>
     *
     * @psalm-pure
     *
     * @return string
     *
     * @template T as string
     * @phpstan-param T $str
     * @phpstan-return (T is non-empty-string ? non-empty-string : string)
     */
    public static function urldecode(string $str, bool $multi_decode = true): string
    {
        if ($str === '') {
            return '';
        }

        $str = self::urldecode_unicode_helper($str);

        if ($multi_decode) {
            do {
                $str_compare = $str;

                /**
                 * @psalm-suppress PossiblyInvalidArgument
                 */
                $str = \urldecode(
                    self::html_entity_decode(
                        self::to_utf8($str),
                        \ENT_QUOTES | \ENT_HTML5
                    )
                );
            } while ($str_compare !== $str);
        } else {
            /**
             * @psalm-suppress PossiblyInvalidArgument
             */
            $str = \urldecode(
                self::html_entity_decode(
                    self::to_utf8($str),
                    \ENT_QUOTES | \ENT_HTML5
                )
            );
        }

        return self::fix_simple_utf8($str);
    }

    /**
     * Decodes a UTF-8 string to ISO-8859-1.
     *
     * EXAMPLE: <code>UTF8::encode('UTF-8', UTF8::utf8_decode('-ABC-中文空白-')); // '-ABC-????-'</code>
     *
     * @param string $str             <p>The input string.</p>
     * @param bool   $keep_utf8_chars
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function utf8_decode(string $str, bool $keep_utf8_chars = false): string
    {
        if ($str === '') {
            return '';
        }

        // save for later comparision
        $str_backup = $str;
        $len = \strlen($str);

        if (self::$ORD === null) {
            self::$ORD = self::getData('ord');
        }

        if (self::$CHR === null) {
            self::$CHR = self::getData('chr');
        }

        $no_char_found = '?';
        for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
            switch ($str[$i] & "\xF0") {
                case "\xC0":
                case "\xD0":
                    $c = (self::$ORD[$str[$i] & "\x1F"] << 6) | self::$ORD[$str[++$i] & "\x3F"];
                    $str[$j] = $c < 256 ? self::$CHR[$c] : $no_char_found;

                    break;

                case "\xF0":
                    ++$i;

                // no break

                case "\xE0":
                    $str[$j] = $no_char_found;
                    $i += 2;

                    break;

                default:
                    $str[$j] = $str[$i];
            }
        }

        /** @var false|string $return - needed for PhpStan (stubs error) */
        $return = \substr($str, 0, $j);
        if ($return === false) {
            $return = '';
        }

        if (
            $keep_utf8_chars
            &&
            (int) self::strlen($return) >= (int) self::strlen($str_backup)
        ) {
            return $str_backup;
        }

        return $return;
    }

    /**
     * Encodes an ISO-8859-1 string to UTF-8.
     *
     * EXAMPLE: <code>UTF8::utf8_decode(UTF8::utf8_encode('-ABC-中文空白-')); // '-ABC-中文空白-'</code>
     *
     * @param string $str <p>The input string.</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function utf8_encode(string $str): string
    {
        if ($str === '') {
            return '';
        }

        /** @noinspection PhpUsageOfSilenceOperatorInspection | TODO for PHP > 8.2: find a replacement for this */
        /** @var false|string $str - the polyfill maybe return false */
        $str = @\utf8_encode($str);

        if ($str === false) {
            return '';
        }

        return $str;
    }

    /**
     * Returns an array with all utf8 whitespace characters.
     *
     * @see http://www.bogofilter.org/pipermail/bogofilter/2003-March/001889.html
     *
     * @psalm-pure
     *
     * @return string[]
     *                  An array with all known whitespace characters as values and the type of whitespace as keys
     *                  as defined in above URL
     */
    public static function whitespace_table(): array
    {
        return self::$WHITESPACE_TABLE;
    }

    /**
     * Limit the number of words in a string.
     *
     * EXAMPLE: <code>UTF8::words_limit('fòô bàř fòô', 2, ''); // 'fòô bàř'</code>
     *
     * @param string      $str        <p>The input string.</p>
     * @param int<1, max> $limit      <p>The limit of words as integer.</p>
     * @param string      $str_add_on <p>Replacement for the striped string.</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function words_limit(
        string $str,
        int $limit = 100,
        string $str_add_on = '…'
    ): string {
        if (
            $str === ''
            ||
            /* @phpstan-ignore-next-line | we do not trust the phpdoc check */
            $limit <= 0
        ) {
            return '';
        }

        \preg_match('/^\\s*+(?:[^\\s]++\\s*+){1,' . $limit . '}/u', $str, $matches);

        if (
            !isset($matches[0])
            ||
            \mb_strlen($str) === (int) \mb_strlen($matches[0])
        ) {
            return $str;
        }

        return \rtrim($matches[0]) . $str_add_on;
    }

    /**
     * Wraps a string to a given number of characters
     *
     * EXAMPLE: <code>UTF8::wordwrap('Iñtërnâtiônàlizætiøn', 2, '<br>', true)); // 'Iñ<br>të<br>rn<br>ât<br>iô<br>nà<br>li<br>zæ<br>ti<br>øn'</code>
     *
     * @see http://php.net/manual/en/function.wordwrap.php
     *
     * @param string      $str   <p>The input string.</p>
     * @param int<1, max> $width [optional] <p>The column width.</p>
     * @param string      $break [optional] <p>The line is broken using the optional break parameter.</p>
     * @param bool        $cut   [optional] <p>
     *                      If the cut is set to true, the string is
     *                      always wrapped at or before the specified width. So if you have
     *                      a word that is larger than the given width, it is broken apart.
     *                      </p>
     *
     * @psalm-pure
     *
     * @return string
     *                <p>The given string wrapped at the specified column.</p>
     */
    public static function wordwrap(
        string $str,
        int $width = 75,
        string $break = "\n",
        bool $cut = false
    ): string {
        if ($str === '' || $break === '') {
            return '';
        }

        $str_split = \explode($break, $str);

        /** @var string[] $charsArray */
        $charsArray = [];
        $word_split = '';
        foreach ($str_split as $i => $i_value) {
            if ($i) {
                $charsArray[] = $break;
                $word_split .= '#';
            }

            foreach (self::str_split($i_value) as $c) {
                $charsArray[] = $c;
                if ($c === ' ') {
                    $word_split .= ' ';
                } else {
                    $word_split .= '?';
                }
            }
        }

        $str_return = '';
        $j = 0;
        $b = -1;
        $i = -1;
        $word_split = \wordwrap($word_split, $width, '#', $cut);

        $max = \mb_strlen($word_split);
        /** @noinspection PhpAssignmentInConditionInspection - is ok here */
        while (($b = \mb_strpos($word_split, '#', $b + 1)) !== false) {
            for (++$i; $i < $b; ++$i) {
                if (isset($charsArray[$j])) {
                    $str_return .= $charsArray[$j];
                    unset($charsArray[$j]);
                }
                ++$j;

                // prevent endless loop, e.g. if there is a error in the "mb_*" polyfill
                if ($i > $max) {
                    break 2;
                }
            }

            if (
                $break === $charsArray[$j]
                ||
                $charsArray[$j] === ' '
            ) {
                unset($charsArray[$j++]);
            }

            $str_return .= $break;

            // prevent endless loop, e.g. if there is a error in the "mb_*" polyfill
            if ($b > $max) {
                break;
            }
        }

        return $str_return . \implode('', $charsArray);
    }

    /**
     * Line-Wrap the string after $limit, but split the string by "$delimiter" before ...
     *    ... so that we wrap the per line.
     *
     * @param string      $str             <p>The input string.</p>
     * @param int<1, max> $width           [optional] <p>The column width.</p>
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
     * @param bool        $cut             [optional] <p>
     *                                     If the cut is set to true, the string is
     *                                     always wrapped at or before the specified width. So if you have
     *                                     a word that is larger than the given width, it is broken apart.
     *                                     </p>
     * @param bool        $add_final_break [optional] <p>
     *                                     If this flag is true, then the method will add a $break at the end
     *                                     of the result string.
     *                                     </p>
     * @param non-empty-string|null $delimiter       [optional] <p>
     *                                     You can change the default behavior, where we split the string by newline.
     *                                     </p>
     *
     * @psalm-pure
     *
     * @return string
     */
    public static function wordwrap_per_line(
        string $str,
        int $width = 75,
        string $break = "\n",
        bool $cut = false,
        bool $add_final_break = true,
        string $delimiter = null
    ): string {
        if ($delimiter === null) {
            $strings = \preg_split('/\\r\\n|\\r|\\n/', $str);
        } else {
            $strings = \explode($delimiter, $str);
        }

        $string_helper_array = [];
        if ($strings !== false) {
            foreach ($strings as $value) {
                $string_helper_array[] = self::wordwrap($value, $width, $break, $cut);
            }
        }

        if ($add_final_break) {
            $final_break = $break;
        } else {
            $final_break = '';
        }

        return \implode($delimiter ?? "\n", $string_helper_array) . $final_break;
    }

    /**
     * Returns an array of Unicode White Space characters.
     *
     * @psalm-pure
     *
     * @return string[]
     *                  <p>An array with numeric code point as key and White Space Character as value.</p>
     */
    public static function ws(): array
    {
        return self::$WHITESPACE;
    }

    /**
     * Checks whether the passed string contains only byte sequences that are valid UTF-8 characters.
     *
     * EXAMPLE: <code>
     * UTF8::is_utf8_string('Iñtërnâtiônàlizætiøn']); // true
     * //
     * UTF8::is_utf8_string("Iñtërnâtiônàlizætiøn\xA0\xA1"); // false
     * </code>
     *
     * @see          http://hsivonen.iki.fi/php-utf8/
     *
     * @param string $str    <p>The string to be checked.</p>
     * @param bool   $strict <p>Check also if the string is not UTF-16 or UTF-32.</p>
     *
     * @psalm-pure
     *
     * @return bool
     */
    private static function is_utf8_string(string $str, bool $strict = false)
    {
        if ($str === '') {
            return true;
        }

        if ($strict) {
            $is_binary = self::is_binary($str, true);

            if ($is_binary && self::is_utf16($str, false) !== false) {
                return false;
            }

            if ($is_binary && self::is_utf32($str, false) !== false) {
                return false;
            }
        }

        if (self::$SUPPORT['pcre_utf8']) {
            // If even just the first character can be matched, when the /u
            // modifier is used, then it's valid UTF-8. If the UTF-8 is somehow
            // invalid, nothing at all will match, even if the string contains
            // some valid sequences
            return \preg_match('/^./us', $str) === 1;
        }

        $mState = 0; // cached expected number of octets after the current octet
        // until the beginning of the next UTF8 character sequence
        $mUcs4 = 0; // cached Unicode character
        $mBytes = 1; // cached expected number of octets in the current sequence

        if (self::$ORD === null) {
            self::$ORD = self::getData('ord');
        }

        $len = \strlen($str);
        for ($i = 0; $i < $len; ++$i) {
            $in = self::$ORD[$str[$i]];

            if ($mState === 0) {
                // When mState is zero we expect either a US-ASCII character or a
                // multi-octet sequence.
                if ((0x80 & $in) === 0) {
                    // US-ASCII, pass straight through.
                    $mBytes = 1;
                } elseif ((0xE0 & $in) === 0xC0) {
                    // First octet of 2 octet sequence.
                    $mUcs4 = $in;
                    $mUcs4 = ($mUcs4 & 0x1F) << 6;
                    $mState = 1;
                    $mBytes = 2;
                } elseif ((0xF0 & $in) === 0xE0) {
                    // First octet of 3 octet sequence.
                    $mUcs4 = $in;
                    $mUcs4 = ($mUcs4 & 0x0F) << 12;
                    $mState = 2;
                    $mBytes = 3;
                } elseif ((0xF8 & $in) === 0xF0) {
                    // First octet of 4 octet sequence.
                    $mUcs4 = $in;
                    $mUcs4 = ($mUcs4 & 0x07) << 18;
                    $mState = 3;
                    $mBytes = 4;
                } elseif ((0xFC & $in) === 0xF8) {
                    /* First octet of 5 octet sequence.
                     *
                     * This is illegal because the encoded codepoint must be either
                     * (a) not the shortest form or
                     * (b) outside the Unicode range of 0-0x10FFFF.
                     * Rather than trying to resynchronize, we will carry on until the end
                     * of the sequence and let the later error handling code catch it.
                     */
                    $mUcs4 = $in;
                    $mUcs4 = ($mUcs4 & 0x03) << 24;
                    $mState = 4;
                    $mBytes = 5;
                } elseif ((0xFE & $in) === 0xFC) {
                    // First octet of 6 octet sequence, see comments for 5 octet sequence.
                    $mUcs4 = $in;
                    $mUcs4 = ($mUcs4 & 1) << 30;
                    $mState = 5;
                    $mBytes = 6;
                } else {
                    // Current octet is neither in the US-ASCII range nor a legal first
                    // octet of a multi-octet sequence.
                    return false;
                }
            } elseif ((0xC0 & $in) === 0x80) {

                // When mState is non-zero, we expect a continuation of the multi-octet
                // sequence

                // Legal continuation.
                $shift = ($mState - 1) * 6;
                $tmp = $in;
                $tmp = ($tmp & 0x0000003F) << $shift;
                $mUcs4 |= $tmp;
                // Prefix: End of the multi-octet sequence. mUcs4 now contains the final
                // Unicode code point to be output.
                if (--$mState === 0) {
                    // Check for illegal sequences and code points.
                    //
                    // From Unicode 3.1, non-shortest form is illegal
                    if (
                        ($mBytes === 2 && $mUcs4 < 0x0080)
                        ||
                        ($mBytes === 3 && $mUcs4 < 0x0800)
                        ||
                        ($mBytes === 4 && $mUcs4 < 0x10000)
                        ||
                        ($mBytes > 4)
                        ||
                        // From Unicode 3.2, surrogate characters are illegal.
                        (($mUcs4 & 0xFFFFF800) === 0xD800)
                        ||
                        // Code points outside the Unicode range are illegal.
                        ($mUcs4 > 0x10FFFF)
                    ) {
                        return false;
                    }
                    // initialize UTF8 cache
                    $mState = 0;
                    $mUcs4 = 0;
                    $mBytes = 1;
                }
            } else {
                // ((0xC0 & (*in) != 0x80) && (mState != 0))
                // Incomplete multi-octet sequence.
                return false;
            }
        }

        return $mState === 0;
    }

    /**
     * @param string $str
     * @param bool   $use_lowercase      <p>Use uppercase by default, otherwise use lowercase.</p>
     * @param bool   $use_full_case_fold <p>Convert not only common cases.</p>
     *
     * @psalm-pure
     *
     * @return string
     */
    private static function fixStrCaseHelper(
        string $str,
        bool $use_lowercase = false,
        bool $use_full_case_fold = false
    ) {
        $upper = self::$COMMON_CASE_FOLD['upper'];
        $lower = self::$COMMON_CASE_FOLD['lower'];

        if ($use_lowercase) {
            $str = \str_replace(
                $upper,
                $lower,
                $str
            );
        } else {
            $str = \str_replace(
                $lower,
                $upper,
                $str
            );
        }

        if ($use_full_case_fold) {
            /**
             * @psalm-suppress ImpureStaticVariable
             *
             * @var array<mixed>|null
             */
            static $FULL_CASE_FOLD = null;
            if ($FULL_CASE_FOLD === null) {
                $FULL_CASE_FOLD = self::getData('caseFolding_full');
            }

            if ($use_lowercase) {
                $str = \str_replace($FULL_CASE_FOLD[0], $FULL_CASE_FOLD[1], $str);
            } else {
                $str = \str_replace($FULL_CASE_FOLD[1], $FULL_CASE_FOLD[0], $str);
            }
        }

        return $str;
    }

    /**
     * get data from "/data/*.php"
     *
     * @param string $file
     *
     * @psalm-pure
     *
     * @return array<array-key, mixed>
     */
    private static function getData(string $file)
    {
        /** @noinspection PhpIncludeInspection */
        /** @noinspection UsingInclusionReturnValueInspection */
        /** @psalm-suppress UnresolvableInclude */
        return include __DIR__ . '/data/' . $file . '.php';
    }

    /**
     * @psalm-pure
     *
     * @return true|null
     */
    private static function initEmojiData()
    {
        if (self::$EMOJI_KEYS_CACHE === null) {
            if (self::$EMOJI === null) {
                self::$EMOJI = self::getData('emoji');
            }

            /**
             * @psalm-suppress ImpureFunctionCall - static sort function is used
             */
            \uksort(
                self::$EMOJI,
                static function (string $a, string $b): int {
                    return \strlen($b) <=> \strlen($a);
                }
            );

            self::$EMOJI_KEYS_CACHE = \array_keys(self::$EMOJI);
            self::$EMOJI_VALUES_CACHE = self::$EMOJI;

            foreach (self::$EMOJI_KEYS_CACHE as $key) {
                $tmp_key = \crc32($key);
                self::$EMOJI_KEYS_REVERSIBLE_CACHE[] = '_-_PORTABLE_UTF8_-_' . $tmp_key . '_-_' . \strrev((string) $tmp_key) . '_-_8FTU_ELBATROP_-_';
            }

            return true;
        }

        return null;
    }

    /**
     * Checks whether mbstring "overloaded" is active on the server.
     *
     * @psalm-pure
     *
     * @return bool
     */
    private static function mbstring_overloaded(): bool
    {
        /**
         * INI directive 'mbstring.func_overload' is deprecated since PHP 7.2
         */

        /** @noinspection PhpComposerExtensionStubsInspection */
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
        /** @noinspection DeprecatedIniOptionsInspection */
        return \defined('MB_OVERLOAD_STRING')
               &&
               ((int) @\ini_get('mbstring.func_overload') & \MB_OVERLOAD_STRING);
    }

    /**
     * @param string[] $strings
     * @param bool     $remove_empty_values
     * @param int|null $remove_short_values
     *
     * @psalm-pure
     *
     * @return list<string>
     */
    private static function reduce_string_array(
        array $strings,
        bool $remove_empty_values,
        int $remove_short_values = null
    ) {
        // init
        $return = [];

        foreach ($strings as &$str) {
            if (
                $remove_short_values !== null
                &&
                \mb_strlen($str) <= $remove_short_values
            ) {
                continue;
            }

            if (
                $remove_empty_values
                &&
                \trim($str) === ''
            ) {
                continue;
            }

            $return[] = $str;
        }

        return $return;
    }

    /**
     * rxClass
     *
     * @param string $s
     * @param string $class
     *
     * @return string
     *
     * @psalm-pure
     */
    private static function rxClass(string $s, string $class = '')
    {
        /**
         * @psalm-suppress ImpureStaticVariable
         *
         * @var array<string,string>
         */
        static $RX_CLASS_CACHE = [];

        $cache_key = $s . '_' . $class;

        if (isset($RX_CLASS_CACHE[$cache_key])) {
            return $RX_CLASS_CACHE[$cache_key];
        }

        $class_array = [];
        $class_array[] = $class;

        /** @noinspection SuspiciousLoopInspection */
        /** @noinspection AlterInForeachInspection */
        foreach (self::str_split($s) as &$s) {
            if ($s === '-') {
                $class_array[0] = '-' . $class_array[0];
            } elseif (!isset($s[2])) {
                $class_array[0] .= \preg_quote($s, '/');
            } elseif (self::strlen($s) === 1) {
                $class_array[0] .= $s;
            } else {
                $class_array[] = $s;
            }
        }

        if ($class_array[0]) {
            $class_array[0] = '[' . $class_array[0] . ']';
        }

        if (\count($class_array) === 1) {
            $return = $class_array[0];
        } else {
            $return = '(?:' . \implode('|', $class_array) . ')';
        }

        $RX_CLASS_CACHE[$cache_key] = $return;

        return $return;
    }

    /**
     * Personal names such as "Marcus Aurelius" are sometimes typed incorrectly using lowercase ("marcus aurelius").
     *
     * @param string $names
     * @param string $delimiter
     * @param string $encoding
     *
     * @phpstan-param non-empty-string $delimiter
     *
     * @psalm-pure
     *
     * @return string
     */
    private static function str_capitalize_name_helper(
        string $names,
        string $delimiter,
        string $encoding = 'UTF-8'
    ) {
        // init
        try {
            $name_helper_array = \explode($delimiter, $names);
        } catch (\Error $e) {
            // PHP >= 8.0 : explode() will now throw ValueError when separator parameter is given an empty string (""). Previously, explode() returned false instead.
            $name_helper_array = false;
        }
        if ($name_helper_array === false) {
            return '';
        }

        $special_cases = [
            'names' => [
                'ab',
                'af',
                'al',
                'and',
                'ap',
                'bint',
                'binte',
                'da',
                'de',
                'del',
                'den',
                'der',
                'di',
                'dit',
                'ibn',
                'la',
                'mac',
                'nic',
                'of',
                'ter',
                'the',
                'und',
                'van',
                'von',
                'y',
                'zu',
            ],
            'prefixes' => [
                'al-',
                "d'",
                'ff',
                "l'",
                'mac',
                'mc',
                'nic',
            ],
        ];

        foreach ($name_helper_array as &$name) {
            if (\in_array($name, $special_cases['names'], true)) {
                continue;
            }

            $continue = false;

            if ($delimiter === '-') {
                foreach ((array) $special_cases['names'] as &$beginning) {
                    if (\strncmp($name, $beginning, \strlen($beginning)) === 0) {
                        $continue = true;

                        break;
                    }
                }
                unset($beginning);
            }

            foreach ((array) $special_cases['prefixes'] as &$beginning) {
                if (\strncmp($name, $beginning, \strlen($beginning)) === 0) {
                    $continue = true;

                    break;
                }
            }
            unset($beginning);

            if ($continue) {
                continue;
            }

            $name = self::ucfirst($name, $encoding);
        }

        return \implode($delimiter, $name_helper_array);
    }

    /**
     * Generic case-sensitive transformation for collation matching.
     *
     * @param string $str <p>The input string</p>
     *
     * @psalm-pure
     *
     * @return string|null
     */
    private static function strtonatfold(string $str)
    {
        $str = \Normalizer::normalize($str, \Normalizer::NFD);
        if ($str === false) {
            return '';
        }

        return \preg_replace(
            '/\p{Mn}+/u',
            '',
            $str
        );
    }

    /**
     * @param int|string $input
     *
     * @psalm-pure
     *
     * @return string
     */
    private static function to_utf8_convert_helper($input)
    {
        // init
        $buf = '';

        if (self::$ORD === null) {
            self::$ORD = self::getData('ord');
        }

        if (self::$CHR === null) {
            self::$CHR = self::getData('chr');
        }

        if (self::$WIN1252_TO_UTF8 === null) {
            self::$WIN1252_TO_UTF8 = self::getData('win1252_to_utf8');
        }

        $ordC1 = self::$ORD[$input];
        if (isset(self::$WIN1252_TO_UTF8[$ordC1])) { // found in Windows-1252 special cases
            $buf .= self::$WIN1252_TO_UTF8[$ordC1];
        } else {
            $cc1 = self::$CHR[$ordC1 / 64] | "\xC0";
            $cc2 = ((string) $input & "\x3F") | "\x80";
            $buf .= $cc1 . $cc2;
        }

        return $buf;
    }

    /**
     * @param string $str
     *
     * @psalm-pure
     *
     * @return string
     */
    private static function urldecode_unicode_helper(string $str)
    {
        if (\strpos($str, '%u') === false) {
            return $str;
        }

        $pattern = '/%u([0-9a-fA-F]{3,4})/';
        if (\preg_match($pattern, $str)) {
            $str = (string) \preg_replace($pattern, '&#x\\1;', $str);
        }

        return $str;
    }
}
<?php

// arabic

static $data = [
    'فى',
    'في',
    'كل',
    'لم',
    'لن',
    'له',
    'من',
    'هو',
    'هي',
    'قوة',
    'كما',
    'لها',
    'منذ',
    'وقد',
    'ولا',
    'نفسه',
    'لقاء',
    'مقابل',
    'هناك',
    'وقال',
    'وكان',
    'نهاية',
    'وقالت',
    'وكانت',
    'للامم',
    'فيه',
    'كلم',
    'لكن',
    'وفي',
    'وقف',
    'ولم',
    'ومن',
    'وهو',
    'وهي',
    'يوم',
    'فيها',
    'منها',
    'مليار',
    'لوكالة',
    'يكون',
    'يمكن',
    'مليون',
    'حيث',
    'اكد',
    'الا',
    'اما',
    'امس',
    'السابق',
    'التى',
    'التي',
    'اكثر',
    'ايار',
    'ايضا',
    'ثلاثة',
    'الذاتي',
    'الاخيرة',
    'الثاني',
    'الثانية',
    'الذى',
    'الذي',
    'الان',
    'امام',
    'ايام',
    'خلال',
    'حوالى',
    'الذين',
    'الاول',
    'الاولى',
    'بين',
    'ذلك',
    'دون',
    'حول',
    'حين',
    'الف',
    'الى',
    'انه',
    'اول',
    'ضمن',
    'انها',
    'جميع',
    'الماضي',
    'الوقت',
    'المقبل',
    'اليوم',
    'ـ',
    'ف',
    'و',
    'و6',
    'قد',
    'لا',
    'ما',
    'مع',
    'مساء',
    'هذا',
    'واحد',
    'واضاف',
    'واضافت',
    'فان',
    'قبل',
    'قال',
    'كان',
    'لدى',
    'نحو',
    'هذه',
    'وان',
    'واكد',
    'كانت',
    'واوضح',
    'مايو',
    'ب',
    'ا',
    'أ',
    '،',
    'عشر',
    'عدد',
    'عدة',
    'عشرة',
    'عدم',
    'عام',
    'عاما',
    'عن',
    'عند',
    'عندما',
    'على',
    'عليه',
    'عليها',
    'زيارة',
    'سنة',
    'سنوات',
    'تم',
    'ضد',
    'بعد',
    'بعض',
    'اعادة',
    'اعلنت',
    'بسبب',
    'حتى',
    'اذا',
    'احد',
    'اثر',
    'برس',
    'باسم',
    'غدا',
    'شخصا',
    'صباح',
    'اطار',
    'اربعة',
    'اخرى',
    'بان',
    'اجل',
    'غير',
    'بشكل',
    'حاليا',
    'بن',
    'به',
    'ثم',
    'اف',
    'ان',
    'او',
    'اي',
    'بها',
    'صفر',
];

$result =& $data;
unset($data);
return $result;
<?php

// bulgarian

static $data = [
    'а',
    'автентичен',
    'аз',
    'ако',
    'ала',
    'бе',
    'без',
    'беше',
    'би',
    'бивш',
    'бивша',
    'бившо',
    'бил',
    'била',
    'били',
    'било',
    'благодаря',
    'близо',
    'бъдат',
    'бъде',
    'бяха',
    'в',
    'вас',
    'ваш',
    'ваша',
    'вероятно',
    'вече',
    'взема',
    'ви',
    'вие',
    'винаги',
    'внимава',
    'време',
    'все',
    'всеки',
    'всички',
    'всичко',
    'всяка',
    'във',
    'въпреки',
    'върху',
    'г',
    'ги',
    'главен',
    'главна',
    'главно',
    'глас',
    'го',
    'година',
    'години',
    'годишен',
    'д',
    'да',
    'дали',
    'два',
    'двама',
    'двамата',
    'две',
    'двете',
    'ден',
    'днес',
    'дни',
    'до',
    'добра',
    'добре',
    'добро',
    'добър',
    'докато',
    'докога',
    'дори',
    'досега',
    'доста',
    'друг',
    'друга',
    'други',
    'е',
    'евтин',
    'едва',
    'един',
    'една',
    'еднаква',
    'еднакви',
    'еднакъв',
    'едно',
    'екип',
    'ето',
    'живот',
    'за',
    'забавям',
    'зад',
    'заедно',
    'заради',
    'засега',
    'заспал',
    'затова',
    'защо',
    'защото',
    'и',
    'из',
    'или',
    'им',
    'има',
    'имат',
    'иска',
    'й',
    'каза',
    'как',
    'каква',
    'какво',
    'както',
    'какъв',
    'като',
    'кога',
    'когато',
    'което',
    'които',
    'кой',
    'който',
    'колко',
    'която',
    'къде',
    'където',
    'към',
    'лесен',
    'лесно',
    'ли',
    'лош',
    'м',
    'май',
    'малко',
    'ме',
    'между',
    'мек',
    'мен',
    'месец',
    'ми',
    'много',
    'мнозина',
    'мога',
    'могат',
    'може',
    'мокър',
    'моля',
    'момента',
    'му',
    'н',
    'на',
    'над',
    'назад',
    'най',
    'направи',
    'напред',
    'например',
    'нас',
    'не',
    'него',
    'нещо',
    'нея',
    'ни',
    'ние',
    'никой',
    'нито',
    'нищо',
    'но',
    'нов',
    'нова',
    'нови',
    'новина',
    'някои',
    'някой',
    'няколко',
    'няма',
    'обаче',
    'около',
    'освен',
    'особено',
    'от',
    'отгоре',
    'отново',
    'още',
    'пак',
    'по',
    'повече',
    'повечето',
    'под',
    'поне',
    'поради',
    'после',
    'почти',
    'прави',
    'пред',
    'преди',
    'през',
    'при',
    'пък',
    'първата',
    'първи',
    'първо',
    'пъти',
    'равен',
    'равна',
    'с',
    'са',
    'сам',
    'само',
    'се',
    'сега',
    'си',
    'син',
    'скоро',
    'след',
    'следващ',
    'сме',
    'смях',
    'според',
    'сред',
    'срещу',
    'сте',
    'съм',
    'със',
    'също',
    'т',
    'тази',
    'така',
    'такива',
    'такъв',
    'там',
    'твой',
    'те',
    'тези',
    'ти',
    'т.н.',
    'то',
    'това',
    'тогава',
    'този',
    'той',
    'толкова',
    'точно',
    'три',
    'трябва',
    'тук',
    'тъй',
    'тя',
    'тях',
    'у',
    'утре',
    'харесва',
    'хиляди',
    'ч',
    'часа',
    'че',
    'често',
    'чрез',
    'ще',
    'щом',
    'юмрук',
    'я',
    'як',
];

$result =& $data;
unset($data);
return $result;
<?php

// catalan

static $data = [
    'og',
    'i',
    'jeg',
    'det',
    'at',
    'en',
    'den',
    'til',
    'er',
    'som',
    'på',
    'de',
    'med',
    'han',
    'af',
    'for',
    'ikke',
    'der',
    'var',
    'mig',
    'sig',
    'men',
    'et',
    'har',
    'om',
    'vi',
    'min',
    'havde',
    'ham',
    'hun',
    'nu',
    'over',
    'da',
    'fra',
    'du',
    'ud',
    'sin',
    'dem',
    'os',
    'op',
    'man',
    'hans',
    'hvor',
    'eller',
    'hvad',
    'skal',
    'selv',
    'her',
    'alle',
    'vil',
    'blev',
    'kunne',
    'ind',
    'når',
    'være',
    'dog',
    'noget',
    'ville',
    'jo',
    'deres',
    'efter',
    'ned',
    'skulle',
    'denne',
    'end',
    'dette',
    'mit',
    'også',
    'under',
    'have',
    'dig',
    'anden',
    'hende',
    'mine',
    'alt',
    'meget',
    'sit',
    'sine',
    'vor',
    'mod',
    'disse',
    'hvis',
    'din',
    'nogle',
    'hos',
    'blive',
    'mange',
    'ad',
    'bliver',
    'hendes',
    'været',
    'thi',
    'jer',
    'sådan',
];

$result =& $data;
unset($data);
return $result;
<?php

// czech

static $data = [
    'ačkoli',
    'ahoj',
    'ale',
    'anebo',
    'ano',
    'asi',
    'aspoň',
    'během',
    'bez',
    'beze',
    'blízko',
    'bohužel',
    'brzo',
    'bude',
    'budeme',
    'budeš',
    'budete',
    'budou',
    'budu',
    'byl',
    'byla',
    'byli',
    'bylo',
    'byly',
    'bys',
    'čau',
    'chce',
    'chceme',
    'chceš',
    'chcete',
    'chci',
    'chtějí',
    'chtít',
    'chut\'',
    'chuti',
    'co',
    'čtrnáct',
    'čtyři',
    'dál',
    'dále',
    'daleko',
    'děkovat',
    'děkujeme',
    'děkuji',
    'den',
    'deset',
    'devatenáct',
    'devět',
    'do',
    'dobrý',
    'docela',
    'dva',
    'dvacet',
    'dvanáct',
    'dvě',
    'hodně',
    'já',
    'jak',
    'jde',
    'je',
    'jeden',
    'jedenáct',
    'jedna',
    'jedno',
    'jednou',
    'jedou',
    'jeho',
    'její',
    'jejich',
    'jemu',
    'jen',
    'jenom',
    'ještě',
    'jestli',
    'jestliže',
    'jí',
    'jich',
    'jím',
    'jimi',
    'jinak',
    'jsem',
    'jsi',
    'jsme',
    'jsou',
    'jste',
    'kam',
    'kde',
    'kdo',
    'kdy',
    'když',
    'ke',
    'kolik',
    'kromě',
    'která',
    'které',
    'kteří',
    'který',
    'kvůli',
    'má',
    'mají',
    'málo',
    'mám',
    'máme',
    'máš',
    'máte',
    'mé',
    'mě',
    'mezi',
    'mí',
    'mít',
    'mně',
    'mnou',
    'moc',
    'mohl',
    'mohou',
    'moje',
    'moji',
    'možná',
    'můj',
    'musí',
    'může',
    'my',
    'na',
    'nad',
    'nade',
    'nám',
    'námi',
    'naproti',
    'nás',
    'náš',
    'naše',
    'naši',
    'ne',
    'ně',
    'nebo',
    'nebyl',
    'nebyla',
    'nebyli',
    'nebyly',
    'něco',
    'nedělá',
    'nedělají',
    'nedělám',
    'neděláme',
    'neděláš',
    'neděláte',
    'nějak',
    'nejsi',
    'někde',
    'někdo',
    'nemají',
    'nemáme',
    'nemáte',
    'neměl',
    'němu',
    'není',
    'nestačí',
    'nevadí',
    'než',
    'nic',
    'nich',
    'ním',
    'nimi',
    'nula',
    'od',
    'ode',
    'on',
    'ona',
    'oni',
    'ono',
    'ony',
    'osm',
    'osmnáct',
    'pak',
    'patnáct',
    'pět',
    'po',
    'pořád',
    'potom',
    'pozdě',
    'před',
    'přes',
    'přese',
    'pro',
    'proč',
    'prosím',
    'prostě',
    'proti',
    'protože',
    'rovně',
    'se',
    'sedm',
    'sedmnáct',
    'šest',
    'šestnáct',
    'skoro',
    'smějí',
    'smí',
    'snad',
    'spolu',
    'sta',
    'sté',
    'sto',
    'ta',
    'tady',
    'tak',
    'takhle',
    'taky',
    'tam',
    'tamhle',
    'tamhleto',
    'tamto',
    'tě',
    'tebe',
    'tebou',
    'ted\'',
    'tedy',
    'ten',
    'ti',
    'tisíc',
    'tisíce',
    'to',
    'tobě',
    'tohle',
    'toto',
    'třeba',
    'tři',
    'třináct',
    'trošku',
    'tvá',
    'tvé',
    'tvoje',
    'tvůj',
    'ty',
    'určitě',
    'už',
    'vám',
    'vámi',
    'vás',
    'váš',
    'vaše',
    'vaši',
    've',
    'večer',
    'vedle',
    'vlastně',
    'všechno',
    'všichni',
    'vůbec',
    'vy',
    'vždy',
    'za',
    'zač',
    'zatímco',
    'ze',
    'že',
];

$result =& $data;
unset($data);
return $result;
<?php

// danish

static $data = [
    'ad',
    'af',
    'aldrig',
    'alle',
    'alt',
    'anden',
    'andet',
    'andre',
    'at',
    'bare',
    'begge',
    'blev',
    'blive',
    'bliver',
    'da',
    'de',
    'dem',
    'den',
    'denne',
    'der',
    'deres',
    'det',
    'dette',
    'dig',
    'din',
    'dine',
    'disse',
    'dit',
    'dog',
    'du',
    'efter',
    'ej',
    'eller',
    'en',
    'end',
    'ene',
    'eneste',
    'enhver',
    'er',
    'et',
    'far',
    'fem',
    'fik',
    'fire',
    'flere',
    'fleste',
    'for',
    'fordi',
    'forrige',
    'fra',
    'få',
    'får',
    'før',
    'god',
    'godt',
    'ham',
    'han',
    'hans',
    'har',
    'havde',
    'have',
    'hej',
    'helt',
    'hende',
    'hendes',
    'her',
    'hos',
    'hun',
    'hvad',
    'hvem',
    'hver',
    'hvilken',
    'hvis',
    'hvor',
    'hvordan',
    'hvorfor',
    'hvornår',
    'i',
    'ikke',
    'ind',
    'ingen',
    'intet',
    'ja',
    'jeg',
    'jer',
    'jeres',
    'jo',
    'kan',
    'kom',
    'komme',
    'kommer',
    'kun',
    'kunne',
    'lad',
    'lav',
    'lidt',
    'lige',
    'lille',
    'man',
    'mand',
    'mange',
    'med',
    'meget',
    'men',
    'mens',
    'mere',
    'mig',
    'min',
    'mine',
    'mit',
    'mod',
    'må',
    'ned',
    'nej',
    'ni',
    'nogen',
    'noget',
    'nogle',
    'nu',
    'ny',
    'nyt',
    'når',
    'nær',
    'næste',
    'næsten',
    'og',
    'også',
    'okay',
    'om',
    'op',
    'os',
    'otte',
    'over',
    'på',
    'se',
    'seks',
    'selv',
    'ser',
    'ses',
    'sig',
    'sige',
    'sin',
    'sine',
    'sit',
    'skal',
    'skulle',
    'som',
    'stor',
    'store',
    'syv',
    'så',
    'sådan',
    'tag',
    'tage',
    'thi',
    'ti',
    'til',
    'to',
    'tre',
    'ud',
    'under',
    'var',
    'ved',
    'vi',
    'vil',
    'ville',
    'vor',
    'vores',
    'være',
    'været',
];

$result =& $data;
unset($data);
return $result;
<?php

// german

static $data = [
    'ab',
    'bei',
    'da',
    'deshalb',
    'ein',
    'für',
    'haben',
    'hier',
    'ich',
    'ja',
    'kann',
    'machen',
    'muesste',
    'nach',
    'oder',
    'seid',
    'sonst',
    'und',
    'vom',
    'wann',
    'wenn',
    'wie',
    'zu',
    'bin',
    'eines',
    'hat',
    'manche',
    'solches',
    'an',
    'anderm',
    'bis',
    'das',
    'deinem',
    'demselben',
    'dir',
    'doch',
    'einig',
    'er',
    'eurer',
    'hatte',
    'ihnen',
    'ihre',
    'ins',
    'jenen',
    'keinen',
    'manchem',
    'meinen',
    'nichts',
    'seine',
    'soll',
    'unserm',
    'welche',
    'werden',
    'wollte',
    'während',
    'alle',
    'allem',
    'allen',
    'aller',
    'alles',
    'als',
    'also',
    'am',
    'ander',
    'andere',
    'anderem',
    'anderen',
    'anderer',
    'anderes',
    'andern',
    'anderr',
    'anders',
    'auch',
    'auf',
    'aus',
    'bist',
    'bsp.',
    'daher',
    'damit',
    'dann',
    'dasselbe',
    'dazu',
    'daß',
    'dein',
    'deine',
    'deinen',
    'deiner',
    'deines',
    'dem',
    'den',
    'denn',
    'denselben',
    'der',
    'derer',
    'derselbe',
    'derselben',
    'des',
    'desselben',
    'dessen',
    'dich',
    'die',
    'dies',
    'diese',
    'dieselbe',
    'dieselben',
    'diesem',
    'diesen',
    'dieser',
    'dieses',
    'dort',
    'du',
    'durch',
    'eine',
    'einem',
    'einen',
    'einer',
    'einige',
    'einigem',
    'einigen',
    'einiger',
    'einiges',
    'einmal',
    'es',
    'etwas',
    'euch',
    'euer',
    'eure',
    'eurem',
    'euren',
    'eures',
    'ganz',
    'ganze',
    'ganzen',
    'ganzer',
    'ganzes',
    'gegen',
    'gemacht',
    'gesagt',
    'gesehen',
    'gewesen',
    'gewollt',
    'hab',
    'habe',
    'hatten',
    'hin',
    'hinter',
    'ihm',
    'ihn',
    'ihr',
    'ihrem',
    'ihren',
    'ihrer',
    'ihres',
    'im',
    'in',
    'indem',
    'ist',
    'jede',
    'jedem',
    'jeden',
    'jeder',
    'jedes',
    'jene',
    'jenem',
    'jener',
    'jenes',
    'jetzt',
    'kein',
    'keine',
    'keinem',
    'keiner',
    'keines',
    'konnte',
    'können',
    'könnte',
    'mache',
    'machst',
    'macht',
    'machte',
    'machten',
    'man',
    'manchen',
    'mancher',
    'manches',
    'mein',
    'meine',
    'meinem',
    'meiner',
    'meines',
    'mich',
    'mir',
    'mit',
    'muss',
    'musste',
    'müßt',
    'nicht',
    'noch',
    'nun',
    'nur',
    'ob',
    'ohne',
    'sage',
    'sagen',
    'sagt',
    'sagte',
    'sagten',
    'sagtest',
    'sehe',
    'sehen',
    'sehr',
    'seht',
    'sein',
    'seinem',
    'seinen',
    'seiner',
    'seines',
    'selbst',
    'sich',
    'sicher',
    'sie',
    'sind',
    'so',
    'solche',
    'solchem',
    'solchen',
    'solcher',
    'sollte',
    'sondern',
    'um',
    'uns',
    'unse',
    'unsen',
    'unser',
    'unses',
    'unter',
    'viel',
    'von',
    'vor',
    'war',
    'waren',
    'warst',
    'was',
    'weg',
    'weil',
    'weiter',
    'welchem',
    'welchen',
    'welcher',
    'welches',
    'werde',
    'wieder',
    'will',
    'wir',
    'wird',
    'wirst',
    'wo',
    'wolle',
    'wollen',
    'wollt',
    'wollten',
    'wolltest',
    'wolltet',
    'würde',
    'würden',
    'z.B.',
    'zum',
    'zur',
    'zwar',
    'zwischen',
    'über',
    'aber',
    'abgerufen',
    'abgerufene',
    'abgerufener',
    'abgerufenes',
    'acht',
    'acute',
    'allein',
    'allerdings',
    'allerlei',
    'allg',
    'allgemein',
    'allmählich',
    'allzu',
    'alsbald',
    'amp',
    'and',
    'andererseits',
    'andernfalls',
    'anerkannt',
    'anerkannte',
    'anerkannter',
    'anerkanntes',
    'anfangen',
    'anfing',
    'angefangen',
    'angesetze',
    'angesetzt',
    'angesetzten',
    'angesetzter',
    'ansetzen',
    'anstatt',
    'arbeiten',
    'aufgehört',
    'aufgrund',
    'aufhören',
    'aufhörte',
    'aufzusuchen',
    'ausdrücken',
    'ausdrückt',
    'ausdrückte',
    'ausgenommen',
    'ausser',
    'ausserdem',
    'author',
    'autor',
    'außen',
    'außer',
    'außerdem',
    'außerhalb',
    'background',
    'bald',
    'bearbeite',
    'bearbeiten',
    'bearbeitete',
    'bearbeiteten',
    'bedarf',
    'bedurfte',
    'bedürfen',
    'been',
    'befragen',
    'befragte',
    'befragten',
    'befragter',
    'begann',
    'beginnen',
    'begonnen',
    'behalten',
    'behielt',
    'beide',
    'beiden',
    'beiderlei',
    'beides',
    'beim',
    'beinahe',
    'beitragen',
    'beitrugen',
    'bekannt',
    'bekannte',
    'bekannter',
    'bekennen',
    'benutzt',
    'bereits',
    'berichten',
    'berichtet',
    'berichtete',
    'berichteten',
    'besonders',
    'besser',
    'bestehen',
    'besteht',
    'beträchtlich',
    'bevor',
    'bezüglich',
    'bietet',
    'bisher',
    'bislang',
    'biz',
    'bleiben',
    'blieb',
    'bloss',
    'bloß',
    'border',
    'brachte',
    'brachten',
    'brauchen',
    'braucht',
    'bringen',
    'bräuchte',
    'bzw',
    'böden',
    'ca',
    'ca.',
    'collapsed',
    'com',
    'comment',
    'content',
    'da?',
    'dabei',
    'dadurch',
    'dafür',
    'dagegen',
    'dahin',
    'damals',
    'danach',
    'daneben',
    'dank',
    'danke',
    'danken',
    'dannen',
    'daran',
    'darauf',
    'daraus',
    'darf',
    'darfst',
    'darin',
    'darum',
    'darunter',
    'darüber',
    'darüberhinaus',
    'dass',
    'davon',
    'davor',
    'demnach',
    'denen',
    'dennoch',
    'derart',
    'derartig',
    'derem',
    'deren',
    'derjenige',
    'derjenigen',
    'derzeit',
    'desto',
    'deswegen',
    'diejenige',
    'diesseits',
    'dinge',
    'direkt',
    'direkte',
    'direkten',
    'direkter',
    'doc',
    'doppelt',
    'dorther',
    'dorthin',
    'drauf',
    'drei',
    'dreißig',
    'drin',
    'dritte',
    'drunter',
    'drüber',
    'dunklen',
    'durchaus',
    'durfte',
    'durften',
    'dürfen',
    'dürfte',
    'eben',
    'ebenfalls',
    'ebenso',
    'ehe',
    'eher',
    'eigenen',
    'eigenes',
    'eigentlich',
    'einbaün',
    'einerseits',
    'einfach',
    'einführen',
    'einführte',
    'einführten',
    'eingesetzt',
    'einigermaßen',
    'eins',
    'einseitig',
    'einseitige',
    'einseitigen',
    'einseitiger',
    'einst',
    'einstmals',
    'einzig',
    'elf',
    'ende',
    'entsprechend',
    'entweder',
    'ergänze',
    'ergänzen',
    'ergänzte',
    'ergänzten',
    'erhalten',
    'erhielt',
    'erhielten',
    'erhält',
    'erneut',
    'erst',
    'erste',
    'ersten',
    'erster',
    'eröffne',
    'eröffnen',
    'eröffnet',
    'eröffnete',
    'eröffnetes',
    'etc',
    'etliche',
    'etwa',
    'fall',
    'falls',
    'fand',
    'fast',
    'ferner',
    'finden',
    'findest',
    'findet',
    'folgende',
    'folgenden',
    'folgender',
    'folgendes',
    'folglich',
    'for',
    'fordern',
    'fordert',
    'forderte',
    'forderten',
    'fortsetzen',
    'fortsetzt',
    'fortsetzte',
    'fortsetzten',
    'fragte',
    'frau',
    'frei',
    'freie',
    'freier',
    'freies',
    'fuer',
    'fünf',
    'gab',
    'ganzem',
    'gar',
    'gbr',
    'geb',
    'geben',
    'geblieben',
    'gebracht',
    'gedurft',
    'geehrt',
    'geehrte',
    'geehrten',
    'geehrter',
    'gefallen',
    'gefiel',
    'gefälligst',
    'gefällt',
    'gegeben',
    'gehabt',
    'gehen',
    'geht',
    'gekommen',
    'gekonnt',
    'gemocht',
    'gemäss',
    'genommen',
    'genug',
    'gern',
    'gestern',
    'gestrige',
    'getan',
    'geteilt',
    'geteilte',
    'getragen',
    'gewissermaßen',
    'geworden',
    'ggf',
    'gib',
    'gibt',
    'gleich',
    'gleichwohl',
    'gleichzeitig',
    'glücklicherweise',
    'gmbh',
    'gratulieren',
    'gratuliert',
    'gratulierte',
    'gute',
    'guten',
    'gängig',
    'gängige',
    'gängigen',
    'gängiger',
    'gängiges',
    'gänzlich',
    'haette',
    'halb',
    'hallo',
    'hast',
    'hattest',
    'hattet',
    'heraus',
    'herein',
    'heute',
    'heutige',
    'hiermit',
    'hiesige',
    'hinein',
    'hinten',
    'hinterher',
    'hoch',
    'html',
    'http',
    'hundert',
    'hätt',
    'hätte',
    'hätten',
    'höchstens',
    'igitt',
    'image',
    'immer',
    'immerhin',
    'important',
    'indessen',
    'info',
    'infolge',
    'innen',
    'innerhalb',
    'insofern',
    'inzwischen',
    'irgend',
    'irgendeine',
    'irgendwas',
    'irgendwen',
    'irgendwer',
    'irgendwie',
    'irgendwo',
    'je',
    'jed',
    'jedenfalls',
    'jederlei',
    'jedoch',
    'jemand',
    'jenseits',
    'jährig',
    'jährige',
    'jährigen',
    'jähriges',
    'kam',
    'kannst',
    'kaum',
    'kei nes',
    'keinerlei',
    'keineswegs',
    'klar',
    'klare',
    'klaren',
    'klares',
    'klein',
    'kleinen',
    'kleiner',
    'kleines',
    'koennen',
    'koennt',
    'koennte',
    'koennten',
    'komme',
    'kommen',
    'kommt',
    'konkret',
    'konkrete',
    'konkreten',
    'konkreter',
    'konkretes',
    'konnten',
    'könn',
    'könnt',
    'könnten',
    'künftig',
    'lag',
    'lagen',
    'langsam',
    'lassen',
    'laut',
    'lediglich',
    'leer',
    'legen',
    'legte',
    'legten',
    'leicht',
    'leider',
    'lesen',
    'letze',
    'letzten',
    'letztendlich',
    'letztens',
    'letztes',
    'letztlich',
    'lichten',
    'liegt',
    'liest',
    'links',
    'längst',
    'längstens',
    'mag',
    'magst',
    'mal',
    'mancherorts',
    'manchmal',
    'mann',
    'margin',
    'med',
    'mehr',
    'mehrere',
    'meist',
    'meiste',
    'meisten',
    'meta',
    'mindestens',
    'mithin',
    'mochte',
    'morgen',
    'morgige',
    'muessen',
    'muesst',
    'musst',
    'mussten',
    'muß',
    'mußt',
    'möchte',
    'möchten',
    'möchtest',
    'mögen',
    'möglich',
    'mögliche',
    'möglichen',
    'möglicher',
    'möglicherweise',
    'müssen',
    'müsste',
    'müssten',
    'müßte',
    'nachdem',
    'nacher',
    'nachhinein',
    'nahm',
    'natürlich',
    'ncht',
    'neben',
    'nebenan',
    'nehmen',
    'nein',
    'neu',
    'neue',
    'neuem',
    'neuen',
    'neuer',
    'neues',
    'neun',
    'nie',
    'niemals',
    'niemand',
    'nimm',
    'nimmer',
    'nimmt',
    'nirgends',
    'nirgendwo',
    'nter',
    'nutzen',
    'nutzt',
    'nutzung',
    'nächste',
    'nämlich',
    'nötigenfalls',
    'nützt',
    'oben',
    'oberhalb',
    'obgleich',
    'obschon',
    'obwohl',
    'oft',
    'online',
    'org',
    'padding',
    'per',
    'pfui',
    'plötzlich',
    'pro',
    'reagiere',
    'reagieren',
    'reagiert',
    'reagierte',
    'rechts',
    'regelmäßig',
    'rief',
    'rund',
    'sang',
    'sangen',
    'schlechter',
    'schließlich',
    'schnell',
    'schon',
    'schreibe',
    'schreiben',
    'schreibens',
    'schreiber',
    'schwierig',
    'schätzen',
    'schätzt',
    'schätzte',
    'schätzten',
    'sechs',
    'sect',
    'sehrwohl',
    'sei',
    'seit',
    'seitdem',
    'seite',
    'seiten',
    'seither',
    'selber',
    'senke',
    'senken',
    'senkt',
    'senkte',
    'senkten',
    'setzen',
    'setzt',
    'setzte',
    'setzten',
    'sicherlich',
    'sieben',
    'siebte',
    'siehe',
    'sieht',
    'singen',
    'singt',
    'sobald',
    'sodaß',
    'soeben',
    'sofern',
    'sofort',
    'sog',
    'sogar',
    'solange',
    'solc hen',
    'solch',
    'sollen',
    'sollst',
    'sollt',
    'sollten',
    'solltest',
    'somit',
    'sonstwo',
    'sooft',
    'soviel',
    'soweit',
    'sowie',
    'sowohl',
    'spielen',
    'später',
    'startet',
    'startete',
    'starteten',
    'statt',
    'stattdessen',
    'steht',
    'steige',
    'steigen',
    'steigt',
    'stets',
    'stieg',
    'stiegen',
    'such',
    'suchen',
    'sämtliche',
    'tages',
    'tat',
    'tatsächlich',
    'tatsächlichen',
    'tatsächlicher',
    'tatsächliches',
    'tausend',
    'teile',
    'teilen',
    'teilte',
    'teilten',
    'titel',
    'total',
    'trage',
    'tragen',
    'trotzdem',
    'trug',
    'trägt',
    'tun',
    'tust',
    'tut',
    'txt',
    'tät',
    'ueber',
    'umso',
    'unbedingt',
    'ungefähr',
    'unmöglich',
    'unmögliche',
    'unmöglichen',
    'unmöglicher',
    'unnötig',
    'unsem',
    'unser',
    'unsere',
    'unserem',
    'unseren',
    'unserer',
    'unseres',
    'unten',
    'unterbrach',
    'unterbrechen',
    'unterhalb',
    'unwichtig',
    'usw',
    'var',
    'vergangen',
    'vergangene',
    'vergangener',
    'vergangenes',
    'vermag',
    'vermutlich',
    'vermögen',
    'verrate',
    'verraten',
    'verriet',
    'verrieten',
    'version',
    'versorge',
    'versorgen',
    'versorgt',
    'versorgte',
    'versorgten',
    'versorgtes',
    'veröffentlichen',
    'veröffentlicher',
    'veröffentlicht',
    'veröffentlichte',
    'veröffentlichten',
    'veröffentlichtes',
    'viele',
    'vielen',
    'vieler',
    'vieles',
    'vielleicht',
    'vielmals',
    'vier',
    'vollständig',
    'voran',
    'vorbei',
    'vorgestern',
    'vorher',
    'vorne',
    'vorüber',
    'völlig',
    'während',
    'wachen',
    'waere',
    'warum',
    'weder',
    'wegen',
    'weitere',
    'weiterem',
    'weiteren',
    'weiterer',
    'weiteres',
    'weiterhin',
    'weiß',
    'wem',
    'wen',
    'wenig',
    'wenige',
    'weniger',
    'wenigstens',
    'wenngleich',
    'wer',
    'werdet',
    'weshalb',
    'wessen',
    'wichtig',
    'wieso',
    'wieviel',
    'wiewohl',
    'willst',
    'wirklich',
    'wodurch',
    'wogegen',
    'woher',
    'wohin',
    'wohingegen',
    'wohl',
    'wohlweislich',
    'womit',
    'woraufhin',
    'woraus',
    'worin',
    'wurde',
    'wurden',
    'währenddessen',
    'wär',
    'wäre',
    'wären',
    'zahlreich',
    'zehn',
    'zeitweise',
    'ziehen',
    'zieht',
    'zog',
    'zogen',
    'zudem',
    'zuerst',
    'zufolge',
    'zugleich',
    'zuletzt',
    'zumal',
    'zurück',
    'zusammen',
    'zuviel',
    'zwanzig',
    'zwei',
    'zwölf',
    'ähnlich',
    'übel',
    'überall',
    'überallhin',
    'überdies',
    'übermorgen',
    'übrig',
    'übrigens',
];

$result =& $data;
unset($data);
return $result;
<?php

// greek

static $data = [
    'αλλα',
    'αν',
    'αντι',
    'απο',
    'αυτα',
    'αυτεσ',
    'αυτη',
    'αυτο',
    'αυτοι',
    'αυτοσ',
    'αυτουσ',
    'αυτων',
    'αἱ',
    'αἳ',
    'αἵ',
    'αὐτόσ',
    'αὐτὸς',
    'αὖ',
    'γάρ',
    'γα',
    'γα^',
    'γε',
    'για',
    'γοῦν',
    'γὰρ',
    'δ\'',
    'δέ',
    'δή',
    'δαί',
    'δαίσ',
    'δαὶ',
    'δαὶς',
    'δε',
    'δεν',
    'δι\'',
    'διά',
    'διὰ',
    'δὲ',
    'δὴ',
    'δ’',
    'εαν',
    'ειμαι',
    'ειμαστε',
    'ειναι',
    'εισαι',
    'ειστε',
    'εκεινα',
    'εκεινεσ',
    'εκεινη',
    'εκεινο',
    'εκεινοι',
    'εκεινοσ',
    'εκεινουσ',
    'εκεινων',
    'ενω',
    'επ',
    'επι',
    'εἰ',
    'εἰμί',
    'εἰμὶ',
    'εἰς',
    'εἰσ',
    'εἴ',
    'εἴμι',
    'εἴτε',
    'η',
    'θα',
    'ισωσ',
    'κ',
    'καί',
    'καίτοι',
    'καθ',
    'και',
    'κατ',
    'κατά',
    'κατα',
    'κατὰ',
    'καὶ',
    'κι',
    'κἀν',
    'κἂν',
    'μέν',
    'μή',
    'μήτε',
    'μα',
    'με',
    'μεθ',
    'μετ',
    'μετά',
    'μετα',
    'μετὰ',
    'μη',
    'μην',
    'μἐν',
    'μὲν',
    'μὴ',
    'μὴν',
    'να',
    'ο',
    'οι',
    'ομωσ',
    'οπωσ',
    'οσο',
    'οτι',
    'οἱ',
    'οἳ',
    'οἷς',
    'οὐ',
    'οὐδ',
    'οὐδέ',
    'οὐδείσ',
    'οὐδεὶς',
    'οὐδὲ',
    'οὐδὲν',
    'οὐκ',
    'οὐχ',
    'οὐχὶ',
    'οὓς',
    'οὔτε',
    'οὕτω',
    'οὕτως',
    'οὕτωσ',
    'οὖν',
    'οὗ',
    'οὗτος',
    'οὗτοσ',
    'παρ',
    'παρά',
    'παρα',
    'παρὰ',
    'περί',
    'περὶ',
    'ποια',
    'ποιεσ',
    'ποιο',
    'ποιοι',
    'ποιοσ',
    'ποιουσ',
    'ποιων',
    'ποτε',
    'που',
    'ποῦ',
    'προ',
    'προσ',
    'πρόσ',
    'πρὸ',
    'πρὸς',
    'πως',
    'πωσ',
    'σε',
    'στη',
    'στην',
    'στο',
    'στον',
    'σόσ',
    'σύ',
    'σύν',
    'σὸς',
    'σὺ',
    'σὺν',
    'τά',
    'τήν',
    'τί',
    'τίς',
    'τίσ',
    'τα',
    'ταῖς',
    'τε',
    'την',
    'τησ',
    'τι',
    'τινα',
    'τις',
    'τισ',
    'το',
    'τοί',
    'τοι',
    'τοιοῦτος',
    'τοιοῦτοσ',
    'τον',
    'τοτε',
    'του',
    'τούσ',
    'τοὺς',
    'τοῖς',
    'τοῦ',
    'των',
    'τό',
    'τόν',
    'τότε',
    'τὰ',
    'τὰς',
    'τὴν',
    'τὸ',
    'τὸν',
    'τῆς',
    'τῆσ',
    'τῇ',
    'τῶν',
    'τῷ',
    'ωσ',
    'ἀλλ\'',
    'ἀλλά',
    'ἀλλὰ',
    'ἀλλ’',
    'ἀπ',
    'ἀπό',
    'ἀπὸ',
    'ἀφ',
    'ἂν',
    'ἃ',
    'ἄλλος',
    'ἄλλοσ',
    'ἄν',
    'ἄρα',
    'ἅμα',
    'ἐάν',
    'ἐγώ',
    'ἐγὼ',
    'ἐκ',
    'ἐμόσ',
    'ἐμὸς',
    'ἐν',
    'ἐξ',
    'ἐπί',
    'ἐπεὶ',
    'ἐπὶ',
    'ἐστι',
    'ἐφ',
    'ἐὰν',
    'ἑαυτοῦ',
    'ἔτι',
    'ἡ',
    'ἢ',
    'ἣ',
    'ἤ',
    'ἥ',
    'ἧς',
    'ἵνα',
    'ὁ',
    'ὃ',
    'ὃν',
    'ὃς',
    'ὅ',
    'ὅδε',
    'ὅθεν',
    'ὅπερ',
    'ὅς',
    'ὅσ',
    'ὅστις',
    'ὅστισ',
    'ὅτε',
    'ὅτι',
    'ὑμόσ',
    'ὑπ',
    'ὑπέρ',
    'ὑπό',
    'ὑπὲρ',
    'ὑπὸ',
    'ὡς',
    'ὡσ',
    'ὥς',
    'ὥστε',
    'ὦ',
    'ᾧ',
];

$result =& $data;
unset($data);
return $result;
<?php

// english

static $data = [
    'a',
    'about',
    'above',
    'above',
    'across',
    'after',
    'afterwards',
    'again',
    'against',
    'all',
    'almost',
    'alone',
    'along',
    'already',
    'also',
    'although',
    'always',
    'am',
    'among',
    'amongst',
    'amoungst',
    'amount',
    'an',
    'and',
    'another',
    'any',
    'anyhow',
    'anyone',
    'anything',
    'anyway',
    'anywhere',
    'are',
    'around',
    'as',
    'at',
    'back',
    'be',
    'became',
    'because',
    'become',
    'becomes',
    'becoming',
    'been',
    'before',
    'beforehand',
    'behind',
    'being',
    'below',
    'beside',
    'besides',
    'between',
    'beyond',
    'bill',
    'both',
    'bottom',
    'but',
    'by',
    'call',
    'can',
    'cannot',
    'cant',
    'co',
    'con',
    'could',
    'couldnt',
    'cry',
    'de',
    'describe',
    'detail',
    'do',
    'done',
    'down',
    'due',
    'during',
    'each',
    'eg',
    'eight',
    'either',
    'eleven',
    'else',
    'elsewhere',
    'empty',
    'enough',
    'etc',
    'even',
    'ever',
    'every',
    'everyone',
    'everything',
    'everywhere',
    'except',
    'few',
    'fifteen',
    'fify',
    'fill',
    'find',
    'fire',
    'first',
    'five',
    'for',
    'former',
    'formerly',
    'forty',
    'found',
    'four',
    'from',
    'front',
    'full',
    'further',
    'get',
    'give',
    'go',
    'had',
    'has',
    'hasnt',
    'have',
    'he',
    'hence',
    'her',
    'here',
    'hereafter',
    'hereby',
    'herein',
    'hereupon',
    'hers',
    'herself',
    'him',
    'himself',
    'his',
    'how',
    'however',
    'hundred',
    'ie',
    'if',
    'in',
    'inc',
    'indeed',
    'interest',
    'into',
    'is',
    'it',
    'its',
    'itself',
    'keep',
    'last',
    'latter',
    'latterly',
    'least',
    'less',
    'ltd',
    'made',
    'many',
    'may',
    'me',
    'meanwhile',
    'might',
    'mill',
    'mine',
    'more',
    'moreover',
    'most',
    'mostly',
    'move',
    'much',
    'must',
    'my',
    'myself',
    'name',
    'namely',
    'neither',
    'never',
    'nevertheless',
    'next',
    'nine',
    'no',
    'nobody',
    'none',
    'noone',
    'nor',
    'not',
    'nothing',
    'now',
    'nowhere',
    'of',
    'off',
    'often',
    'on',
    'once',
    'one',
    'only',
    'onto',
    'or',
    'other',
    'others',
    'otherwise',
    'our',
    'ours',
    'ourselves',
    'out',
    'over',
    'own',
    'part',
    'per',
    'perhaps',
    'please',
    'put',
    'rather',
    're',
    'same',
    'see',
    'seem',
    'seemed',
    'seeming',
    'seems',
    'serious',
    'several',
    'she',
    'should',
    'show',
    'side',
    'since',
    'sincere',
    'six',
    'sixty',
    'so',
    'some',
    'somehow',
    'someone',
    'something',
    'sometime',
    'sometimes',
    'somewhere',
    'still',
    'such',
    'system',
    'take',
    'ten',
    'than',
    'that',
    'the',
    'their',
    'them',
    'themselves',
    'then',
    'thence',
    'there',
    'thereafter',
    'thereby',
    'therefore',
    'therein',
    'thereupon',
    'these',
    'they',
    'thickv',
    'thin',
    'third',
    'this',
    'those',
    'though',
    'three',
    'through',
    'throughout',
    'thru',
    'thus',
    'to',
    'together',
    'too',
    'top',
    'toward',
    'towards',
    'twelve',
    'twenty',
    'two',
    'un',
    'under',
    'until',
    'up',
    'upon',
    'us',
    'very',
    'via',
    'was',
    'we',
    'well',
    'were',
    'what',
    'whatever',
    'when',
    'whence',
    'whenever',
    'where',
    'whereafter',
    'whereas',
    'whereby',
    'wherein',
    'whereupon',
    'wherever',
    'whether',
    'which',
    'while',
    'whither',
    'who',
    'whoever',
    'whole',
    'whom',
    'whose',
    'why',
    'will',
    'with',
    'within',
    'without',
    'would',
    'yet',
    'you',
    'your',
    'yours',
    'yourself',
    'yourselves',
    'the',
];

$result =& $data;
unset($data);
return $result;
<?php

// esperanto

static $data = [
    'adiaŭ',
    'ajn',
    'al',
    'ankoraŭ',
    'antaŭ',
    'aŭ',
    'bonan',
    'bonvole',
    'bonvolu',
    'bv',
    'ci',
    'cia',
    'cian',
    'cin',
    'd-ro',
    'da',
    'de',
    'dek',
    'deka',
    'do',
    'doktor\'',
    'doktoro',
    'du',
    'dua',
    'dum',
    'eble',
    'ekz',
    'ekzemple',
    'en',
    'estas',
    'estis',
    'estos',
    'estu',
    'estus',
    'eĉ',
    'f-no',
    'feliĉan',
    'for',
    'fraŭlino',
    'ha',
    'havas',
    'havis',
    'havos',
    'havu',
    'havus',
    'he',
    'ho',
    'hu',
    'ili',
    'ilia',
    'ilian',
    'ilin',
    'inter',
    'io',
    'ion',
    'iu',
    'iujn',
    'iun',
    'ja',
    'jam',
    'je',
    'jes',
    'k',
    'kaj',
    'ke',
    'kio',
    'kion',
    'kiu',
    'kiujn',
    'kiun',
    'kvankam',
    'kvar',
    'kvara',
    'kvazaŭ',
    'kvin',
    'kvina',
    'la',
    'li',
    'lia',
    'lian',
    'lin',
    'malantaŭ',
    'male',
    'malgraŭ',
    'mem',
    'mi',
    'mia',
    'mian',
    'min',
    'minus',
    'naŭ',
    'naŭa',
    'ne',
    'nek',
    'nenio',
    'nenion',
    'neniu',
    'neniun',
    'nepre',
    'ni',
    'nia',
    'nian',
    'nin',
    'nu',
    'nun',
    'nur',
    'ok',
    'oka',
    'oni',
    'onia',
    'onian',
    'onin',
    'plej',
    'pli',
    'plu',
    'plus',
    'por',
    'post',
    'preter',
    's-no',
    's-ro',
    'se',
    'sed',
    'sep',
    'sepa',
    'ses',
    'sesa',
    'si',
    'sia',
    'sian',
    'sin',
    'sinjor\'',
    'sinjorino',
    'sinjoro',
    'sub',
    'super',
    'supren',
    'sur',
    'tamen',
    'tio',
    'tion',
    'tiu',
    'tiujn',
    'tiun',
    'tra',
    'tri',
    'tria',
    'tuj',
    'tute',
    'unu',
    'unua',
    've',
    'verŝajne',
    'vi',
    'via',
    'vian',
    'vin',
    'ĉi',
    'ĉio',
    'ĉion',
    'ĉiu',
    'ĉiujn',
    'ĉiun',
    'ĉu',
    'ĝi',
    'ĝia',
    'ĝian',
    'ĝin',
    'ĝis',
    'ĵus',
    'ŝi',
    'ŝia',
    'ŝin',
];

$result =& $data;
unset($data);
return $result;
<?php

// spanish

static $data = [
    'de',
    'la',
    'que',
    'el',
    'en',
    'y',
    'a',
    'los',
    'del',
    'se',
    'las',
    'por',
    'un',
    'para',
    'con',
    'no',
    'una',
    'su',
    'al',
    'lo',
    'como',
    'más',
    'pero',
    'sus',
    'le',
    'ya',
    'o',
    'este',
    'sí',
    'porque',
    'esta',
    'entre',
    'cuando',
    'muy',
    'sin',
    'sobre',
    'también',
    'me',
    'hasta',
    'hay',
    'donde',
    'quien',
    'desde',
    'todo',
    'nos',
    'durante',
    'todos',
    'uno',
    'les',
    'ni',
    'contra',
    'otros',
    'ese',
    'eso',
    'ante',
    'ellos',
    'e',
    'esto',
    'mí',
    'antes',
    'algunos',
    'qué',
    'unos',
    'yo',
    'otro',
    'otras',
    'otra',
    'él',
    'tanto',
    'esa',
    'estos',
    'mucho',
    'quienes',
    'nada',
    'muchos',
    'cual',
    'poco',
    'ella',
    'estar',
    'estas',
    'algunas',
    'algo',
    'nosotros',
    'mi',
    'mis',
    'tú',
    'te',
    'ti',
    'tu',
    'tus',
    'ellas',
    'nosotras',
    'vosostros',
    'vosostras',
    'os',
    'mío',
    'mía',
    'míos',
    'mías',
    'tuyo',
    'tuya',
    'tuyos',
    'tuyas',
    'suyo',
    'suya',
    'suyos',
    'suyas',
    'nuestro',
    'nuestra',
    'nuestros',
    'nuestras',
    'vuestro',
    'vuestra',
    'vuestros',
    'vuestras',
    'esos',
    'esas',
    'estoy',
    'estás',
    'está',
    'estamos',
    'estáis',
    'están',
    'esté',
    'estés',
    'estemos',
    'estéis',
    'estén',
    'estaré',
    'estarás',
    'estará',
    'estaremos',
    'estaréis',
    'estarán',
    'estaría',
    'estarías',
    'estaríamos',
    'estaríais',
    'estarían',
    'estaba',
    'estabas',
    'estábamos',
    'estabais',
    'estaban',
    'estuve',
    'estuviste',
    'estuvo',
    'estuvimos',
    'estuvisteis',
    'estuvieron',
    'estuviera',
    'estuvieras',
    'estuviéramos',
    'estuvierais',
    'estuvieran',
    'estuviese',
    'estuvieses',
    'estuviésemos',
    'estuvieseis',
    'estuviesen',
    'estando',
    'estado',
    'estada',
    'estados',
    'estadas',
    'estad',
    'he',
    'has',
    'ha',
    'hemos',
    'habéis',
    'han',
    'haya',
    'hayas',
    'hayamos',
    'hayáis',
    'hayan',
    'habré',
    'habrás',
    'habrá',
    'habremos',
    'habréis',
    'habrán',
    'habría',
    'habrías',
    'habríamos',
    'habríais',
    'habrían',
    'había',
    'habías',
    'habíamos',
    'habíais',
    'habían',
    'hube',
    'hubiste',
    'hubo',
    'hubimos',
    'hubisteis',
    'hubieron',
    'hubiera',
    'hubieras',
    'hubiéramos',
    'hubierais',
    'hubieran',
    'hubiese',
    'hubieses',
    'hubiésemos',
    'hubieseis',
    'hubiesen',
    'habiendo',
    'habido',
    'habida',
    'habidos',
    'habidas',
    'soy',
    'eres',
    'es',
    'somos',
    'sois',
    'son',
    'sea',
    'seas',
    'seamos',
    'seáis',
    'sean',
    'seré',
    'serás',
    'será',
    'seremos',
    'seréis',
    'serán',
    'sería',
    'serías',
    'seríamos',
    'seríais',
    'serían',
    'era',
    'eras',
    'éramos',
    'erais',
    'eran',
    'fui',
    'fuiste',
    'fue',
    'fuimos',
    'fuisteis',
    'fueron',
    'fuera',
    'fueras',
    'fuéramos',
    'fuerais',
    'fueran',
    'fuese',
    'fueses',
    'fuésemos',
    'fueseis',
    'fuesen',
    'sintiendo',
    'sentido',
    'sentida',
    'sentidos',
    'sentidas',
    'siente',
    'sentid',
    'tengo',
    'tienes',
    'tiene',
    'tenemos',
    'tenéis',
    'tienen',
    'tenga',
    'tengas',
    'tengamos',
    'tengáis',
    'tengan',
    'tendré',
    'tendrás',
    'tendrá',
    'tendremos',
    'tendréis',
    'tendrán',
    'tendría',
    'tendrías',
    'tendríamos',
    'tendríais',
    'tendrían',
    'tenía',
    'tenías',
    'teníamos',
    'teníais',
    'tenían',
    'tuve',
    'tuviste',
    'tuvo',
    'tuvimos',
    'tuvisteis',
    'tuvieron',
    'tuviera',
    'tuvieras',
    'tuviéramos',
    'tuvierais',
    'tuvieran',
    'tuviese',
    'tuvieses',
    'tuviésemos',
    'tuvieseis',
    'tuviesen',
    'teniendo',
    'tenido',
    'tenida',
    'tenidos',
    'tenidas',
    'tened',
];

$result =& $data;
unset($data);
return $result;
<?php

// estonian

static $data = [
    'aga',
    'ei',
    'et',
    'ja',
    'jah',
    'kas',
    'kui',
    'kõik',
    'ma',
    'me',
    'mida',
    'midagi',
    'mind',
    'minu',
    'mis',
    'mu',
    'mul',
    'mulle',
    'nad',
    'nii',
    'oled',
    'olen',
    'oli',
    'oma',
    'on',
    'pole',
    'sa',
    'seda',
    'see',
    'selle',
    'siin',
    'siis',
    'ta',
    'te',
    'ära',
];

$result =& $data;
unset($data);
return $result;
<?php

// finnish

static $data = [
    'olla',
    'olen',
    'olet',
    'on',
    'olemme',
    'olette',
    'ovat',
    'ole',
    'oli',
    'olisi',
    'olisit',
    'olisin',
    'olisimme',
    'olisitte',
    'olisivat',
    'olit',
    'olin',
    'olimme',
    'olitte',
    'olivat',
    'ollut',
    'olleet',
    'en',
    'et',
    'ei',
    'emme',
    'ette',
    'eivät',
    'minä',
    'minun',
    'minut',
    'minua',
    'minussa',
    'minusta',
    'minuun',
    'minulla',
    'minulta',
    'minulle',
    'sinä',
    'sinun',
    'sinut',
    'sinua',
    'sinussa',
    'sinusta',
    'sinuun',
    'sinulla',
    'sinulta',
    'sinulle',
    'hän',
    'hänen',
    'hänet',
    'häntä',
    'hänessä',
    'hänestä',
    'häneen',
    'hänellä',
    'häneltä',
    'hänelle',
    'me',
    'meidän',
    'meidät',
    'meitä',
    'meissä',
    'meistä',
    'meihin',
    'meillä',
    'meiltä',
    'meille',
    'te',
    'teidän',
    'teidät',
    'teitä',
    'teissä',
    'teistä',
    'teihin',
    'teillä',
    'teiltä',
    'teille',
    'he',
    'heidän',
    'heidät',
    'heitä',
    'heissä',
    'heistä',
    'heihin',
    'heillä',
    'heiltä',
    'heille',
    'tämä',
    'tämän',
    'tätä',
    'tässä',
    'tästä',
    'tähän',
    'tallä',
    'tältä',
    'tälle',
    'tänä',
    'täksi',
    'tuo',
    'tuon',
    'tuotä',
    'tuossa',
    'tuosta',
    'tuohon',
    'tuolla',
    'tuolta',
    'tuolle',
    'tuona',
    'tuoksi',
    'se',
    'sen',
    'sitä',
    'siinä',
    'siitä',
    'siihen',
    'sillä',
    'siltä',
    'sille',
    'sinä',
    'siksi',
    'nämä',
    'näiden',
    'näitä',
    'näissä',
    'näistä',
    'näihin',
    'näillä',
    'näiltä',
    'näille',
    'näinä',
    'näiksi',
    'nuo',
    'noiden',
    'noita',
    'noissa',
    'noista',
    'noihin',
    'noilla',
    'noilta',
    'noille',
    'noina',
    'noiksi',
    'ne',
    'niiden',
    'niitä',
    'niissä',
    'niistä',
    'niihin',
    'niillä',
    'niiltä',
    'niille',
    'niinä',
    'niiksi',
    'kuka',
    'kenen',
    'kenet',
    'ketä',
    'kenessä',
    'kenestä',
    'keneen',
    'kenellä',
    'keneltä',
    'kenelle',
    'kenenä',
    'keneksi',
    'ketkä',
    'keiden',
    'ketkä',
    'keitä',
    'keissä',
    'keistä',
    'keihin',
    'keillä',
    'keiltä',
    'keille',
    'keinä',
    'keiksi',
    'mikä',
    'minkä',
    'minkä',
    'mitä',
    'missä',
    'mistä',
    'mihin',
    'millä',
    'miltä',
    'mille',
    'minä',
    'miksi',
    'mitkä',
    'joka',
    'jonka',
    'jota',
    'jossa',
    'josta',
    'johon',
    'jolla',
    'jolta',
    'jolle',
    'jona',
    'joksi',
    'jotka',
    'joiden',
    'joita',
    'joissa',
    'joista',
    'joihin',
    'joilla',
    'joilta',
    'joille',
    'joina',
    'joiksi',
    'että',
    'ja',
    'jos',
    'koska',
    'kuin',
    'mutta',
    'niin',
    'sekä',
    'sillä',
    'tai',
    'vaan',
    'vai',
    'vaikka',
    'kanssa',
    'mukaan',
    'noin',
    'poikki',
    'yli',
    'kun',
    'niin',
    'nyt',
    'itse',
];

$result =& $data;
unset($data);
return $result;
<?php

// french

static $data = [
    'a',
    'A',
    'à',
    'afin',
    'ah',
    'ai',
    'aie',
    'aient',
    'aies',
    'ailleurs',
    'ainsi',
    'ait',
    'alentour',
    'alias',
    'allais',
    'allaient',
    'allait',
    'allons',
    'allez',
    'alors',
    'Ap.',
    'Apr.',
    'après',
    'après-demain',
    'arrière',
    'as',
    'assez',
    'attendu',
    'au',
    'aucun',
    'aucune',
    'au-dedans',
    'au-dehors',
    'au-delà',
    'au-dessous',
    'au-dessus',
    'au-devant',
    'audit',
    'aujourd\'',
    'aujourd\'hui',
    'auparavant',
    'auprès',
    'auquel',
    'aura',
    'aurai',
    'auraient',
    'aurais',
    'aurait',
    'auras',
    'aurez',
    'auriez',
    'aurions',
    'aurons',
    'auront',
    'aussi',
    'aussitôt',
    'autant',
    'autour',
    'autre',
    'autrefois',
    'autres',
    'autrui',
    'aux',
    'auxdites',
    'auxdits',
    'auxquelles',
    'auxquels',
    'avaient',
    'avais',
    'avait',
    'avant',
    'avant-hier',
    'avec',
    'avez',
    'aviez',
    'avions',
    'avoir',
    'avons',
    'ayant',
    'ayez',
    'ayons',
    'B',
    'bah',
    'banco',
    'bé',
    'beaucoup',
    'ben',
    'bien',
    'bientôt',
    'bis',
    'bon',
    'C',
    'c\'',
    'ç\'',
    'c.-à-d.',
    'Ca',
    'ça',
    'çà',
    'cahin-caha',
    'car',
    'ce',
    '-ce',
    'céans',
    'ceci',
    'cela',
    'celle',
    'celle-ci',
    'celle-là',
    'celles',
    'celles-ci',
    'celles-là',
    'celui',
    'celui-ci',
    'celui-là',
    'cent',
    'cents',
    'cependant',
    'certain',
    'certaine',
    'certaines',
    'certains',
    'certes',
    'ces',
    'c\'est-à-dire',
    'cet',
    'cette',
    'ceux',
    'ceux-ci',
    'ceux-là',
    'cf.',
    'cg',
    'cgr',
    'chacun',
    'chacune',
    'chaque',
    'cher',
    'chez',
    'ci',
    '-ci',
    'ci-après',
    'ci-dessous',
    'ci-dessus',
    'cinq',
    'cinquante',
    'cinquante-cinq',
    'cinquante-deux',
    'cinquante-et-un',
    'cinquante-huit',
    'cinquante-neuf',
    'cinquante-quatre',
    'cinquante-sept',
    'cinquante-six',
    'cinquante-trois',
    'cl',
    'cm',
    'cm²',
    'combien',
    'comme',
    'comment',
    'contrario',
    'contre',
    'crescendo',
    'D',
    'd\'',
    'd\'abord',
    'd\'accord',
    'd\'affilée',
    'd\'ailleurs',
    'dans',
    'd\'après',
    'd\'arrache-pied',
    'davantage',
    'de',
    'debout',
    'dedans',
    'dehors',
    'déjà',
    'delà',
    'demain',
    'd\'emblée',
    'depuis',
    'derechef',
    'derrière',
    'des',
    'dès',
    'desdites',
    'desdits',
    'désormais',
    'desquelles',
    'desquels',
    'dessous',
    'dessus',
    'deux',
    'devant',
    'devers',
    'dg',
    'die',
    'différentes',
    'différents',
    'dire',
    'dis',
    'disent',
    'dit',
    'dito',
    'divers',
    'diverses',
    'dix',
    'dix-huit',
    'dix-neuf',
    'dix-sept',
    'dl',
    'dm',
    'donc',
    'dont',
    'dorénavant',
    'douze',
    'du',
    'dû',
    'dudit',
    'duquel',
    'durant',
    'E',
    'eh',
    'elle',
    '-elle',
    'elles',
    '-elles',
    'en',
    '\'en',
    '-en',
    'encore',
    'enfin',
    'ensemble',
    'ensuite',
    'entre',
    'entre-temps',
    'envers',
    'environ',
    'es',
    'ès',
    'est',
    'et',
    'et/ou',
    'étaient',
    'étais',
    'était',
    'étant',
    'etc',
    'été',
    'êtes',
    'étiez',
    'étions',
    'être',
    'eu',
    'eue',
    'eues',
    'euh',
    'eûmes',
    'eurent',
    'eus',
    'eusse',
    'eussent',
    'eusses',
    'eussiez',
    'eussions',
    'eut',
    'eût',
    'eûtes',
    'eux',
    'exprès',
    'extenso',
    'extremis',
    'F',
    'facto',
    'fallait',
    'faire',
    'fais',
    'faisais',
    'faisait',
    'faisaient',
    'faisons',
    'fait',
    'faites',
    'faudrait',
    'faut',
    'fi',
    'flac',
    'fors',
    'fort',
    'forte',
    'fortiori',
    'frais',
    'fûmes',
    'fur',
    'furent',
    'fus',
    'fusse',
    'fussent',
    'fusses',
    'fussiez',
    'fussions',
    'fut',
    'fût',
    'fûtes',
    'G',
    'gr',
    'grosso',
    'guère',
    'H',
    'ha',
    'han',
    'haut',
    'hé',
    'hein',
    'hem',
    'heu',
    'hg',
    'hier',
    'hl',
    'holà',
    'hop',
    'hormis',
    'hors',
    'hui',
    'huit',
    'hum',
    'I',
    'ibidem',
    'ici',
    'ici-bas',
    'idem',
    'il',
    '-il',
    'illico',
    'ils',
    '-ils',
    'ipso',
    'item',
    'J',
    'j\'',
    'jadis',
    'jamais',
    'je',
    '-je',
    'jusqu\'',
    'jusqu\'à',
    'jusqu\'au',
    'jusqu\'aux',
    'jusque',
    'juste',
    'l\'',
    'la',
    '-la',
    'là',
    '-là',
    'là-bas',
    'là-dedans',
    'là-dehors',
    'là-derrière',
    'là-dessous',
    'là-dessus',
    'là-devant',
    'là-haut',
    'laquelle',
    'l\'autre',
    'le',
    '-le',
    'lequel',
    'les',
    '-les',
    'lès',
    'lesquelles',
    'lesquels',
    'leur',
    '-leur',
    'leurs',
    'lez',
    'loin',
    'l\'on',
    'longtemps',
    'lors',
    'lorsqu\'',
    'lorsque',
    'lui',
    '-lui',
    'l\'un',
    'l\'une',
    'M',
    'm\'',
    'ma',
    'maint',
    'mainte',
    'maintenant',
    'maintes',
    'maints',
    'mais',
    'mal',
    'malgré',
    'me',
    'même',
    'mêmes',
    'mes',
    'mg',
    'mgr',
    'mieux',
    'mil',
    'mille',
    'milliards',
    'millions',
    'minima',
    'modo',
    'moi',
    '-moi',
    'moins',
    'mon',
    'moult',
    'moyennant',
    'N',
    'n\'',
    'naguère',
    'ne',
    'néanmoins',
    'neuf',
    'ni',
    'non',
    'nonante',
    'nonobstant',
    'nos',
    'notre',
    'nous',
    '-nous',
    'nul',
    'nulle',
    'O',
    'ô',
    'octante',
    'oh',
    'on',
    '-on',
    'ont',
    'onze',
    'or',
    'ou',
    'où',
    'ouais',
    'oui',
    'outre',
    'P',
    'par',
    'parbleu',
    'parce',
    'par-ci',
    'par-delà',
    'par-derrière',
    'par-dessous',
    'par-dessus',
    'par-devant',
    'parfois',
    'par-là',
    'parmi',
    'partout',
    'pas',
    'passé',
    'passim',
    'pendant',
    'personne',
    'petto',
    'peu',
    'peut',
    'peuvent',
    'peux',
    'peut-être',
    'pis',
    'plus',
    'plusieurs',
    'plutôt',
    'point',
    'posteriori',
    'pour',
    'pourquoi',
    'pourtant',
    'préalable',
    'près',
    'presqu\'',
    'presque',
    'primo',
    'priori',
    'prou',
    'pu',
    'puis',
    'puisqu\'',
    'puisque',
    'Q',
    'qu\'',
    'qua',
    'quand',
    'quarante',
    'quarante-cinq',
    'quarante-deux',
    'quarante-et-un',
    'quarante-huit',
    'quarante-neuf',
    'quarante-quatre',
    'quarante-sept',
    'quarante-six',
    'quarante-trois',
    'quasi',
    'quatorze',
    'quatre',
    'quatre-vingt',
    'quatre-vingt-cinq',
    'quatre-vingt-deux',
    'quatre-vingt-dix',
    'quatre-vingt-dix-huit',
    'quatre-vingt-dix-neuf',
    'quatre-vingt-dix-sept',
    'quatre-vingt-douze',
    'quatre-vingt-huit',
    'quatre-vingt-neuf',
    'quatre-vingt-onze',
    'quatre-vingt-quatorze',
    'quatre-vingt-quatre',
    'quatre-vingt-quinze',
    'quatre-vingts',
    'quatre-vingt-seize',
    'quatre-vingt-sept',
    'quatre-vingt-six',
    'quatre-vingt-treize',
    'quatre-vingt-trois',
    'quatre-vingt-un',
    'quatre-vingt-une',
    'que',
    'quel',
    'quelle',
    'quelles',
    'quelqu\'',
    'quelque',
    'quelquefois',
    'quelques',
    'quelques-unes',
    'quelques-uns',
    'quelqu\'un',
    'quelqu\'une',
    'quels',
    'qui',
    'quiconque',
    'quinze',
    'quoi',
    'quoiqu\'',
    'quoique',
    'R',
    'revoici',
    'revoilà',
    'rien',
    'S',
    's\'',
    'sa',
    'sans',
    'sauf',
    'se',
    'secundo',
    'seize',
    'selon',
    'sensu',
    'sept',
    'septante',
    'sera',
    'serai',
    'seraient',
    'serais',
    'serait',
    'seras',
    'serez',
    'seriez',
    'serions',
    'serons',
    'seront',
    'ses',
    'si',
    'sic',
    'sine',
    'sinon',
    'sitôt',
    'situ',
    'six',
    'soi',
    'soient',
    'sois',
    'soit',
    'soixante',
    'soixante-cinq',
    'soixante-deux',
    'soixante-dix',
    'soixante-dix-huit',
    'soixante-dix-neuf',
    'soixante-dix-sept',
    'soixante-douze',
    'soixante-et-onze',
    'soixante-et-un',
    'soixante-et-une',
    'soixante-huit',
    'soixante-neuf',
    'soixante-quatorze',
    'soixante-quatre',
    'soixante-quinze',
    'soixante-seize',
    'soixante-sept',
    'soixante-six',
    'soixante-treize',
    'soixante-trois',
    'sommes',
    'son',
    'sont',
    'soudain',
    'sous',
    'souvent',
    'soyez',
    'soyons',
    'stricto',
    'suis',
    'sur',
    'sur-le-champ',
    'surtout',
    'sus',
    'T',
    '-t',
    't\'',
    'ta',
    'tacatac',
    'tant',
    'tantôt',
    'tard',
    'te',
    'tel',
    'telle',
    'telles',
    'tels',
    'ter',
    'tes',
    'toi',
    '-toi',
    'ton',
    'tôt',
    'toujours',
    'tous',
    'tout',
    'toute',
    'toutefois',
    'toutes',
    'treize',
    'trente',
    'trente-cinq',
    'trente-deux',
    'trente-et-un',
    'trente-huit',
    'trente-neuf',
    'trente-quatre',
    'trente-sept',
    'trente-six',
    'trente-trois',
    'très',
    'trois',
    'trop',
    'tu',
    '-tu',
    'U',
    'un',
    'une',
    'unes',
    'uns',
    'USD',
    'V',
    'va',
    'vais',
    'vas',
    'vers',
    'veut',
    'veux',
    'via',
    'vice-versa',
    'vingt',
    'vingt-cinq',
    'vingt-deux',
    'vingt-huit',
    'vingt-neuf',
    'vingt-quatre',
    'vingt-sept',
    'vingt-six',
    'vingt-trois',
    'vis-à-vis',
    'vite',
    'vitro',
    'vivo',
    'voici',
    'voilà',
    'voire',
    'volontiers',
    'vos',
    'votre',
    'vous',
    '-vous',
    'W',
    'X',
    'y',
    '-y',
    'Z',
    'zéro',
];

$result =& $data;
unset($data);
return $result;
<?php

// hindi

static $data = [
    'अंदर',
    'अत',
    'अदि',
    'अप',
    'अपना',
    'अपनि',
    'अपनी',
    'अपने',
    'अभि',
    'अभी',
    'आदि',
    'आप',
    'इंहिं',
    'इंहें',
    'इंहों',
    'इतयादि',
    'इत्यादि',
    'इन',
    'इनका',
    'इन्हीं',
    'इन्हें',
    'इन्हों',
    'इस',
    'इसका',
    'इसकि',
    'इसकी',
    'इसके',
    'इसमें',
    'इसि',
    'इसी',
    'इसे',
    'उंहिं',
    'उंहें',
    'उंहों',
    'उन',
    'उनका',
    'उनकि',
    'उनकी',
    'उनके',
    'उनको',
    'उन्हीं',
    'उन्हें',
    'उन्हों',
    'उस',
    'उसके',
    'उसि',
    'उसी',
    'उसे',
    'एक',
    'एवं',
    'एस',
    'एसे',
    'ऐसे',
    'ओर',
    'और',
    'कइ',
    'कई',
    'कर',
    'करता',
    'करते',
    'करना',
    'करने',
    'करें',
    'कहते',
    'कहा',
    'का',
    'काफि',
    'काफ़ी',
    'कि',
    'किंहें',
    'किंहों',
    'कितना',
    'किन्हें',
    'किन्हों',
    'किया',
    'किर',
    'किस',
    'किसि',
    'किसी',
    'किसे',
    'की',
    'कुछ',
    'कुल',
    'के',
    'को',
    'कोइ',
    'कोई',
    'कोन',
    'कोनसा',
    'कौन',
    'कौनसा',
    'गया',
    'घर',
    'जब',
    'जहाँ',
    'जहां',
    'जा',
    'जिंहें',
    'जिंहों',
    'जितना',
    'जिधर',
    'जिन',
    'जिन्हें',
    'जिन्हों',
    'जिस',
    'जिसे',
    'जीधर',
    'जेसा',
    'जेसे',
    'जैसा',
    'जैसे',
    'जो',
    'तक',
    'तब',
    'तरह',
    'तिंहें',
    'तिंहों',
    'तिन',
    'तिन्हें',
    'तिन्हों',
    'तिस',
    'तिसे',
    'तो',
    'था',
    'थि',
    'थी',
    'थे',
    'दबारा',
    'दवारा',
    'दिया',
    'दुसरा',
    'दुसरे',
    'दूसरे',
    'दो',
    'द्वारा',
    'न',
    'नहिं',
    'नहीं',
    'ना',
    'निचे',
    'निहायत',
    'नीचे',
    'ने',
    'पर',
    'पहले',
    'पुरा',
    'पूरा',
    'पे',
    'फिर',
    'बनि',
    'बनी',
    'बहि',
    'बही',
    'बहुत',
    'बाद',
    'बाला',
    'बिलकुल',
    'भि',
    'भितर',
    'भी',
    'भीतर',
    'मगर',
    'मानो',
    'मे',
    'में',
    'यदि',
    'यह',
    'यहाँ',
    'यहां',
    'यहि',
    'यही',
    'या',
    'यिह',
    'ये',
    'रखें',
    'रवासा',
    'रहा',
    'रहे',
    'ऱ्वासा',
    'लिए',
    'लिये',
    'लेकिन',
    'व',
    'वगेरह',
    'वरग',
    'वर्ग',
    'वह',
    'वहाँ',
    'वहां',
    'वहिं',
    'वहीं',
    'वाले',
    'वुह',
    'वे',
    'वग़ैरह',
    'संग',
    'सकता',
    'सकते',
    'सबसे',
    'सभि',
    'सभी',
    'साथ',
    'साबुत',
    'साभ',
    'सारा',
    'से',
    'सो',
    'हि',
    'ही',
    'हुअ',
    'हुआ',
    'हुइ',
    'हुई',
    'हुए',
    'हे',
    'हें',
    'है',
    'हैं',
    'हो',
    'होता',
    'होति',
    'होती',
    'होते',
    'होना',
    'होने',
];

$result =& $data;
unset($data);
return $result;
<?php

// croatian

static $data = [
    'a',
    'ako',
    'ali',
    'bi',
    'bih',
    'bila',
    'bili',
    'bilo',
    'bio',
    'bismo',
    'biste',
    'biti',
    'bumo',
    'da',
    'do',
    'duž',
    'ga',
    'hoće',
    'hoćemo',
    'hoćete',
    'hoćeš',
    'hoću',
    'i',
    'iako',
    'ih',
    'ili',
    'iz',
    'ja',
    'je',
    'jedna',
    'jedne',
    'jedno',
    'jer',
    'jesam',
    'jesi',
    'jesmo',
    'jest',
    'jeste',
    'jesu',
    'jim',
    'joj',
    'još',
    'ju',
    'kada',
    'kako',
    'kao',
    'koja',
    'koje',
    'koji',
    'kojima',
    'koju',
    'kroz',
    'li',
    'me',
    'mene',
    'meni',
    'mi',
    'mimo',
    'moj',
    'moja',
    'moje',
    'mu',
    'na',
    'nad',
    'nakon',
    'nam',
    'nama',
    'nas',
    'naš',
    'naša',
    'naše',
    'našeg',
    'ne',
    'nego',
    'neka',
    'neki',
    'nekog',
    'neku',
    'nema',
    'netko',
    'neće',
    'nećemo',
    'nećete',
    'nećeš',
    'neću',
    'nešto',
    'ni',
    'nije',
    'nikoga',
    'nikoje',
    'nikoju',
    'nisam',
    'nisi',
    'nismo',
    'niste',
    'nisu',
    'njega',
    'njegov',
    'njegova',
    'njegovo',
    'njemu',
    'njezin',
    'njezina',
    'njezino',
    'njih',
    'njihov',
    'njihova',
    'njihovo',
    'njim',
    'njima',
    'njoj',
    'nju',
    'no',
    'o',
    'od',
    'odmah',
    'on',
    'ona',
    'oni',
    'ono',
    'ova',
    'pa',
    'pak',
    'po',
    'pod',
    'pored',
    'prije',
    's',
    'sa',
    'sam',
    'samo',
    'se',
    'sebe',
    'sebi',
    'si',
    'smo',
    'ste',
    'su',
    'sve',
    'svi',
    'svog',
    'svoj',
    'svoja',
    'svoje',
    'svom',
    'ta',
    'tada',
    'taj',
    'tako',
    'te',
    'tebe',
    'tebi',
    'ti',
    'to',
    'toj',
    'tome',
    'tu',
    'tvoj',
    'tvoja',
    'tvoje',
    'u',
    'uz',
    'vam',
    'vama',
    'vas',
    'vaš',
    'vaša',
    'vaše',
    'već',
    'vi',
    'vrlo',
    'za',
    'zar',
    'će',
    'ćemo',
    'ćete',
    'ćeš',
    'ću',
    'što',
];

$result =& $data;
unset($data);
return $result;
<?php

// hungarian

static $data = [
    'a',
    'ahogy',
    'ahol',
    'aki',
    'akik',
    'akkor',
    'alatt',
    'által',
    'általában',
    'amely',
    'amelyek',
    'amelyekben',
    'amelyeket',
    'amelyet',
    'amelynek',
    'ami',
    'amit',
    'amolyan',
    'amíg',
    'amikor',
    'át',
    'abban',
    'ahhoz',
    'annak',
    'arra',
    'arról',
    'az',
    'azok',
    'azon',
    'azt',
    'azzal',
    'azért',
    'aztán',
    'azután',
    'azonban',
    'bár',
    'be',
    'belül',
    'benne',
    'cikk',
    'cikkek',
    'cikkeket',
    'csak',
    'de',
    'e',
    'eddig',
    'egész',
    'egy',
    'egyes',
    'egyetlen',
    'egyéb',
    'egyik',
    'egyre',
    'ekkor',
    'el',
    'elég',
    'ellen',
    'elõ',
    'elõször',
    'elõtt',
    'elsõ',
    'én',
    'éppen',
    'ebben',
    'ehhez',
    'emilyen',
    'ennek',
    'erre',
    'ez',
    'ezt',
    'ezek',
    'ezen',
    'ezzel',
    'ezért',
    'és',
    'fel',
    'felé',
    'hanem',
    'hiszen',
    'hogy',
    'hogyan',
    'igen',
    'így',
    'illetve',
    'ill.',
    'ill',
    'ilyen',
    'ilyenkor',
    'ison',
    'ismét',
    'itt',
    'jó',
    'jól',
    'jobban',
    'kell',
    'kellett',
    'keresztül',
    'keressünk',
    'ki',
    'kívül',
    'között',
    'közül',
    'legalább',
    'lehet',
    'lehetett',
    'legyen',
    'lenne',
    'lenni',
    'lesz',
    'lett',
    'maga',
    'magát',
    'majd',
    'majd',
    'már',
    'más',
    'másik',
    'meg',
    'még',
    'mellett',
    'mert',
    'mely',
    'melyek',
    'mi',
    'mit',
    'míg',
    'miért',
    'milyen',
    'mikor',
    'minden',
    'mindent',
    'mindenki',
    'mindig',
    'mint',
    'mintha',
    'mivel',
    'most',
    'nagy',
    'nagyobb',
    'nagyon',
    'ne',
    'néha',
    'nekem',
    'neki',
    'nem',
    'néhány',
    'nélkül',
    'nincs',
    'olyan',
    'ott',
    'össze',
    'õ',
    'õk',
    'õket',
    'pedig',
    'persze',
    'rá',
    's',
    'saját',
    'sem',
    'semmi',
    'sok',
    'sokat',
    'sokkal',
    'számára',
    'szemben',
    'szerint',
    'szinte',
    'talán',
    'tehát',
    'teljes',
    'tovább',
    'továbbá',
    'több',
    'úgy',
    'ugyanis',
    'új',
    'újabb',
    'újra',
    'után',
    'utána',
    'utolsó',
    'vagy',
    'vagyis',
    'valaki',
    'valami',
    'valamint',
    'való',
    'vagyok',
    'van',
    'vannak',
    'volt',
    'voltam',
    'voltak',
    'voltunk',
    'vissza',
    'vele',
    'viszont',
    'volna',
];

$result =& $data;
unset($data);
return $result;
<?php

// indonesian

static $data = [
    'ada',
    'adanya',
    'adalah',
    'adapun',
    'agak',
    'agaknya',
    'agar',
    'akan',
    'akankah',
    'akhirnya',
    'aku',
    'akulah',
    'amat',
    'amatlah',
    'anda',
    'andalah',
    'antar',
    'diantaranya',
    'antara',
    'antaranya',
    'diantara',
    'apa',
    'apaan',
    'mengapa',
    'apabila',
    'apakah',
    'apalagi',
    'apatah',
    'atau',
    'ataukah',
    'ataupun',
    'bagai',
    'bagaikan',
    'sebagai',
    'sebagainya',
    'bagaimana',
    'bagaimanapun',
    'sebagaimana',
    'bagaimanakah',
    'bagi',
    'bahkan',
    'bahwa',
    'bahwasanya',
    'sebaliknya',
    'banyak',
    'sebanyak',
    'beberapa',
    'seberapa',
    'begini',
    'beginian',
    'beginikah',
    'beginilah',
    'sebegini',
    'begitu',
    'begitukah',
    'begitulah',
    'begitupun',
    'sebegitu',
    'belum',
    'belumlah',
    'sebelum',
    'sebelumnya',
    'sebenarnya',
    'berapa',
    'berapakah',
    'berapalah',
    'berapapun',
    'betulkah',
    'sebetulnya',
    'biasa',
    'biasanya',
    'bila',
    'bilakah',
    'bisa',
    'bisakah',
    'sebisanya',
    'boleh',
    'bolehkah',
    'bolehlah',
    'buat',
    'bukan',
    'bukankah',
    'bukanlah',
    'bukannya',
    'cuma',
    'percuma',
    'dahulu',
    'dalam',
    'dan',
    'dapat',
    'dari',
    'daripada',
    'dekat',
    'demi',
    'demikian',
    'demikianlah',
    'sedemikian',
    'dengan',
    'depan',
    'di',
    'dia',
    'dialah',
    'dini',
    'diri',
    'dirinya',
    'terdiri',
    'dong',
    'dulu',
    'enggak',
    'enggaknya',
    'entah',
    'entahlah',
    'terhadap',
    'terhadapnya',
    'hal',
    'hampir',
    'hanya',
    'hanyalah',
    'harus',
    'haruslah',
    'harusnya',
    'seharusnya',
    'hendak',
    'hendaklah',
    'hendaknya',
    'hingga',
    'sehingga',
    'ia',
    'ialah',
    'ibarat',
    'ingin',
    'inginkah',
    'inginkan',
    'ini',
    'inikah',
    'inilah',
    'itu',
    'itukah',
    'itulah',
    'jangan',
    'jangankan',
    'janganlah',
    'jika',
    'jikalau',
    'juga',
    'justru',
    'kala',
    'kalau',
    'kalaulah',
    'kalaupun',
    'kalian',
    'kami',
    'kamilah',
    'kamu',
    'kamulah',
    'kan',
    'kapan',
    'kapankah',
    'kapanpun',
    'dikarenakan',
    'karena',
    'karenanya',
    'ke',
    'kecil',
    'kemudian',
    'kenapa',
    'kepada',
    'kepadanya',
    'ketika',
    'seketika',
    'khususnya',
    'kini',
    'kinilah',
    'kiranya',
    'sekiranya',
    'kita',
    'kitalah',
    'kok',
    'lagi',
    'lagian',
    'selagi',
    'lah',
    'lain',
    'lainnya',
    'melainkan',
    'selaku',
    'lalu',
    'melalui',
    'terlalu',
    'lama',
    'lamanya',
    'selama',
    'selama',
    'selamanya',
    'lebih',
    'terlebih',
    'bermacam',
    'macam',
    'semacam',
    'maka',
    'makanya',
    'makin',
    'malah',
    'malahan',
    'mampu',
    'mampukah',
    'mana',
    'manakala',
    'manalagi',
    'masih',
    'masihkah',
    'semasih',
    'masing',
    'mau',
    'maupun',
    'semaunya',
    'memang',
    'mereka',
    'merekalah',
    'meski',
    'meskipun',
    'semula',
    'mungkin',
    'mungkinkah',
    'nah',
    'namun',
    'nanti',
    'nantinya',
    'nyaris',
    'oleh',
    'olehnya',
    'seorang',
    'seseorang',
    'pada',
    'padanya',
    'padahal',
    'paling',
    'sepanjang',
    'pantas',
    'sepantasnya',
    'sepantasnyalah',
    'para',
    'pasti',
    'pastilah',
    'per',
    'pernah',
    'pula',
    'pun',
    'merupakan',
    'rupanya',
    'serupa',
    'saat',
    'saatnya',
    'sesaat',
    'saja',
    'sajalah',
    'saling',
    'bersama',
    'sama',
    'sesama',
    'sambil',
    'sampai',
    'sana',
    'sangat',
    'sangatlah',
    'saya',
    'sayalah',
    'se',
    'sebab',
    'sebabnya',
    'sebuah',
    'tersebut',
    'tersebutlah',
    'sedang',
    'sedangkan',
    'sedikit',
    'sedikitnya',
    'segala',
    'segalanya',
    'segera',
    'sesegera',
    'sejak',
    'sejenak',
    'sekali',
    'sekalian',
    'sekalipun',
    'sesekali',
    'sekaligus',
    'sekarang',
    'sekarang',
    'sekitar',
    'sekitarnya',
    'sela',
    'selain',
    'selalu',
    'seluruh',
    'seluruhnya',
    'semakin',
    'sementara',
    'sempat',
    'semua',
    'semuanya',
    'sendiri',
    'sendirinya',
    'seolah',
    'seperti',
    'sepertinya',
    'sering',
    'seringnya',
    'serta',
    'siapa',
    'siapakah',
    'siapapun',
    'disini',
    'disinilah',
    'sini',
    'sinilah',
    'sesuatu',
    'sesuatunya',
    'suatu',
    'sesudah',
    'sesudahnya',
    'sudah',
    'sudahkah',
    'sudahlah',
    'supaya',
    'tadi',
    'tadinya',
    'tak',
    'tanpa',
    'setelah',
    'telah',
    'tentang',
    'tentu',
    'tentulah',
    'tentunya',
    'tertentu',
    'seterusnya',
    'tapi',
    'tetapi',
    'setiap',
    'tiap',
    'setidaknya',
    'tidak',
    'tidakkah',
    'tidaklah',
    'toh',
    'waduh',
    'wah',
    'wahai',
    'sewaktu',
    'walau',
    'walaupun',
    'wong',
    'yaitu',
    'yakni',
    'yang',
];

$result =& $data;
unset($data);
return $result;
<?php

// italian

static $data = [
    'ad',
    'al',
    'allo',
    'ai',
    'agli',
    'all',
    'agl',
    'alla',
    'alle',
    'con',
    'col',
    'coi',
    'da',
    'dal',
    'dallo',
    'dai',
    'dagli',
    'dall',
    'dagl',
    'dalla',
    'dalle',
    'di',
    'del',
    'dello',
    'dei',
    'degli',
    'dell',
    'degl',
    'della',
    'delle',
    'in',
    'nel',
    'nello',
    'nei',
    'negli',
    'nell',
    'negl',
    'nella',
    'nelle',
    'su',
    'sul',
    'sullo',
    'sui',
    'sugli',
    'sull',
    'sugl',
    'sulla',
    'sulle',
    'per',
    'tra',
    'contro',
    'io',
    'tu',
    'lui',
    'lei',
    'noi',
    'voi',
    'loro',
    'mio',
    'mia',
    'miei',
    'mie',
    'tuo',
    'tua',
    'tuoi',
    'tue',
    'suo',
    'sua',
    'suoi',
    'sue',
    'nostro',
    'nostra',
    'nostri',
    'nostre',
    'vostro',
    'vostra',
    'vostri',
    'vostre',
    'mi',
    'ti',
    'ci',
    'vi',
    'lo',
    'la',
    'li',
    'le',
    'gli',
    'ne',
    'il',
    'un',
    'uno',
    'una',
    'ma',
    'ed',
    'se',
    'perché',
    'anche',
    'come',
    'dov',
    'dove',
    'che',
    'chi',
    'cui',
    'non',
    'più',
    'quale',
    'quanto',
    'quanti',
    'quanta',
    'quante',
    'quello',
    'quelli',
    'quella',
    'quelle',
    'questo',
    'questi',
    'questa',
    'queste',
    'si',
    'tutto',
    'tutti',
    'a',
    'c',
    'e',
    'i',
    'l',
    'o',
    'ho',
    'hai',
    'ha',
    'abbiamo',
    'avete',
    'hanno',
    'abbia',
    'abbiate',
    'abbiano',
    'avrò',
    'avrai',
    'avrà',
    'avremo',
    'avrete',
    'avranno',
    'avrei',
    'avresti',
    'avrebbe',
    'avremmo',
    'avreste',
    'avrebbero',
    'avevo',
    'avevi',
    'aveva',
    'avevamo',
    'avevate',
    'avevano',
    'ebbi',
    'avesti',
    'ebbe',
    'avemmo',
    'aveste',
    'ebbero',
    'avessi',
    'avesse',
    'avessimo',
    'avessero',
    'avendo',
    'avuto',
    'avuta',
    'avuti',
    'avute',
    'sono',
    'sei',
    'è',
    'siamo',
    'siete',
    'sia',
    'siate',
    'siano',
    'sarò',
    'sarai',
    'sarà',
    'saremo',
    'sarete',
    'saranno',
    'sarei',
    'saresti',
    'sarebbe',
    'saremmo',
    'sareste',
    'sarebbero',
    'ero',
    'eri',
    'era',
    'eravamo',
    'eravate',
    'erano',
    'fui',
    'fosti',
    'fu',
    'fummo',
    'foste',
    'furono',
    'fossi',
    'fosse',
    'fossimo',
    'fossero',
    'essendo',
    'faccio',
    'fai',
    'facciamo',
    'fanno',
    'faccia',
    'facciate',
    'facciano',
    'farò',
    'farai',
    'farà',
    'faremo',
    'farete',
    'faranno',
    'farei',
    'faresti',
    'farebbe',
    'faremmo',
    'fareste',
    'farebbero',
    'facevo',
    'facevi',
    'faceva',
    'facevamo',
    'facevate',
    'facevano',
    'feci',
    'facesti',
    'fece',
    'facemmo',
    'faceste',
    'fecero',
    'facessi',
    'facesse',
    'facessimo',
    'facessero',
    'facendo',
    'sto',
    'stai',
    'sta',
    'stiamo',
    'stanno',
    'stia',
    'stiate',
    'stiano',
    'starò',
    'starai',
    'starà',
    'staremo',
    'starete',
    'staranno',
    'starei',
    'staresti',
    'starebbe',
    'staremmo',
    'stareste',
    'starebbero',
    'stavo',
    'stavi',
    'stava',
    'stavamo',
    'stavate',
    'stavano',
    'stetti',
    'stesti',
    'stette',
    'stemmo',
    'steste',
    'stettero',
    'stessi',
    'stesse',
    'stessimo',
    'stessero',
    'stando',
];

$result =& $data;
unset($data);
return $result;

<?php

// georgian

static $data = [
    'ა.შ.',
    'აგერ',
    'აგრეთვე',
    'ალბათ',
    'ამაზე',
    'ამას',
    'ამასთან',
    'ამასთანავე',
    'ამგვარად',
    'ამდენად',
    'ამით',
    'ამის',
    'ამისთვის',
    'ამიტომ',
    'ამიტომაც',
    'ამჟამად',
    'ამჯერად',
    'ან',
    'ანუ',
    'არ',
    'არა',
    'არადა',
    'არათუ',
    'არამარტო',
    'არამედ',
    'არამხოლოდ',
    'არანაკლებ',
    'არასოდეს',
    'არაუადრეს',
    'არაუგვიანეს',
    'არაუმეტეს',
    'არსად',
    'არსაიდან',
    'არც',
    'არცერთ',
    'ასევე',
    'ასეც',
    'აქამდე',
    'აღარ',
    'აღარც',
    'ბოლოს',
    'ბოლოსკენ',
    'გამო',
    'გამუდმებით',
    'განსაკუთრებით',
    'გარდა',
    'გარეშე',
    'და',
    'დასასრულს',
    'დასაწყისში',
    'დროულად',
    'ე.ი.',
    'ე.წ.',
    'ეგებ',
    'ერთადერთი',
    'ერთადერთმა',
    'ერთ-ერთი',
    'ერთხელ',
    'ესოდე',
    'ვერ',
    'ვითომ',
    'ვინაიდან',
    'ვინძლო',
    'ვისაც',
    'ზემოაღნიშნულმა',
    'ზოგჯერ',
    'თავად',
    'თავადაც',
    'თავადვე',
    'თავდაპირველად',
    'თავიდანვე',
    'თავის მხრივ',
    'თან',
    'თანაც',
    'თანახმადაც',
    'თანდათან',
    'თვით',
    'თვითონ',
    'თვითონაც',
    'თვითონვე',
    'თითოეულმა',
    'თითქოს',
    'თუ',
    'თუკი',
    'თუმცა',
    'თუმცაღა',
    'თუნდაც',
    'იმავდროულად',
    'იმავე',
    'იმან',
    'იმას',
    'იმდენად',
    'იმთავითვე',
    'იმით',
    'იმის',
    'იმისთვის',
    'იმიტომ',
    'ისევე',
    'ისეთი',
    'ისეც',
    'იშვიათად',
    'კერძოდ',
    'კვლავ',
    'კი',
    'კიდევ',
    'მაგალითად',
    'მაგან',
    'მაგას',
    'მაგით',
    'მაგის',
    'მაგრამ',
    'მათი',
    'მაინც',
    'მანამ',
    'მანამდე',
    'მართალია',
    'მარტო',
    'მაშასადამე',
    'მაშინ',
    'მაშინვე',
    'მერე',
    'მეტად',
    'მთელი',
    'მიერ',
    'მით',
    'მიმართ',
    'მისივე',
    'მსგავსი',
    'მხოლოდ',
    'ნაწილობრივ',
    'ნეტავ',
    'ნეტავი',
    'ნუ',
    'ნურასოდეს',
    'ნურც',
    'ნუღარ',
    'ნუღარც',
    'ოდენ',
    'ოდესღაც',
    'ოღონდ',
    'პირველი',
    'პირიქით',
    'პრინციპში',
    'რადგან',
    'რადგანაც',
    'რათა',
    'რაკი',
    'რამდენად',
    'რამდენადაც',
    'რამეთუ',
    'რამენაირად',
    'რამეფრად',
    'რანაირადაც',
    'რასაკვირველია',
    'რასაც',
    'რაღაც',
    'რაც',
    'რითაც',
    'რისთვისაც',
    'როგორადაც',
    'როგორიც',
    'როგორიცაა',
    'როგორღაც',
    'როგორც',
    'როდესაც',
    'როდესღაც',
    'რომ',
    'რომელიმე',
    'რომელიც',
    'რომელსაც',
    'რომლებიც',
    'რომლითაც',
    'რომლის',
    'როცა',
    'საბოლოოდ',
    'სადაც',
    'სადღაც',
    'საერთოდ',
    'სათანადოდ',
    'საიდანაც',
    'სამომავლოდ',
    'სანამ',
    'სანამდე',
    'სრულად',
    'სულ',
    'სწორედ',
    'სხვადასხვა',
    'სხვები',
    'უკვე',
    'უნდა',
    'უსათუოდ',
    'უფრო',
    'უცებ',
    'უცნაურად',
    'ფაქტობრივად',
    'ყველა',
    'ყოველგვარი',
    'ყოველთვის',
    'ყოველი',
    'ყოველივე',
    'შედარებით',
    'შედეგად',
    'შემდგომ',
    'შემდგომში',
    'შემდეგ',
    'შესახებ',
    'შორის',
    'ჩვეულებრივ',
    'წინააღმდეგ',
    'წინაშე',
    'ხან',
    'ხოლმე',
    'ხოლო',
    'ხშირად',
    'ჯერაც',
    'ჯერჯერობით',
    'ამის გარდა',
    'ამის გარეშე',
    'ამის მიუხედავად',
    'ამასთან ერთად',
    'ამის მიხედვით',
    'ამის ნაცვლად',
    'ამის პასუხად',
    'ამასთან შედარებით',
    'ამბობს, რომ',
    'ამ დროს',
    'ამ თემაზე',
    'ამ მიზნით',
    'ამის საპირისპიროდ',
    'ამის გამო',
    'ამ მხრივ',
    'ამის უარსაყოფად',
    'ამის შედეგად',
    'ამ შემთხვევაში',
    'ამავე დროს',
    'ამას გარდა',
    'ამასთან დაკავშირებით',
    'ამის შემდეგ',
    'ამის შესაბამისად',
    'ამის შესახებ',
    'ამისგან განსხვავებით',
    'არა მარტო',
    'არა მხოლოდ',
    'არა უადრეს',
    'არა უგვიანეს',
    'არც ერთი',
    'არც კი',
    'არც მეორე',
    'ასე ვთქვათ',
    'ასე მაგალითად',
    'ასე რომ',
    'ასე შემდეგ',
    'ასევე განიხილავს',
    'აქედან გამომდინარე',
    'აქედან დასკვნა',
    'აღნიშნა რომ',
    'აღნიშნულთან დაკავშირებით',
    'აცხადებს რომ',
    'ბოლო ერთი',
    'ბოლო პერიოდში',
    'ბოლო წლებში',
    'გამოთქვა იმედი',
    'განაცხადა, რომ',
    'განმარტა, რომ',
    'გარდა ამისა',
    'გარშემო არსებული',
    'და სხვ.',
    'და სხვა',
    'დაადასტურა, რომ',
    'ეგრეთ წოდებული',
    'ეგრეთ წოდებულმა',
    'ერთი თვალსაზრისით',
    'ერთი მხრივ',
    'ერთის მხრივ',
    'ეს კი',
    'ესე იგი',
    'ვიდრე არ',
    'თავიდან ბოლომდე',
    'თუ რამდენად',
    'თუ როგორ',
    'იგივეა რაც',
    'იმ შემთხვევაში',
    'იმაზე მეტი',
    'იმაზე, რომ',
    'იმას, რომ',
    'იმასთან დაკავშირებით',
    'იმდენად რამდენადაც',
    'იმედი გამოთქვა',
    'იმის გამო',
    'იმის თაობაზე',
    'იმის საწინააღმდეგოდ',
    'იმისათვის, რომ',
    'იმისთვის, რათა',
    'იმისთვის, რომ',
    'იმიტომ, რომ',
    'ის, რომელიც',
    'ისე როგორც',
    'ისე, რომ',
    'ისევე როგორც',
    'ისეთი როგორიც',
    'იქიდან გამომდინარე',
    'კიდევ ერთხელ',
    'მაგრამ თუ',
    'მათ შორის',
    'მათი ვარაუდით',
    'მანამ, სანამ',
    'მას შემდეგ',
    'მაშინ, როცა',
    'მაშინაც კი',
    'მეორე მხრივ',
    'მეორეც ერთი',
    'მერე მეორე',
    'მით უფრო',
    'მიიჩნევს, რომ',
    'მისი განმარტებით',
    'მისი თქმით',
    'მისივე თქმით',
    'მიუხედავად ამისა',
    'ნურც კი',
    'პირველ რიგში',
    'რა დროსაც',
    'რა მიზეზითაც',
    'რაც შეეხება',
    'რაც შეიძლება',
    'რის გამოც',
    'რის საფუძველზედაც',
    'რის საფუძველზეც',
    'რის შედეგადაც',
    'რის შემდეგაც',
    'როგორც კი',
    'რომ არა',
    'რომ თუ',
    'რომელთა გამოც',
    'რომლის თანახმად',
    'რომლის თანახმადაც',
    'რომლის მიხედვითაც',
    'რომლის შესახებ',
    'საკითხთან დაკავშირებით',
    'სულ მცირე',
    'სულ ცოტა',
    'სხვა კუთხით',
    'სხვა მხრივ',
    'სხვა რამ',
    'სხვათა შორის',
    'უფრო მეტიც',
    'ყოველივე ეს',
    'შემდეგ უკვე',
    'ჩვენი განცხადებით',
    'ჯერ ერთი',
    'ჯერ კიდევ',
    'ამ ბოლო დროს',
    'ამა თუ იმ',
    'ასე თუ ისე',
    'აქედან ჩანს, რომ',
    'ბოლოს და ბოლოს',
    'გამომდინარე იქიდან, რომ',
    'და ასე შემდეგ',
    'ვინაიდან და რადგანაც',
    'თუ რის საფუძველზე',
    'იმის გათვალისწინებით, რომ',
    'იმის გამო, რომ',
    'იმის ნაცვლად, რომ',
    'ისევ და ისევ',
    'იქვე აღნიშნა, რომ',
    'იქიდან გამომდინარე, რომ',
    'კიდევ და კიდევ',
    'მაინც და მაინც',
    'მას შემდეგ, რაც',
    'მიუხედავად იმისა, თუ',
    'მიუხედავად იმისა, რომ',
    'როგორც უკვე ითქვა',
    'როდის და რატომ',
    'უფრო და უფრო',
];

$result =& $data;
unset($data);
return $result;
<?php

// lithuanian

static $data = [
    'abi',
    'abidvi',
    'abiejose',
    'abiejuose',
    'abiejø',
    'abiem',
    'abigaliai',
    'abipus',
    'abu',
    'abudu',
    'ai',
    'ana',
    'anaiptol',
    'anaisiais',
    'anajai',
    'anajam',
    'anajame',
    'anapus',
    'anas',
    'anasai',
    'anasis',
    'anei',
    'aniedvi',
    'anieji',
    'aniesiems',
    'anoji',
    'anojo',
    'anojoje',
    'anokia',
    'anoks',
    'anosiomis',
    'anosioms',
    'anosios',
    'anosiose',
    'anot',
    'ant',
    'antai',
    'anuodu',
    'anuoju',
    'anuosiuose',
    'anuosius',
    'anàja',
    'anàjà',
    'anàjá',
    'anàsias',
    'anøjø',
    'apie',
    'aplink',
    'ar',
    'arba',
    'argi',
    'arti',
    'aukðèiau',
    'að',
    'be',
    'bei',
    'beje',
    'bemaþ',
    'bent',
    'bet',
    'betgi',
    'beveik',
    'dar',
    'dargi',
    'daugmaþ',
    'deja',
    'dëka',
    'dël',
    'dëlei',
    'dëlto',
    'ech',
    'et',
    'gal',
    'galbût',
    'galgi',
    'gan',
    'gana',
    'gi',
    'greta',
    'idant',
    'iki',
    'ir',
    'irgi',
    'it',
    'itin',
    'ið',
    'iðilgai',
    'iðvis',
    'jaisiais',
    'jajai',
    'jajam',
    'jajame',
    'jei',
    'jeigu',
    'ji',
    'jiedu',
    'jiedvi',
    'jieji',
    'jiesiems',
    'jinai',
    'jis',
    'jisai',
    'jog',
    'joji',
    'jojo',
    'jojoje',
    'jokia',
    'joks',
    'josiomis',
    'josioms',
    'josios',
    'josiose',
    'judu',
    'judvi',
    'juk',
    'jumis',
    'jums',
    'jumyse',
    'juodu',
    'juoju',
    'juosiuose',
    'juosius',
    'jus',
    'jàja',
    'jàjà',
    'jàsias',
    'jájá',
    'jøjø',
    'jûs',
    'jûsiðkis',
    'jûsiðkë',
    'jûsø',
    'kad',
    'kada',
    'kadangi',
    'kai',
    'kaip',
    'kaipgi',
    'kas',
    'katra',
    'katras',
    'katriedvi',
    'katruodu',
    'kaþin',
    'kaþkas',
    'kaþkatra',
    'kaþkatras',
    'kaþkokia',
    'kaþkoks',
    'kaþkuri',
    'kaþkuris',
    'kiaurai',
    'kiek',
    'kiekvienas',
    'kieno',
    'kita',
    'kitas',
    'kitokia',
    'kitoks',
    'kodël',
    'kokia',
    'koks',
    'kol',
    'kolei',
    'kone',
    'kuomet',
    'kur',
    'kurgi',
    'kuri',
    'kuriedvi',
    'kuris',
    'kuriuodu',
    'lai',
    'lig',
    'ligi',
    'link',
    'lyg',
    'man',
    'manaisiais',
    'manajai',
    'manajam',
    'manajame',
    'manas',
    'manasai',
    'manasis',
    'mane',
    'manieji',
    'maniesiems',
    'manim',
    'manimi',
    'maniðkis',
    'maniðkë',
    'mano',
    'manoji',
    'manojo',
    'manojoje',
    'manosiomis',
    'manosioms',
    'manosios',
    'manosiose',
    'manuoju',
    'manuosiuose',
    'manuosius',
    'manyje',
    'manàja',
    'manàjà',
    'manàjá',
    'manàsias',
    'manæs',
    'manøjø',
    'mat',
    'maþdaug',
    'maþne',
    'mes',
    'mudu',
    'mudvi',
    'mumis',
    'mums',
    'mumyse',
    'mus',
    'mûsiðkis',
    'mûsiðkë',
    'mûsø',
    'na',
    'nagi',
    'ne',
    'nebe',
    'nebent',
    'negi',
    'negu',
    'nei',
    'nejau',
    'nejaugi',
    'nekaip',
    'nelyginant',
    'nes',
    'net',
    'netgi',
    'netoli',
    'neva',
    'nors',
    'nuo',
    'në',
    'o',
    'ogi',
    'oi',
    'paeiliui',
    'pagal',
    'pakeliui',
    'palaipsniui',
    'palei',
    'pas',
    'pasak',
    'paskos',
    'paskui',
    'paskum',
    'pat',
    'pati',
    'patiems',
    'paties',
    'pats',
    'patys',
    'patá',
    'paèiais',
    'paèiam',
    'paèiame',
    'paèiu',
    'paèiuose',
    'paèius',
    'paèiø',
    'per',
    'pernelyg',
    'pirm',
    'pirma',
    'pirmiau',
    'po',
    'prie',
    'prieð',
    'prieðais',
    'pro',
    'pusiau',
    'rasi',
    'rodos',
    'sau',
    'savaisiais',
    'savajai',
    'savajam',
    'savajame',
    'savas',
    'savasai',
    'savasis',
    'save',
    'savieji',
    'saviesiems',
    'savimi',
    'saviðkis',
    'saviðkë',
    'savo',
    'savoji',
    'savojo',
    'savojoje',
    'savosiomis',
    'savosioms',
    'savosios',
    'savosiose',
    'savuoju',
    'savuosiuose',
    'savuosius',
    'savyje',
    'savàja',
    'savàjà',
    'savàjá',
    'savàsias',
    'savæs',
    'savøjø',
    'skersai',
    'skradþiai',
    'staèiai',
    'su',
    'sulig',
    'ta',
    'tad',
    'tai',
    'taigi',
    'taip',
    'taipogi',
    'taisiais',
    'tajai',
    'tajam',
    'tajame',
    'tamsta',
    'tarp',
    'tarsi',
    'tartum',
    'tarytum',
    'tas',
    'tasai',
    'tau',
    'tavaisiais',
    'tavajai',
    'tavajam',
    'tavajame',
    'tavas',
    'tavasai',
    'tavasis',
    'tave',
    'tavieji',
    'taviesiems',
    'tavimi',
    'taviðkis',
    'taviðkë',
    'tavo',
    'tavoji',
    'tavojo',
    'tavojoje',
    'tavosiomis',
    'tavosioms',
    'tavosios',
    'tavosiose',
    'tavuoju',
    'tavuosiuose',
    'tavuosius',
    'tavyje',
    'tavàja',
    'tavàjà',
    'tavàjá',
    'tavàsias',
    'tavæs',
    'tavøjø',
    'taèiau',
    'te',
    'tegu',
    'tegul',
    'tiedvi',
    'tieji',
    'ties',
    'tiesiems',
    'tiesiog',
    'tik',
    'tikriausiai',
    'tiktai',
    'toji',
    'tojo',
    'tojoje',
    'tokia',
    'toks',
    'tol',
    'tolei',
    'toliau',
    'tosiomis',
    'tosioms',
    'tosios',
    'tosiose',
    'tu',
    'tuodu',
    'tuoju',
    'tuosiuose',
    'tuosius',
    'turbût',
    'tàja',
    'tàjà',
    'tàjá',
    'tàsias',
    'tøjø',
    'tûlas',
    'uþ',
    'uþtat',
    'uþvis',
    'va',
    'vai',
    'viduj',
    'vidury',
    'vien',
    'vienas',
    'vienokia',
    'vienoks',
    'vietoj',
    'virð',
    'virðuj',
    'virðum',
    'vis',
    'vis dëlto',
    'visa',
    'visas',
    'visgi',
    'visokia',
    'visoks',
    'vos',
    'vël',
    'vëlgi',
    'ypaè',
    'á',
    'ákypai',
    'ástriþai',
    'ðalia',
    'ðe',
    'ði',
    'ðiaisiais',
    'ðiajai',
    'ðiajam',
    'ðiajame',
    'ðiapus',
    'ðiedvi',
    'ðieji',
    'ðiesiems',
    'ðioji',
    'ðiojo',
    'ðiojoje',
    'ðiokia',
    'ðioks',
    'ðiosiomis',
    'ðiosioms',
    'ðiosios',
    'ðiosiose',
    'ðis',
    'ðisai',
    'ðit',
    'ðita',
    'ðitas',
    'ðitiedvi',
    'ðitokia',
    'ðitoks',
    'ðituodu',
    'ðiuodu',
    'ðiuoju',
    'ðiuosiuose',
    'ðiuosius',
    'ðiàja',
    'ðiàjà',
    'ðiàsias',
    'ðiøjø',
    'ðtai',
    'ðájá',
    'þemiau',
];

$result =& $data;
unset($data);
return $result;
<?php

// latvian

static $data = [
    'aiz',
    'ap',
    'apakš',
    'apakšpus',
    'ar',
    'arī',
    'augšpus',
    'bet',
    'bez',
    'bija',
    'biji',
    'biju',
    'bijām',
    'bijāt',
    'būs',
    'būsi',
    'būsiet',
    'būsim',
    'būt',
    'būšu',
    'caur',
    'diemžēl',
    'diezin',
    'droši',
    'dēļ',
    'esam',
    'esat',
    'esi',
    'esmu',
    'gan',
    'gar',
    'iekam',
    'iekams',
    'iekām',
    'iekāms',
    'iekš',
    'iekšpus',
    'ik',
    'ir',
    'it',
    'itin',
    'iz',
    'ja',
    'jau',
    'jeb',
    'jebšu',
    'jel',
    'jo',
    'jā',
    'ka',
    'kamēr',
    'kaut',
    'kolīdz',
    'kopš',
    'kā',
    'kļuva',
    'kļuvi',
    'kļuvu',
    'kļuvām',
    'kļuvāt',
    'kļūs',
    'kļūsi',
    'kļūsiet',
    'kļūsim',
    'kļūst',
    'kļūstam',
    'kļūstat',
    'kļūsti',
    'kļūstu',
    'kļūt',
    'kļūšu',
    'labad',
    'lai',
    'lejpus',
    'līdz',
    'līdzko',
    'ne',
    'nebūt',
    'nedz',
    'nekā',
    'nevis',
    'nezin',
    'no',
    'nu',
    'nē',
    'otrpus',
    'pa',
    'par',
    'pat',
    'pie',
    'pirms',
    'pret',
    'priekš',
    'pār',
    'pēc',
    'starp',
    'tad',
    'tak',
    'tapi',
    'taps',
    'tapsi',
    'tapsiet',
    'tapsim',
    'tapt',
    'tapāt',
    'tapšu',
    'taču',
    'te',
    'tiec',
    'tiek',
    'tiekam',
    'tiekat',
    'tieku',
    'tik',
    'tika',
    'tikai',
    'tiki',
    'tikko',
    'tiklab',
    'tiklīdz',
    'tiks',
    'tiksiet',
    'tiksim',
    'tikt',
    'tiku',
    'tikvien',
    'tikām',
    'tikāt',
    'tikšu',
    'tomēr',
    'topat',
    'turpretim',
    'turpretī',
    'tā',
    'tādēļ',
    'tālab',
    'tāpēc',
    'un',
    'uz',
    'vai',
    'var',
    'varat',
    'varēja',
    'varēji',
    'varēju',
    'varējām',
    'varējāt',
    'varēs',
    'varēsi',
    'varēsiet',
    'varēsim',
    'varēt',
    'varēšu',
    'vien',
    'virs',
    'virspus',
    'vis',
    'viņpus',
    'zem',
    'ārpus',
    'šaipus',
];

$result =& $data;
unset($data);
return $result;
<?php

// dutch

static $data = [
    'de',
    'en',
    'van',
    'ik',
    'te',
    'dat',
    'die',
    'in',
    'een',
    'hij',
    'het',
    'niet',
    'zijn',
    'is',
    'was',
    'op',
    'aan',
    'met',
    'als',
    'voor',
    'had',
    'er',
    'maar',
    'om',
    'hem',
    'dan',
    'zou',
    'of',
    'wat',
    'mijn',
    'men',
    'dit',
    'zo',
    'door',
    'over',
    'ze',
    'zich',
    'bij',
    'ook',
    'tot',
    'je',
    'mij',
    'uit',
    'der',
    'daar',
    'haar',
    'naar',
    'heb',
    'hoe',
    'heeft',
    'hebben',
    'deze',
    'u',
    'want',
    'nog',
    'zal',
    'me',
    'zij',
    'nu',
    'ge',
    'geen',
    'omdat',
    'iets',
    'worden',
    'toch',
    'al',
    'waren',
    'veel',
    'meer',
    'doen',
    'toen',
    'moet',
    'ben',
    'zonder',
    'kan',
    'hun',
    'dus',
    'alles',
    'onder',
    'ja',
    'eens',
    'hier',
    'wie',
    'werd',
    'altijd',
    'doch',
    'wordt',
    'wezen',
    'kunnen',
    'ons',
    'zelf',
    'tegen',
    'na',
    'reeds',
    'wil',
    'kon',
    'niets',
    'uw',
    'iemand',
    'geweest',
    'andere',
];

$result =& $data;
unset($data);
return $result;
<?php

// norwegian

static $data = [
    'og',
    'i',
    'jeg',
    'det',
    'at',
    'en',
    'et',
    'den',
    'til',
    'er',
    'som',
    'på',
    'de',
    'med',
    'han',
    'av',
    'ikke',
    'ikkje',
    'der',
    'så',
    'var',
    'meg',
    'seg',
    'men',
    'ett',
    'har',
    'om',
    'vi',
    'min',
    'mitt',
    'ha',
    'hadde',
    'hun',
    'nå',
    'over',
    'da',
    'ved',
    'fra',
    'du',
    'ut',
    'sin',
    'dem',
    'oss',
    'opp',
    'man',
    'kan',
    'hans',
    'hvor',
    'eller',
    'hva',
    'skal',
    'selv',
    'sjøl',
    'her',
    'alle',
    'vil',
    'bli',
    'ble',
    'blei',
    'blitt',
    'kunne',
    'inn',
    'når',
    'være',
    'kom',
    'noen',
    'noe',
    'ville',
    'dere',
    'som',
    'deres',
    'kun',
    'ja',
    'etter',
    'ned',
    'skulle',
    'denne',
    'for',
    'deg',
    'si',
    'sine',
    'sitt',
    'mot',
    'å',
    'meget',
    'hvorfor',
    'dette',
    'disse',
    'uten',
    'hvordan',
    'ingen',
    'din',
    'ditt',
    'blir',
    'samme',
    'hvilken',
    'hvilke',
    'sånn',
    'inni',
    'mellom',
    'vår',
    'hver',
    'hvem',
    'vors',
    'hvis',
    'både',
    'bare',
    'enn',
    'fordi',
    'før',
    'mange',
    'også',
    'slik',
    'vært',
    'være',
    'båe',
    'begge',
    'siden',
    'dykk',
    'dykkar',
    'dei',
    'deira',
    'deires',
    'deim',
    'di',
    'då',
    'eg',
    'ein',
    'eit',
    'eitt',
    'elles',
    'honom',
    'hjå',
    'ho',
    'hoe',
    'henne',
    'hennar',
    'hennes',
    'hoss',
    'hossen',
    'ikkje',
    'ingi',
    'inkje',
    'korleis',
    'korso',
    'kva',
    'kvar',
    'kvarhelst',
    'kven',
    'kvi',
    'kvifor',
    'me',
    'medan',
    'mi',
    'mine',
    'mykje',
    'no',
    'nokon',
    'noka',
    'nokor',
    'noko',
    'nokre',
    'si',
    'sia',
    'sidan',
    'so',
    'somt',
    'somme',
    'um',
    'upp',
    'vere',
    'vore',
    'verte',
    'vort',
    'varte',
    'vart',
];

$result =& $data;
unset($data);
return $result;
<?php

// polish

static $data = [
    'ach',
    'aj',
    'albo',
    'bardzo',
    'bez',
    'bo',
    'być',
    'ci',
    'cię',
    'ciebie',
    'co',
    'czy',
    'daleko',
    'dla',
    'dlaczego',
    'dlatego',
    'do',
    'dobrze',
    'dokąd',
    'dość',
    'dużo',
    'dwa',
    'dwaj',
    'dwie',
    'dwoje',
    'dziś',
    'dzisiaj',
    'gdyby',
    'gdzie',
    'go',
    'ich',
    'ile',
    'im',
    'inny',
    'ja',
    'ją',
    'jak',
    'jakby',
    'jaki',
    'je',
    'jeden',
    'jedna',
    'jedno',
    'jego',
    'jej',
    'jemu',
    'jeśli',
    'jest',
    'jestem',
    'jeżeli',
    'już',
    'każdy',
    'kiedy',
    'kierunku',
    'kto',
    'ku',
    'lub',
    'ma',
    'mają',
    'mam',
    'mi',
    'mną',
    'mnie',
    'moi',
    'mój',
    'moja',
    'moje',
    'może',
    'mu',
    'my',
    'na',
    'nam',
    'nami',
    'nas',
    'nasi',
    'nasz',
    'nasza',
    'nasze',
    'natychmiast',
    'nią',
    'nic',
    'nich',
    'nie',
    'niego',
    'niej',
    'niemu',
    'nigdy',
    'nim',
    'nimi',
    'niż',
    'obok',
    'od',
    'około',
    'on',
    'ona',
    'one',
    'oni',
    'ono',
    'owszem',
    'po',
    'pod',
    'ponieważ',
    'przed',
    'przedtem',
    'są',
    'sam',
    'sama',
    'się',
    'skąd',
    'tak',
    'taki',
    'tam',
    'ten',
    'to',
    'tobą',
    'tobie',
    'tu',
    'tutaj',
    'twoi',
    'twój',
    'twoja',
    'twoje',
    'ty',
    'wam',
    'wami',
    'was',
    'wasi',
    'wasz',
    'wasza',
    'wasze',
    'we',
    'więc',
    'wszystko',
    'wtedy',
    'wy',
    'żaden',
    'zawsze',
    'że',
];

$result =& $data;
unset($data);
return $result;
<?php

// portuguese

static $data = [
    'de',
    'a',
    'o',
    'que',
    'e',
    'do',
    'da',
    'em',
    'um',
    'para',
    'com',
    'não',
    'uma',
    'os',
    'no',
    'se',
    'na',
    'por',
    'mais',
    'as',
    'dos',
    'como',
    'mas',
    'ao',
    'ele',
    'das',
    'à',
    'seu',
    'sua',
    'ou',
    'quando',
    'muito',
    'nos',
    'já',
    'eu',
    'também',
    'só',
    'pelo',
    'pela',
    'até',
    'isso',
    'ela',
    'entre',
    'depois',
    'sem',
    'mesmo',
    'aos',
    'seus',
    'quem',
    'nas',
    'me',
    'esse',
    'eles',
    'você',
    'essa',
    'num',
    'nem',
    'suas',
    'meu',
    'às',
    'minha',
    'numa',
    'pelos',
    'elas',
    'qual',
    'nós',
    'lhe',
    'deles',
    'essas',
    'esses',
    'pelas',
    'este',
    'dele',
    'tu',
    'te',
    'vocês',
    'vos',
    'lhes',
    'meus',
    'minhas',
    'teu',
    'tua',
    'teus',
    'tuas',
    'nosso',
    'nossa',
    'nossos',
    'nossas',
    'dela',
    'delas',
    'esta',
    'estes',
    'estas',
    'aquele',
    'aquela',
    'aqueles',
    'aquelas',
    'isto',
    'aquilo',
    'estou',
    'está',
    'estamos',
    'estão',
    'estive',
    'esteve',
    'estivemos',
    'estiveram',
    'estava',
    'estávamos',
    'estavam',
    'estivera',
    'estivéramos',
    'esteja',
    'estejamos',
    'estejam',
    'estivesse',
    'estivéssemos',
    'estivessem',
    'estiver',
    'estivermos',
    'estiverem',
    'hei',
    'há',
    'havemos',
    'hão',
    'houve',
    'houvemos',
    'houveram',
    'houvera',
    'houvéramos',
    'haja',
    'hajamos',
    'hajam',
    'houvesse',
    'houvéssemos',
    'houvessem',
    'houver',
    'houvermos',
    'houverem',
    'houverei',
    'houverá',
    'houveremos',
    'houverão',
    'houveria',
    'houveríamos',
    'houveriam',
    'sou',
    'somos',
    'são',
    'era',
    'éramos',
    'eram',
    'fui',
    'foi',
    'fomos',
    'foram',
    'fora',
    'fôramos',
    'seja',
    'sejamos',
    'sejam',
    'fosse',
    'fôssemos',
    'fossem',
    'for',
    'formos',
    'forem',
    'serei',
    'será',
    'seremos',
    'serão',
    'seria',
    'seríamos',
    'seriam',
    'tenho',
    'tem',
    'temos',
    'tém',
    'tinha',
    'tínhamos',
    'tinham',
    'tive',
    'teve',
    'tivemos',
    'tiveram',
    'tivera',
    'tivéramos',
    'tenha',
    'tenhamos',
    'tenham',
    'tivesse',
    'tivéssemos',
    'tivessem',
    'tiver',
    'tivermos',
    'tiverem',
    'terei',
    'terá',
    'teremos',
    'terão',
    'teria',
    'teríamos',
    'teriam',
];

$result =& $data;
unset($data);
return $result;

<?php

// romanian

static $data = [
    'vreo',
    'acelea',
    'cita',
    'degraba',
    'lor',
    'alta',
    'tot',
    'ai',
    'dat',
    'x',
    'despre',
    'peste',
    'bine',
    'dar',
    'foarte',
    'z',
    'avea',
    'multi',
    'cit',
    'alt',
    'mai',
    'sa',
    'fie',
    'tu',
    'multe',
    'e',
    'orice',
    'dintr',
    'se',
    'g',
    'intr',
    'niste',
    'multa',
    'insa',
    'il',
    'fost',
    'a',
    'abia',
    'nimic',
    'sub',
    'acel',
    'in',
    'altceva',
    'si',
    'avem',
    'altfel',
    'c',
    'ea',
    'acest',
    'li',
    'parca',
    'fi',
    'dintre',
    'unele',
    'm',
    'acestei',
    'mare',
    'cel',
    'este',
    'pe',
    'atitia',
    'uneori',
    'acela',
    'iti',
    'astazi',
    'acestui',
    'o',
    'imi',
    'ele',
    'ceilalti',
    'pai',
    'fata',
    'noua',
    'sa-ti',
    'altul',
    'au',
    'i',
    'prin',
    'conform',
    'aceste',
    'anume',
    'azi',
    'k',
    'unul',
    'ala',
    'unei',
    'fara',
    'ei',
    'la',
    'aceeasi',
    'u',
    'inapoi',
    'acestea',
    'acesta',
    'catre',
    'sale',
    'asupra',
    'as',
    'aceea',
    'ba',
    'ale',
    'da',
    'le',
    'apoi',
    'aia',
    'suntem',
    'cum',
    'isi',
    'inainte',
    's',
    'de',
    'cind',
    'cumva',
    'chiar',
    'acestia',
    'daca',
    'sunt',
    'care',
    'al',
    'numai',
    'cui',
    'sus',
    'tocmai',
    'prea',
    'cu',
    'mi',
    'eu',
    'doar',
    'niciodata',
    'exact',
    'putini',
    'aiurea',
    'tuturor',
    'celor',
    'astfel',
    'atunci',
    'citeva',
    'cat',
    'sau',
    'fel',
    'intre',
    'acolo',
    'nostri',
    'ma',
    'mult',
    'una',
    'ceea',
    'iar',
    'sintem',
    'ati',
    'din',
    'geaba',
    'sai',
    'caruia',
    'adica',
    'inca',
    'are',
    'aici',
    'ca',
    'ia',
    'nici',
    'd',
    'oricum',
    'asta',
    'carora',
    'face',
    'citiva',
    'voi',
    'unor',
    'f',
    'atat',
    'toata',
    'alaturi',
    'cea',
    'nu',
    'totusi',
    'ce',
    'altii',
    'acum',
    'sint',
    'capat',
    'mod',
    'deasupra',
    'cam',
    'vom',
    'b',
    'toate',
    'careia',
    'aceasta',
    'atit',
    'nimeni',
    'ii',
    'ci',
    'unde',
    'ul',
    'plus',
    'era',
    'sa-mi',
    'l',
    'spre',
    'dupa',
    'nou',
    'cele',
    'acea',
    'un',
    'incit',
    'n',
    'cei',
    'or',
    'va',
    'deci',
    'acelasi',
    'atatea',
    'h',
    'vor',
    'decit',
    'noi',
    'cineva',
    'desi',
    'ceva',
    'j',
    'ului',
    'atitea',
    'avut',
    'ar',
    'pina',
    't',
    'atata',
    'unui',
    'el',
    'citi',
    'asa',
    'totul',
    'pentru',
    'atita',
    'v',
    'alti',
    'asemenea',
    'atatia',
    'te',
    'ne',
    'deja',
    'unii',
    'p',
    'atare',
    'cite',
    'cine',
    'cand',
    'toti',
    'vreun',
    'ori',
    'r',
    'alte',
    'lui',
    'ti',
    'ni',
    'aceia',
    'am',
];

$result =& $data;
unset($data);
return $result;
<?php

// russian

static $data = [
    'и',
    'в',
    'во',
    'не',
    'что',
    'он',
    'на',
    'я',
    'с',
    'со',
    'как',
    'а',
    'то',
    'все',
    'она',
    'так',
    'его',
    'но',
    'да',
    'ты',
    'к',
    'у',
    'же',
    'вы',
    'за',
    'бы',
    'по',
    'только',
    'ее',
    'мне',
    'было',
    'вот',
    'от',
    'меня',
    'еще',
    'нет',
    'о',
    'из',
    'ему',
    'теперь',
    'когда',
    'даже',
    'ну',
    'вдруг',
    'ли',
    'если',
    'уже',
    'или',
    'ни',
    'быть',
    'был',
    'него',
    'до',
    'вас',
    'нибудь',
    'опять',
    'уж',
    'вам',
    'ведь',
    'там',
    'потом',
    'себя',
    'ничего',
    'ей',
    'может',
    'они',
    'тут',
    'где',
    'есть',
    'надо',
    'ней',
    'для',
    'мы',
    'тебя',
    'их',
    'чем',
    'была',
    'сам',
    'чтоб',
    'без',
    'будто',
    'чего',
    'раз',
    'тоже',
    'себе',
    'под',
    'будет',
    'ж',
    'тогда',
    'кто',
    'этот',
    'того',
    'потому',
    'этого',
    'какой',
    'совсем',
    'ним',
    'здесь',
    'этом',
    'один',
    'почти',
    'мой',
    'тем',
    'чтобы',
    'нее',
    'сейчас',
    'были',
    'куда',
    'зачем',
    'всех',
    'никогда',
    'можно',
    'при',
    'наконец',
    'два',
    'об',
    'другой',
    'хоть',
    'после',
    'над',
    'больше',
    'тот',
    'через',
    'эти',
    'нас',
    'про',
    'всего',
    'них',
    'какая',
    'много',
    'разве',
    'три',
    'эту',
    'моя',
    'впрочем',
    'хорошо',
    'свою',
    'этой',
    'перед',
    'иногда',
    'лучше',
    'чуть',
    'том',
    'нельзя',
    'такой',
    'им',
    'более',
    'всегда',
    'конечно',
    'всю',
    'между',
];

$result =& $data;
unset($data);
return $result;
<?php

// slovak

static $data = [
    'a',
    'aby',
    'aj',
    'ak',
    'ako',
    'ale',
    'alebo',
    'and',
    'ani',
    'áno',
    'asi',
    'až',
    'bez',
    'bude',
    'budem',
    'budeš',
    'budeme',
    'budete',
    'budú',
    'by',
    'bol',
    'bola',
    'boli',
    'bolo',
    'byť',
    'cez',
    'čo',
    'či',
    'ďalší',
    'ďalšia',
    'ďalšie',
    'dnes',
    'do',
    'ho',
    'ešte',
    'for',
    'i',
    'ja',
    'je',
    'jeho',
    'jej',
    'ich',
    'iba',
    'iné',
    'iný',
    'som',
    'si',
    'sme',
    'sú',
    'k',
    'kam',
    'každý',
    'každá',
    'každé',
    'každí',
    'kde',
    'keď',
    'kto',
    'ktorá',
    'ktoré',
    'ktorou',
    'ktorý',
    'ktorí',
    'ku',
    'lebo',
    'len',
    'ma',
    'mať',
    'má',
    'máte',
    'medzi',
    'mi',
    'mna',
    'mne',
    'mnou',
    'musieť',
    'môcť',
    'môj',
    'môže',
    'my',
    'na',
    'nad',
    'nám',
    'náš',
    'naši',
    'nie',
    'nech',
    'než',
    'nič',
    'niektorý',
    'nové',
    'nový',
    'nová',
    'nové',
    'noví',
    'o',
    'od',
    'odo',
    'of',
    'on',
    'ona',
    'ono',
    'oni',
    'ony',
    'po',
    'pod',
    'podľa',
    'pokiaľ',
    'potom',
    'práve',
    'pre',
    'prečo',
    'preto',
    'pretože',
    'prvý',
    'prvá',
    'prvé',
    'prví',
    'pred',
    'predo',
    'pri',
    'pýta',
    's',
    'sa',
    'so',
    'si',
    'svoje',
    'svoj',
    'svojich',
    'svojím',
    'svojími',
    'ta',
    'tak',
    'takže',
    'táto',
    'teda',
    'te',
    'tě',
    'ten',
    'tento',
    'the',
    'tieto',
    'tým',
    'týmto',
    'tiež',
    'to',
    'toto',
    'toho',
    'tohoto',
    'tom',
    'tomto',
    'tomuto',
    'toto',
    'tu',
    'tú',
    'túto',
    'tvoj',
    'ty',
    'tvojími',
    'už',
    'v',
    'vám',
    'váš',
    'vaše',
    'vo',
    'viac',
    'však',
    'všetok',
    'vy',
    'z',
    'za',
    'zo',
    'že',
];

$result =& $data;
unset($data);
return $result;
<?php

// swedish

static $data = [
    'och',
    'det',
    'att',
    'i',
    'en',
    'jag',
    'hon',
    'som',
    'han',
    'på',
    'den',
    'med',
    'var',
    'sig',
    'för',
    'så',
    'till',
    'är',
    'men',
    'ett',
    'om',
    'hade',
    'de',
    'av',
    'icke',
    'mig',
    'du',
    'henne',
    'då',
    'sin',
    'nu',
    'har',
    'inte',
    'hans',
    'honom',
    'skulle',
    'hennes',
    'där',
    'min',
    'man',
    'ej',
    'vid',
    'kunde',
    'något',
    'från',
    'ut',
    'när',
    'efter',
    'upp',
    'vi',
    'dem',
    'vara',
    'vad',
    'över',
    'än',
    'dig',
    'kan',
    'sina',
    'här',
    'ha',
    'mot',
    'alla',
    'under',
    'någon',
    'eller',
    'allt',
    'mycket',
    'sedan',
    'ju',
    'denna',
    'själv',
    'detta',
    'åt',
    'utan',
    'varit',
    'hur',
    'ingen',
    'mitt',
    'ni',
    'bli',
    'blev',
    'oss',
    'din',
    'dessa',
    'några',
    'deras',
    'blir',
    'mina',
    'samma',
    'vilken',
    'er',
    'sådan',
    'vår',
    'blivit',
    'dess',
    'inom',
    'mellan',
    'sådant',
    'varför',
    'varje',
    'vilka',
    'ditt',
    'vem',
    'vilket',
    'sitta',
    'sådana',
    'vart',
    'dina',
    'vars',
    'vårt',
    'våra',
    'ert',
    'era',
    'vilkas',
];

$result =& $data;
unset($data);
return $result;
<?php

// turkish

static $data = [
    'acaba',
    'ama',
    'aslında',
    'az',
    'bazı',
    'belki',
    'biri',
    'birkaç',
    'birşey',
    'biz',
    'bu',
    'çok',
    'çünkü',
    'da',
    'daha',
    'de',
    'defa',
    'diye',
    'eğer',
    'en',
    'gibi',
    'hem',
    'hep',
    'hepsi',
    'her',
    'hiç',
    'için',
    'ile',
    'ise',
    'kez',
    'ki',
    'kim',
    'mı',
    'mu',
    'mü',
    'nasıl',
    'ne',
    'neden',
    'nerde',
    'nerede',
    'nereye',
    'niçin',
    'niye',
    'o',
    'sanki',
    'şey',
    'siz',
    'şu',
    'tüm',
    've',
    'veya',
    'ya',
    'yani',
];

$result =& $data;
unset($data);
return $result;
<?php

// ukrainian

static $data = [
    'a',
    'б',
    'в',
    'г',
    'е',
    'ж',
    'з',
    'м',
    'т',
    'у',
    'я',
    'є',
    'і',
    'аж',
    'ви',
    'де',
    'до',
    'за',
    'зі',
    'ми',
    'на',
    'не',
    'ну',
    'нх',
    'ні',
    'по',
    'та',
    'ти',
    'то',
    'ту',
    'ті',
    'це',
    'цю',
    'ця',
    'ці',
    'чи',
    'ще',
    'що',
    'як',
    'їй',
    'їм',
    'їх',
    'її',
    'або',
    'але',
    'ало',
    'без',
    'був',
    'вам',
    'вас',
    'ваш',
    'вже',
    'все',
    'всю',
    'вся',
    'від',
    'він',
    'два',
    'дві',
    'для',
    'ким',
    'мож',
    'моя',
    'моє',
    'мої',
    'міг',
    'між',
    'мій',
    'над',
    'нам',
    'нас',
    'наш',
    'нею',
    'неї',
    'них',
    'ніж',
    'ній',
    'ось',
    'при',
    'про',
    'під',
    'пір',
    'раз',
    'рік',
    'сам',
    'сих',
    'сім',
    'так',
    'там',
    'теж',
    'тим',
    'тих',
    'той',
    'тою',
    'три',
    'тут',
    'хоч',
    'хто',
    'цей',
    'цим',
    'цих',
    'час',
    'щоб',
    'яка',
    'які',
    'адже',
    'буде',
    'буду',
    'будь',
    'була',
    'були',
    'було',
    'бути',
    'вами',
    'ваша',
    'ваше',
    'ваші',
    'весь',
    'вниз',
    'вона',
    'вони',
    'воно',
    'всею',
    'всім',
    'всіх',
    'втім',
    'геть',
    'далі',
    'двох',
    'день',
    'дуже',
    'зате',
    'його',
    'йому',
    'каже',
    'кого',
    'коли',
    'кому',
    'крім',
    'куди',
    'лише',
    'люди',
    'мало',
    'мати',
    'мене',
    'мені',
    'миру',
    'мною',
    'може',
    'нами',
    'наша',
    'наше',
    'наші',
    'ними',
    'ніби',
    'один',
    'поки',
    'пора',
    'рано',
    'року',
    'році',
    'сама',
    'саме',
    'саму',
    'самі',
    'свою',
    'своє',
    'свої',
    'себе',
    'собі',
    'став',
    'суть',
    'така',
    'таке',
    'такі',
    'твоя',
    'твоє',
    'твій',
    'тебе',
    'тими',
    'тобі',
    'того',
    'тоді',
    'тому',
    'туди',
    'хоча',
    'хіба',
    'цими',
    'цієї',
    'часу',
    'чого',
    'чому',
    'який',
    'яких',
    'якої',
    'якщо',
    'ім\'я',
    'інша',
    'інше',
    'інші',
    'буває',
    'будеш',
    'більш',
    'вгору',
    'вміти',
    'внизу',
    'вісім',
    'давно',
    'даром',
    'добре',
    'довго',
    'друго',
    'дякую',
    'життя',
    'зараз',
    'знову',
    'какая',
    'кожен',
    'кожна',
    'кожне',
    'кожні',
    'краще',
    'ледве',
    'майже',
    'менше',
    'могти',
    'можна',
    'назад',
    'немає',
    'нижче',
    'нього',
    'однак',
    'п\'ять',
    'перед',
    'поруч',
    'потім',
    'проти',
    'після',
    'років',
    'самим',
    'самих',
    'самій',
    'свого',
    'своєї',
    'своїх',
    'собою',
    'справ',
    'такий',
    'також',
    'тепер',
    'тисяч',
    'тобою',
    'треба',
    'трохи',
    'усюди',
    'усіма',
    'хочеш',
    'цього',
    'цьому',
    'часто',
    'через',
    'шість',
    'якого',
    'іноді',
    'інший',
    'інших',
    'багато',
    'будемо',
    'будете',
    'будуть',
    'більше',
    'всього',
    'всьому',
    'далеко',
    'десять',
    'досить',
    'другий',
    'дійсно',
    'завжди',
    'звідси',
    'зовсім',
    'кругом',
    'кілька',
    'людина',
    'можуть',
    'навіть',
    'навіщо',
    'нагорі',
    'небудь',
    'низько',
    'ніколи',
    'нікуди',
    'нічого',
    'обидва',
    'одного',
    'однієї',
    'п\'ятий',
    'перший',
    'просто',
    'раніше',
    'раптом',
    'самими',
    'самого',
    'самому',
    'сказав',
    'скрізь',
    'сьомий',
    'третій',
    'тільки',
    'хотіти',
    'чотири',
    'чудово',
    'шостий',
    'близько',
    'важлива',
    'важливе',
    'важливі',
    'вдалині',
    'восьмий',
    'говорив',
    'дев\'ять',
    'десятий',
    'зайнята',
    'зайнято',
    'зайняті',
    'занадто',
    'значить',
    'навколо',
    'нарешті',
    'нерідко',
    'повинно',
    'посеред',
    'початку',
    'пізніше',
    'сказала',
    'сказати',
    'скільки',
    'спасибі',
    'частіше',
    'важливий',
    'двадцять',
    'дев\'ятий',
    'зазвичай',
    'зайнятий',
    'звичайно',
    'здається',
    'найбільш',
    'не можна',
    'недалеко',
    'особливо',
    'потрібно',
    'спочатку',
    'сьогодні',
    'численна',
    'численне',
    'численні',
    'відсотків',
    'двадцятий',
    'звідусіль',
    'мільйонів',
    'нещодавно',
    'прекрасно',
    'четвертий',
    'численний',
    'будь ласка',
    'дванадцять',
    'одинадцять',
    'сімнадцять',
    'тринадцять',
    'безперервно',
    'дванадцятий',
    'одинадцятий',
    'одного разу',
    'п\'ятнадцять',
    'сімнадцятий',
    'тринадцятий',
    'шістнадцять',
    'вісімнадцять',
    'п\'ятнадцятий',
    'чотирнадцять',
    'шістнадцятий',
    'вісімнадцятий',
    'дев\'ятнадцять',
    'чотирнадцятий',
    'дев\'ятнадцятий',
];

$result =& $data;
unset($data);
return $result;
<?php

// vietnamese

static $data = [
    'a ha',
    'a-lô',
    'ai',
    'ai ai',
    'ai nấy',
    'alô',
    'amen',
    'anh',
    'bao giờ',
    'bao lâu',
    'bao nhiêu',
    'bao nả',
    'bay biến',
    'biết',
    'biết bao',
    'biết bao nhiêu',
    'biết chừng nào',
    'biết mấy',
    'biết đâu',
    'biết đâu chừng',
    'biết đâu đấy',
    'bà',
    'bài',
    'bác',
    'bây bẩy',
    'bây chừ',
    'bây giờ',
    'bây nhiêu',
    'bèn',
    'béng',
    'bông',
    'bạn',
    'bản',
    'bất chợt',
    'bất cứ',
    'bất giác',
    'bất kì',
    'bất kể',
    'bất kỳ',
    'bất luận',
    'bất nhược',
    'bất quá',
    'bất thình lình',
    'bất tử',
    'bất đồ',
    'bấy',
    'bấy chầy',
    'bấy chừ',
    'bấy giờ',
    'bấy lâu',
    'bấy lâu nay',
    'bấy nay',
    'bấy nhiêu',
    'bập bà bập bõm',
    'bập bõm',
    'bắt đầu từ',
    'bằng',
    'bằng không',
    'bằng nấy',
    'bằng ấy',
    'bển',
    'bệt',
    'bị',
    'bỏ mẹ',
    'bỗng',
    'bỗng chốc',
    'bỗng dưng',
    'bỗng không',
    'bỗng nhiên',
    'bỗng đâu',
    'bộ',
    'bội phần',
    'bớ',
    'bởi',
    'bởi chưng',
    'bởi nhưng',
    'bởi thế',
    'bởi vì',
    'bởi vậy',
    'bức',
    'cao',
    'cha',
    'cha chả',
    'chao ôi',
    'chiếc',
    'cho',
    'cho nên',
    'cho tới',
    'cho tới khi',
    'cho đến',
    'cho đến khi',
    'choa',
    'chu cha',
    'chui cha',
    'chung cục',
    'chung qui',
    'chung quy',
    'chung quy lại',
    'chuyện',
    'chành chạnh',
    'chí chết',
    'chính',
    'chính là',
    'chính thị',
    'chùn chùn',
    'chùn chũn',
    'chú',
    'chú mày',
    'chú mình',
    'chúng mình',
    'chúng ta',
    'chúng tôi',
    'chăn chắn',
    'chăng',
    'chưa',
    'chầm chập',
    'chậc',
    'chắc',
    'chắc hẳn',
    'chẳng lẽ',
    'chẳng những',
    'chẳng nữa',
    'chẳng phải',
    'chết nỗi',
    'chết thật',
    'chết tiệt',
    'chỉ',
    'chỉn',
    'chốc chốc',
    'chớ',
    'chớ chi',
    'chợt',
    'chủn',
    'chứ',
    'chứ lị',
    'coi bộ',
    'coi mòi',
    'con',
    'cu cậu',
    'cuốn',
    'cuộc',
    'càng',
    'các',
    'cái',
    'cây',
    'còn',
    'có',
    'có chăng là',
    'có dễ',
    'có thể',
    'có vẻ',
    'cóc khô',
    'cô',
    'cô mình',
    'công nhiên',
    'cùng',
    'cùng cực',
    'cùng nhau',
    'cùng với',
    'căn',
    'căn cắt',
    'cũng',
    'cũng như',
    'cũng vậy',
    'cũng vậy thôi',
    'cơ',
    'cơ chừng',
    'cơ hồ',
    'cơ mà',
    'cơn',
    'cả',
    'cả thảy',
    'cả thể',
    'cảm ơn',
    'cần',
    'cật lực',
    'cật sức',
    'cậu',
    'cổ lai',
    'của',
    'cứ',
    'cứ việc',
    'cực lực',
    'do',
    'do vì',
    'do vậy',
    'do đó',
    'duy',
    'dào',
    'dì',
    'dù cho',
    'dù rằng',
    'dưới',
    'dạ',
    'dần dà',
    'dần dần',
    'dầu sao',
    'dẫu',
    'dẫu sao',
    'dễ sợ',
    'dễ thường',
    'dở chừng',
    'dữ',
    'em',
    'giữa',
    'gì',
    'hay',
    'hoàn toàn',
    'hoặc',
    'hơn',
    'hầu hết',
    'họ',
    'hỏi',
    'khi',
    'khác',
    'không',
    'luôn',
    'là',
    'làm',
    'lên',
    'lúc',
    'lại',
    'lần',
    'lớn',
    'muốn',
    'mà',
    'mình',
    'mỗi',
    'một',
    'một cách',
    'mới',
    'mợ',
    'ngay',
    'ngay cả',
    'ngay khi',
    'ngay lúc',
    'ngay lập tức',
    'ngay tức khắc',
    'ngay từ',
    'nghe chừng',
    'nghe đâu',
    'nghen',
    'nghiễm nhiên',
    'nghỉm',
    'ngoài',
    'ngoài ra',
    'ngoải',
    'ngày',
    'ngày càng',
    'ngày ngày',
    'ngày xưa',
    'ngày xửa',
    'ngôi',
    'ngõ hầu',
    'ngăn ngắt',
    'ngươi',
    'người',
    'ngọn',
    'ngọt',
    'ngộ nhỡ',
    'nh',
    'nhau',
    'nhiên hậu',
    'nhiều',
    'nhiệt liệt',
    'nhung nhăng',
    'nhà',
    'nhân dịp',
    'nhân tiện',
    'nhé',
    'nhón nhén',
    'như',
    'như chơi',
    'như không',
    'như quả',
    'như thể',
    'như tuồng',
    'như vậy',
    'nhưng',
    'nhưng mà',
    'nhược bằng',
    'nhất',
    'nhất loạt',
    'nhất luật',
    'nhất mực',
    'nhất nhất',
    'nhất quyết',
    'nhất sinh',
    'nhất thiết',
    'nhất tâm',
    'nhất tề',
    'nhất đán',
    'nhất định',
    'nhận',
    'nhỉ',
    'nhỡ ra',
    'những',
    'những ai',
    'những như',
    'nào',
    'này',
    'nên',
    'nên chi',
    'nó',
    'nóc',
    'nói',
    'năm',
    'nơi',
    'nấy',
    'nếu',
    'nếu như',
    'nền',
    'nọ',
    'nớ',
    'nức nở',
    'nữa',
    'oai oái',
    'oái',
    'pho',
    'phè',
    'phóc',
    'phót',
    'phăn phắt',
    'phương chi',
    'phải',
    'phải chi',
    'phải chăng',
    'phắt',
    'phỉ phui',
    'phỏng',
    'phỏng như',
    'phốc',
    'phụt',
    'phứt',
    'qua',
    'qua quít',
    'qua quýt',
    'quyết',
    'quyết nhiên',
    'quyển',
    'quá',
    'quá chừng',
    'quá lắm',
    'quá sá',
    'quá thể',
    'quá trời',
    'quá xá',
    'quá đỗi',
    'quá độ',
    'quá ư',
    'quý hồ',
    'quả',
    'quả là',
    'quả tang',
    'quả thật',
    'quả tình',
    'quả vậy',
    'quả đúng',
    'ra',
    'ra phết',
    'ra sao',
    'ra trò',
    'ren rén',
    'riu ríu',
    'riêng',
    'riệt',
    'rày',
    'ráo',
    'ráo trọi',
    'rén',
    'rích',
    'rón rén',
    'rút cục',
    'răng',
    'rất',
    'rằng',
    'rằng là',
    'rốt cuộc',
    'rốt cục',
    'rồi',
    'rứa',
    'sa sả',
    'sao',
    'sau',
    'sau chót',
    'sau cuối',
    'sau cùng',
    'sau đó',
    'so',
    'song le',
    'suýt',
    'sì',
    'sạch',
    'sất',
    'sắp',
    'sẽ',
    'số',
    'số là',
    'sốt sột',
    'sở dĩ',
    'sự',
    'tanh',
    'tha hồ',
    'than ôi',
    'thanh',
    'theo',
    'thi thoảng',
    'thoạt',
    'thoạt nhiên',
    'thoắt',
    'thuần',
    'thà',
    'thà là',
    'thà rằng',
    'thành ra',
    'thành thử',
    'thái quá',
    'tháng',
    'thì',
    'thì thôi',
    'thình lình',
    'thím',
    'thôi',
    'thúng thắng',
    'thương ôi',
    'thường',
    'thảo hèn',
    'thảo nào',
    'thấy',
    'thẩy',
    'thậm',
    'thậm chí',
    'thật lực',
    'thật ra',
    'thật vậy',
    'thế',
    'thế là',
    'thế mà',
    'thế nào',
    'thế nên',
    'thế ra',
    'thế thì',
    'thế à',
    'thếch',
    'thỉnh thoảng',
    'thỏm',
    'thốc',
    'thốc tháo',
    'thốt',
    'thốt nhiên',
    'thộc',
    'thời gian',
    'thục mạng',
    'thửa',
    'thực ra',
    'thực sự',
    'thực vậy',
    'tiếp theo',
    'tiếp đó',
    'tiện thể',
    'toà',
    'toé khói',
    'toẹt',
    'trong',
    'trên',
    'trước',
    'trước kia',
    'trước nay',
    'trước tiên',
    'trước đây',
    'trước đó',
    'trếu tráo',
    'trển',
    'trệt',
    'trệu trạo',
    'trỏng',
    'trời đất ơi',
    'trừ phi',
    'tuy',
    'tuy nhiên',
    'tuy rằng',
    'tuy thế',
    'tuy vậy',
    'tuyệt nhiên',
    'tuần tự',
    'tuốt luốt',
    'tuốt tuồn tuột',
    'tuốt tuột',
    'tà tà',
    'tênh',
    'tít mù',
    'tò te',
    'tôi',
    'tông tốc',
    'tù tì',
    'tăm tắp',
    'tại',
    'tại vì',
    'tấm',
    'tấn',
    'tất cả',
    'tất thảy',
    'tất tần tật',
    'tất tật',
    'tắp',
    'tắp lự',
    'tọt',
    'tỏ ra',
    'tỏ vẻ',
    'tốc tả',
    'tối ư',
    'tột',
    'tớ',
    'tới',
    'tức thì',
    'tức tốc',
    'từ',
    'từng',
    'tự vì',
    'tựu trung',
    'veo',
    'veo veo',
    'việc',
    'vung thiên địa',
    'vung tàn tán',
    'vung tán tàn',
    'và',
    'vào',
    'vâng',
    'vèo',
    'vì',
    'vì chưng',
    'vì thế',
    'vì vậy',
    'ví bằng',
    'ví dù',
    'ví phỏng',
    'ví thử',
    'vô hình trung',
    'vô kể',
    'vô luận',
    'vô vàn',
    'văng tê',
    'vạn nhất',
    'vả chăng',
    'vả lại',
    'vẫn',
    'vậy',
    'vậy là',
    'vậy thì',
    'về',
    'vị tất',
    'vốn dĩ',
    'với',
    'với lại',
    'vở',
    'vụt',
    'vừa',
    'vừa mới',
    'xa xả',
    'xiết bao',
    'xon xón',
    'xoành xoạch',
    'xoét',
    'xoẳn',
    'xoẹt',
    'xuất kì bất ý',
    'xuất kỳ bất ý',
    'xuể',
    'xuống',
    'xăm xúi',
    'xăm xăm',
    'xăm xắm',
    'xềnh xệch',
    'xệp',
    'à',
    'à ơi',
    'ào',
    'á',
    'á à',
    'ái',
    'ái chà',
    'ái dà',
    'áng',
    'âu là',
    'ô hay',
    'ô hô',
    'ô kê',
    'ô kìa',
    'ôi chao',
    'ôi thôi',
    'ông',
    'úi',
    'úi chà',
    'úi dào',
    'ý',
    'ý chừng',
    'ý da',
    'đang',
    'đi',
    'điều',
    'đành đạch',
    'đáng lí',
    'đáng lý',
    'đáng lẽ',
    'đánh đùng',
    'đáo để',
    'đây',
    'đã',
    'đó',
    'được',
    'đại loại',
    'đại nhân',
    'đại phàm',
    'đại để',
    'đến',
    'đến nỗi',
    'đều',
    'để',
    'ơ',
    'ơ hay',
    'ơ kìa',
    'ơi',
    'ư',
    'ạ',
    'ạ ơi',
    'ấy',
    'ầu ơ',
    'ắt',
    'ắt hẳn',
    'ắt là',
    'ối dào',
    'ối giời',
    'ối giời ơi',
    'ồ',
    'ổng',
    'ớ',
    'ờ',
    'ở',
    'ở trên',
    'ủa',
    'ứ hự',
    'ứ ừ',
    'ừ',
    'ử',
];

$result =& $data;
unset($data);
return $result;
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * Phonetic-Helper-Class
 *
 * @package voku\helper
 */
final class StopWords
{
  /**
   * @var array
   */
  private static $availableLanguages = array(
      'ar',
      'bg',
      'ca',
      'cz',
      'da',
      'de',
      'el',
      'en',
      'eo',
      'es',
      'et',
      'fi',
      'fr',
      'hi',
      'hr',
      'hu',
      'id',
      'it',
      'ka',
      'lt',
      'lv',
      'nl',
      'no',
      'pl',
      'pt',
      'ro',
      'ru',
      'sk',
      'sv',
      'tr',
      'uk',
      'vi'
  );

  /**
   * @var array
   */
  private $stopWords = array();

  /**
   * Load language-data from one language.
   *
   * @param string $language
   *
   * @throws StopWordsLanguageNotExists
   */
  private function loadLanguageData(string $language = 'de')
  {
    if (\in_array($language, self::$availableLanguages, true) === false) {
      throw new StopWordsLanguageNotExists('language not supported: ' . $language);
    }

    $this->stopWords[$language] = $this->getData($language);
  }

  /**
   * Get data from "/data/*.php".
   *
   * @param string $file
   *
   * @return array <p>Will return an empty array on error.</p>
   */
  private function getData(string $file): array
  {
    static $RESULT_STOP_WORDS_CACHE = array();

    if (isset($RESULT_STOP_WORDS_CACHE[$file])) {
      return $RESULT_STOP_WORDS_CACHE[$file];
    }

    $file = __DIR__ . '/stopwords/' . $file . '.php';
    if (file_exists($file)) {
      /** @noinspection PhpIncludeInspection */
      $RESULT_STOP_WORDS_CACHE[$file] = require $file;
    } else {
      $RESULT_STOP_WORDS_CACHE[$file] = array();
    }

    return $RESULT_STOP_WORDS_CACHE[$file];
  }

  /**
   * Get the stop-words from one language.
   *
   * @param string $language
   *
   * @return array
   *
   * @throws StopWordsLanguageNotExists
   */
  public function getStopWordsFromLanguage(string $language = 'de'): array
  {
    if (\in_array($language, self::$availableLanguages, true) === false) {
      throw new StopWordsLanguageNotExists('language not supported: ' . $language);
    }

    if (!isset($this->stopWords[$language])) {
      $this->loadLanguageData($language);
    }

    return $this->stopWords[$language];
  }

  private function loadLanguageDataAll()
  {
    foreach (self::$availableLanguages as $language) {
      if (!isset($this->stopWords[$language])) {
        $this->loadLanguageData($language);
      }
    }
  }

  /**
   * Get all stop-words from all languages.
   *
   * @return array
   *
   * @throws StopWordsLanguageNotExists
   */
  public function getStopWordsAll(): array
  {
    $this->loadLanguageDataAll();

    return $this->stopWords;
  }
}
<?php

declare(strict_types=1);

namespace voku\helper;

/**
 * PhoneticExceptionLanguageNotExists-Helper-Class
 *
 * @package voku\helper
 */
class StopWordsLanguageNotExists extends \Exception
{
}
<?php

/** @noinspection ReturnTypeCanBeDeclaredInspection */

declare(strict_types=1);

namespace voku\helper;

/**
 * A PHP port of URLify.js from the Django project + fallback via "Portable UTF-8".
 *
 * - https://github.com/django/django/blob/master/django/contrib/admin/static/admin/js/urlify.js
 * - https://github.com/voku/portable-ascii
 * - https://github.com/voku/portable-utf8
 *
 * Handles symbols from latin languages, Arabic, Azerbaijani, Bulgarian, Burmese, Croatian, Czech, Danish, Esperanto,
 * Estonian, Finnish, French, Switzerland (French), Austrian (French), Georgian, German, Switzerland (German),
 * Austrian (German), Greek, Hindi, Kazakh, Latvian, Lithuanian, Norwegian, Persian, Polish, Romanian, Russian, Swedish,
 * Serbian, Slovak, Turkish, Ukrainian and Vietnamese ... and many other via "ASCII::to_transliterate()".
 */
class URLify
{
    /**
     * The language-mapping array.
     *
     * ISO 639-1 codes: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
     *
     * @var array[]
     */
    public static $maps = [];

    /**
     * List of words to remove from URLs.
     *
     * @var array[]
     */
    public static $remove_list = [];

    /**
     * An array of strings that will convert into the separator-char - used by "URLify::filter()".
     *
     * @var string[]
     */
    private static $arrayToSeparator = [];

    /**
     * Add new strings the will be replaced with the separator.
     *
     * @param array $array <p>An array of things that should replaced by the separator.</p>
     * @param bool  $merge <p>Keep the previous (default) array-to-separator array.</p>
     *
     * @return void
     *
     * @psalm-param string[] $array
     */
    public static function add_array_to_separator(array $array, bool $merge = true)
    {
        if ($merge === true) {
            self::$arrayToSeparator = \array_unique(
                \array_merge(
                    self::$arrayToSeparator,
                    $array
                )
            );
        } else {
            self::$arrayToSeparator = $array;
        }
    }

    /**
     * Add new characters to the list. `$map` should be a hash.
     *
     * @param array       $map
     * @param string|null $language
     *
     * @return void
     *
     * @psalm-param array<string, string> $map
     */
    public static function add_chars(array $map, string $language = null)
    {
        $language_key = $language ?? \uniqid('urlify', true);

        if (isset(self::$maps[$language_key])) {
            self::$maps[$language_key] = \array_merge($map, self::$maps[$language_key]);
        } else {
            self::$maps[$language_key] = $map;
        }
    }

    /**
     * Append words to the remove list. Accepts either single words or an array of words.
     *
     * @param string|string[] $words
     * @param string          $language
     * @param bool            $merge    <p>Keep the previous (default) remove-words array.</p>
     *
     * @return void
     */
    public static function add_remove_list($words, string $language = 'en', bool $merge = true)
    {
        if (\is_array($words) === false) {
            $words = [$words];
        }

        foreach ($words as $removeWordKey => $removeWord) {
            $words[$removeWordKey] = \preg_quote($removeWord, '/');
        }

        if ($merge === true) {
            self::$remove_list[$language] = \array_unique(
                \array_merge(
                    self::get_remove_list($language),
                    $words
                )
            );
        } else {
            self::$remove_list[$language] = $words;
        }
    }

    /**
     * Transliterates characters to their ASCII equivalents.
     * $language specifies a priority for a specific language.
     * The latter is useful if languages have different rules for the same character.
     *
     * @param string $string                            <p>The input string.</p>
     * @param string $language                          <p>Your primary language.</p>
     * @param bool   $convertToAsciiOnlyViaLanguageMaps <p>
     *                                                  Set to <strong>true</strong> if you only want to convert the
     *                                                  language-maps.
     *                                                  (better performance, but less complete ASCII converting)
     *                                                  </p>
     * @param string $unknown                           <p>Character use if character unknown. (default is ?).</p>
     * @param bool   $convertUtf8Specials               <p>
     *                                                  Convert (html) special chars with portable-utf8 (e.g. \0,
     *                                                  \xE9, %F6, ...).
     *                                                  </p>
     * @param bool   $expandString                      <p>Expand strings like 1$ into 1 Dollar.</p>
     *
     * @return string
     */
    public static function downcode(
        string $string,
        string $language = 'en',
        bool $convertToAsciiOnlyViaLanguageMaps = false,
        string $unknown = '',
        bool $convertUtf8Specials = true,
        bool $expandString = true
    ): string {
        if ($convertUtf8Specials === true) {
            $string = UTF8::rawurldecode($string);
        }

        if ($expandString === true) {
            $string = self::expandString($string, $language);
        }

        foreach (self::$maps as $mapsInner) {
            foreach ($mapsInner as $orig => $replace) {
                $string = \str_replace($orig, $replace, $string);
            }
        }

        $string = ASCII::to_ascii(
            $string,
            $language,
            false,
            true
        );

        if ($convertToAsciiOnlyViaLanguageMaps === true) {
            return $string;
        }

        return ASCII::to_transliterate($string, $unknown, false);
    }

    /**
     * Convert a String to URL.
     *
     * e.g.: "Petty<br>theft" to "Petty-theft"
     *
     * @param string $string                            <p>The text you want to convert.</p>
     * @param int    $maxLength                         <p>Max. length of the output string, set to "0" (zero) to
     *                                                  disable it</p>
     * @param string $language                          <p>The language you want to convert to.</p>
     * @param bool   $fileName                          <p>
     *                                                  Keep the "." from the extension e.g.: "imaäe.jpg" =>
     *                                                  "image.jpg"
     *                                                  </p>
     * @param bool   $removeWords                       <p>
     *                                                  Remove some "words" from the string.<br />
     *                                                  Info: Set extra words via <strong>remove_words()</strong>.
     *                                                  </p>
     * @param bool   $strToLower                        <p>Use <strong>strtolower()</strong> at the end.</p>
     * @param string $separator                         <p>Define a new separator for the words.</p>
     * @param bool   $convertToAsciiOnlyViaLanguageMaps <p>
     *                                                  Set to <strong>true</strong> if you only want to convert the
     *                                                  language-maps.
     *                                                  (better performance, but less complete ASCII converting)
     *                                                  </p>
     * @param bool   $convertUtf8Specials               <p>
     *                                                  Convert (html) special chars with portable-utf8 (e.g. \0,
     *                                                  \xE9, %F6, ...).
     *                                                  </p>
     * @param bool   $expandString                      <p>Expand strings like 1$ into 1 Dollar.</p>
     *
     * @return string
     */
    public static function filter(
        string $string,
        int $maxLength = 200,
        string $language = 'en',
        bool $fileName = false,
        bool $removeWords = false,
        bool $strToLower = false,
        string $separator = '-',
        bool $convertToAsciiOnlyViaLanguageMaps = false,
        bool $convertUtf8Specials = false,
        bool $expandString = false
    ): string {
        if ($language === '' || $string === '') {
            return '';
        }

        // fallback
        if ($separator === '') {
            $separator = '-';
        }

        // use defaults, if there are no values
        if (self::$arrayToSeparator === []) {
            self::reset_array_to_separator();
        }

        // 1) clean invalid chars
        if ($convertUtf8Specials) {
            $string = ASCII::clean(
                $string,
                true,
                true,
                true,
                true
            );
        }

        // 2) remove apostrophes which are not used as quotes around a string
        if (\strpos($string, "'") !== false) {
            $stringTmp = \preg_replace("/(\w)'(\w)/u", '${1}${2}', $string);
            if ($stringTmp !== null) {
                $string = (string) $stringTmp;
            }
        }

        // 3) replace with $separator
        $string = (string) \preg_replace(
            self::$arrayToSeparator,
            $separator,
            $string
        );

        // 4) remove all other html-tags
        if (
            \strpos($string, '<') !== false
            ||
            \strpos($string, '>') !== false
        ) {
            $string = \strip_tags($string);
        }

        // 5) use special language replacer
        $string = self::downcode(
            $string,
            $language,
            $convertToAsciiOnlyViaLanguageMaps,
            '',
            $convertUtf8Specials,
            $expandString
        );

        // 6) replace with $separator, again
        $string = (string) \preg_replace(
            self::$arrayToSeparator,
            $separator,
            $string
        );

        // remove all these words from the string before urlifying
        $removeWordsSearch = '//';
        if ($removeWords === true) {
            $removeList = self::get_remove_list($language);
            if ($removeList !== []) {
                $removeWordsSearch = '/\b(?:' . \implode('|', $removeList) . ')\b/ui';
            }
        }

        // keep the "." from e.g.: a file-extension?
        if ($fileName) {
            $removePatternAddOn = '.';
        } else {
            $removePatternAddOn = '';
        }

        // escaped separator
        $separatorEscaped = \preg_quote($separator, '/');

        $string = (string) \preg_replace(
            [
                // 1) remove un-needed chars
                '/[^' . $separatorEscaped . $removePatternAddOn . '\-a-zA-Z0-9\s]/u',
                // 2) convert spaces to $separator
                '/[\s]+/u',
                // 3) remove some extras words
                $removeWordsSearch,
                // 4) remove double $separator's
                '/[' . ($separatorEscaped ?: ' ') . ']+/u',
                // 5) remove $separator at the end
                '/[' . ($separatorEscaped ?: ' ') . ']+$/u',
            ],
            [
                '',
                $separator,
                '',
                $separator,
                '',
            ],
            $string
        );

        // "substr" only if "$length" is set
        if (
            $maxLength
            &&
            $maxLength > 0
            &&
            \strlen($string) > $maxLength
        ) {
            $string = (string) \substr(\trim($string, $separator), 0, $maxLength);
        }

        // convert to lowercase
        if ($strToLower === true) {
            $string = \strtolower($string);
        }

        // trim "$separator" from beginning and end of the string
        return \trim($string, $separator);
    }

    /**
     * @param string|string[] $words
     * @param string          $language
     * @param bool            $merge
     *
     * @see        self::add_remove_list
     * @deprecated <p>Please use URLify::add_remove_list().</p>
     *
     * @return void
     */
    public static function remove_words($words, string $language = 'en', bool $merge = true)
    {
        self::add_remove_list($words, $language, $merge);
    }

    /**
     * Reset the internal "self::$arrayToSeparator" to the default values.
     *
     * @return void
     */
    public static function reset_array_to_separator()
    {
        self::$arrayToSeparator = [
            '/&quot;|&amp;|&lt;|&gt;|&ndash;|&mdash;/i',  // ", &, <, >, –, —
            '/⁻|-|—|_|"|`|´|\'/',
            "#/\r\n|\r|\n|<br.*/?>#isU",
        ];
    }

    /**
     * @return void
     */
    public static function reset_chars()
    {
        self::$maps = [];
    }

    /**
     * reset the word-remove-array
     *
     * @param string $language
     *
     * @return void
     */
    public static function reset_remove_list(string $language = 'en')
    {
        if ($language === '') {
            return;
        }

        $language_orig = $language;
        $language = self::get_language_for_reset_remove_list($language);
        if ($language === '') {
            return;
        }

        $stopWords = new StopWords();

        try {
            self::$remove_list[$language_orig] = $stopWords->getStopWordsFromLanguage($language);
        } catch (StopWordsLanguageNotExists $e) {
            self::$remove_list[$language_orig] = [];
        }
    }

    /**
     * slug
     *
     * @param string $string
     * @param string $language
     * @param string $separator
     * @param bool   $strToLower
     *
     * @return string
     */
    public static function slug(
        string $string,
        string $language = 'en',
        string $separator = '-',
        bool $strToLower = false
    ): string {
        return self::filter(
            $string,
            200,
            $language,
            false,
            false,
            $strToLower,
            $separator,
            false,
            true,
            true
        );
    }

    /**
     * Alias of `URLify::downcode()`.
     *
     * @param string $string
     * @param string $language
     *
     * @return string
     */
    public static function transliterate(string $string, string $language = 'en'): string
    {
        return self::downcode($string, $language);
    }

    /**
     * Expands the given string replacing some special parts for words.
     * e.g. "lorem@ipsum.com" is replaced by "lorem at ipsum dot com".
     *
     * Most of these transformations have been inspired by the pelle/slugger
     * project, distributed under the Eclipse Public License.
     * Copyright 2012 Pelle Braendgaard
     *
     * @param string $string   The string to expand
     * @param string $language
     *
     * @return string The result of expanding the string
     */
    protected static function expandString(string $string, string $language = 'en'): string
    {
        $string = self::expandCurrencies($string, $language);

        return self::expandSymbols($string, $language);
    }

    /**
     * @param string $language
     *
     * @return string
     */
    private static function get_language_for_reset_remove_list(string $language)
    {
        if ($language === '') {
            return '';
        }

        if (
            \strpos($language, '_') === false
            &&
            \strpos($language, '-') === false
        ) {
            $language = \strtolower($language);
        } else {
            $regex = '/(?<first>[a-z]{2}).*/i';
            $language = \strtolower((string) \preg_replace($regex, '$1', $language));
        }

        return $language;
    }

    /**
     * Expands the numeric currencies in euros, dollars, pounds
     * and yens that the given string may include.
     *
     * @param string $string
     * @param string $language
     *
     * @return string
     */
    private static function expandCurrencies(string $string, string $language = 'en')
    {
        if (
            \strpos($string, '€') === false
            &&
            \strpos($string, '$') === false
            &&
            \strpos($string, '£') === false
            &&
            \strpos($string, '¥') === false
        ) {
            return $string;
        }

        if ($language === 'de') {
            return (string) \preg_replace(
                [
                    '/(?:\s|^)(\d+)(?: )*€(?:\s|$)/',
                    '/(?:\s|^)\$(?: )*(\d+)(?:\s|$)/',
                    '/(?:\s|^)£(?: )*(\d+)(?:\s|$)/',
                    '/(?:\s|^)¥(?: )*(\d+)(?:\s|$)/',
                    '/(?:\s|^)(\d+)[.|,](\d+)(?: )*€(?:\s|$)/',
                    '/(?:\s|^)\$(?: )*(\d+)[.|,](\d+)(?:\s|$)/',
                    '/(?:\s|^)£(?: )*(\d+)[.|,](\d+)(?:\s|$)/',
                ],
                [
                    ' \1 Euro ',
                    ' \1 Dollar ',
                    ' \1 Pound ',
                    ' \1 Yen ',
                    ' \1 Euro \2 Cent ',
                    ' \1 Dollar \2 Cent ',
                    ' \1 Pound \2 Pence ',
                ],
                $string
            );
        }

        return (string) \preg_replace(
            [
                '/(?:\s|^)1(?: )*€(?:\s|$)/',
                '/(?:\s|^)(\d+)(?: )*€(?:\s|$)/',
                '/(?:\s|^)\$(?: )*1(?:\s|$)/',
                '/(?:\s|^)\$(?: )*(\d+)(?:\s|$)/',
                '/(?:\s|^)£(?: )*1(?:\s|$)/',
                '/(?:\s|^)£(?: )*(\d+)(?:\s|$)/',
                '/(?:\s|^)¥(?: )*(\d+)(?:\s|$)/',
                '/(?:\s|^)1[.|,](\d+)(?: )*€(?:\s|$)/',
                '/(?:\s|^)(\d+)[.|,](\d+)(?: )*€(?:\s|$)/',
                '/(?:\s|^)1[.|,](\d+)(?: )*$(?:\s|$)/',
                '/(?:\s|^)\$(?: )*(\d+)[.|,](\d+)(?:\s|$)/',
                '/(?:\s|^)1[.|,](\d+)(?: )*£(?:\s|$)/',
                '/(?:\s|^)£(?: )*(\d+)[.|,](\d+)(?:\s|$)/',
            ],
            [
                ' 1 Euro ',
                ' \1 Euros ',
                ' 1 Dollar ',
                ' \1 Dollars ',
                ' 1 Pound ',
                ' \1 Pounds ',
                ' \1 Yen ',
                ' 1 Euros \1 Cents ',
                ' \1 Euros \2 Cents ',
                ' 1 Dollars \1 Cents ',
                ' \1 Dollars \2 Cents ',
                ' 1 Pounds \1 Pence ',
                ' \1 Pounds \2 Pence ',
            ],
            $string
        );
    }

    /**
     * Expands the special symbols that the given string may include, such as '@', '.', '#' and '%'.
     *
     * @param string $string
     * @param string $language
     *
     * @return string
     */
    private static function expandSymbols(string $string, string $language = 'en')
    {
        if (
            \strpos($string, '©') === false
            &&
            \strpos($string, '®') === false
            &&
            \strpos($string, '@') === false
            &&
            \strpos($string, '&') === false
            &&
            \strpos($string, '%') === false
            &&
            \strpos($string, '=') === false
        ) {
            return $string;
        }

        $maps = ASCII::charsArray(true);

        return (string) \preg_replace(
            [
                '/\s*©\s*/',
                '/\s*®\s*/',
                '/\s*@\s*/',
                '/\s*&\s*/',
                '/\s*%\s*/',
                '/(\s*=\s*)/',
            ],
            [
                $maps['latin_symbols']['©'],
                $maps['latin_symbols']['®'],
                $maps['latin_symbols']['@'],
                $maps[$language]['&'] ?? '&',
                $maps[$language]['%'] ?? '%',
                $maps[$language]['='] ?? '=',
            ],
            $string
        );
    }

    /**
     * return the "self::$remove_list[$language]" array
     *
     * @param string $language
     *
     * @return array<mixed>
     */
    private static function get_remove_list(string $language = 'en')
    {
        // check for language
        if ($language === '') {
            return [];
        }

        // set remove-array
        if (!isset(self::$remove_list[$language])) {
            self::reset_remove_list($language);
        }

        // check for array
        if (
            !isset(self::$remove_list[$language])
            ||
            empty(self::$remove_list[$language])
        ) {
            return [];
        }

        return self::$remove_list[$language];
    }
}
<?php

/*
 * This file is part of the webmozart/assert package.
 *
 * (c) Bernhard Schussek <bschussek@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Webmozart\Assert;

use ArrayAccess;
use BadMethodCallException;
use Closure;
use Countable;
use DateTime;
use DateTimeImmutable;
use Exception;
use ResourceBundle;
use SimpleXMLElement;
use Throwable;
use Traversable;

/**
 * Efficient assertions to validate the input/output of your methods.
 *
 * @since  1.0
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 */
class Assert
{
    use Mixin;

    /**
     * @psalm-pure
     * @psalm-assert string $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function string($value, $message = '')
    {
        if (!\is_string($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a string. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert non-empty-string $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function stringNotEmpty($value, $message = '')
    {
        static::string($value, $message);
        static::notEq($value, '', $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert int $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function integer($value, $message = '')
    {
        if (!\is_int($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an integer. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert numeric $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function integerish($value, $message = '')
    {
        if (!\is_numeric($value) || $value != (int) $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an integerish value. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert positive-int $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function positiveInteger($value, $message = '')
    {
        if (!(\is_int($value) && $value > 0)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a positive integer. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert float $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function float($value, $message = '')
    {
        if (!\is_float($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a float. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert numeric $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function numeric($value, $message = '')
    {
        if (!\is_numeric($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a numeric. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert positive-int|0 $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function natural($value, $message = '')
    {
        if (!\is_int($value) || $value < 0) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a non-negative integer. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert bool $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function boolean($value, $message = '')
    {
        if (!\is_bool($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a boolean. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert scalar $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function scalar($value, $message = '')
    {
        if (!\is_scalar($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a scalar. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert object $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function object($value, $message = '')
    {
        if (!\is_object($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an object. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert resource $value
     *
     * @param mixed       $value
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
     * @param string      $message
     *
     * @throws InvalidArgumentException
     */
    public static function resource($value, $type = null, $message = '')
    {
        if (!\is_resource($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a resource. Got: %s',
                static::typeToString($value)
            ));
        }

        if ($type && $type !== \get_resource_type($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a resource of type %2$s. Got: %s',
                static::typeToString($value),
                $type
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert callable $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isCallable($value, $message = '')
    {
        if (!\is_callable($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a callable. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert array $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isArray($value, $message = '')
    {
        if (!\is_array($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable $value
     *
     * @deprecated use "isIterable" or "isInstanceOf" instead
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isTraversable($value, $message = '')
    {
        @\trigger_error(
            \sprintf(
                'The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.',
                __METHOD__
            ),
            \E_USER_DEPRECATED
        );

        if (!\is_array($value) && !($value instanceof Traversable)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a traversable. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert array|ArrayAccess $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isArrayAccessible($value, $message = '')
    {
        if (!\is_array($value) && !($value instanceof ArrayAccess)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array accessible. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert countable $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isCountable($value, $message = '')
    {
        if (
            !\is_array($value)
            && !($value instanceof Countable)
            && !($value instanceof ResourceBundle)
            && !($value instanceof SimpleXMLElement)
        ) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a countable. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isIterable($value, $message = '')
    {
        if (!\is_array($value) && !($value instanceof Traversable)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an iterable. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert ExpectedType $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function isInstanceOf($value, $class, $message = '')
    {
        if (!($value instanceof $class)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an instance of %2$s. Got: %s',
                static::typeToString($value),
                $class
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert !ExpectedType $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function notInstanceOf($value, $class, $message = '')
    {
        if ($value instanceof $class) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an instance other than %2$s. Got: %s',
                static::typeToString($value),
                $class
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param mixed                $value
     * @param array<object|string> $classes
     * @param string               $message
     *
     * @throws InvalidArgumentException
     */
    public static function isInstanceOfAny($value, array $classes, $message = '')
    {
        foreach ($classes as $class) {
            if ($value instanceof $class) {
                return;
            }
        }

        static::reportInvalidArgument(\sprintf(
            $message ?: 'Expected an instance of any of %2$s. Got: %s',
            static::typeToString($value),
            \implode(', ', \array_map(array(static::class, 'valueToString'), $classes))
        ));
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert ExpectedType|class-string<ExpectedType> $value
     *
     * @param object|string $value
     * @param string        $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function isAOf($value, $class, $message = '')
    {
        static::string($class, 'Expected class as a string. Got: %s');

        if (!\is_a($value, $class, \is_string($value))) {
            static::reportInvalidArgument(sprintf(
                $message ?: 'Expected an instance of this class or to this class among its parents "%2$s". Got: %s',
                static::valueToString($value),
                $class
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-template UnexpectedType of object
     * @psalm-param class-string<UnexpectedType> $class
     * @psalm-assert !UnexpectedType $value
     * @psalm-assert !class-string<UnexpectedType> $value
     *
     * @param object|string $value
     * @param string        $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function isNotA($value, $class, $message = '')
    {
        static::string($class, 'Expected class as a string. Got: %s');

        if (\is_a($value, $class, \is_string($value))) {
            static::reportInvalidArgument(sprintf(
                $message ?: 'Expected an instance of this class or to this class among its parents other than "%2$s". Got: %s',
                static::valueToString($value),
                $class
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param object|string $value
     * @param string[]      $classes
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function isAnyOf($value, array $classes, $message = '')
    {
        foreach ($classes as $class) {
            static::string($class, 'Expected class as a string. Got: %s');

            if (\is_a($value, $class, \is_string($value))) {
                return;
            }
        }

        static::reportInvalidArgument(sprintf(
            $message ?: 'Expected an instance of any of this classes or any of those classes among their parents "%2$s". Got: %s',
            static::valueToString($value),
            \implode(', ', $classes)
        ));
    }

    /**
     * @psalm-pure
     * @psalm-assert empty $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isEmpty($value, $message = '')
    {
        if (!empty($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an empty value. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert !empty $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notEmpty($value, $message = '')
    {
        if (empty($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a non-empty value. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function null($value, $message = '')
    {
        if (null !== $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected null. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert !null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notNull($value, $message = '')
    {
        if (null === $value) {
            static::reportInvalidArgument(
                $message ?: 'Expected a value other than null.'
            );
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert true $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function true($value, $message = '')
    {
        if (true !== $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be true. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert false $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function false($value, $message = '')
    {
        if (false !== $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be false. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert !false $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notFalse($value, $message = '')
    {
        if (false === $value) {
            static::reportInvalidArgument(
                $message ?: 'Expected a value other than false.'
            );
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function ip($value, $message = '')
    {
        if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be an IP. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function ipv4($value, $message = '')
    {
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be an IPv4. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function ipv6($value, $message = '')
    {
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be an IPv6. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function email($value, $message = '')
    {
        if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to be a valid e-mail address. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion.
     *
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function uniqueValues(array $values, $message = '')
    {
        $allValues = \count($values);
        $uniqueValues = \count(\array_unique($values));

        if ($allValues !== $uniqueValues) {
            $difference = $allValues - $uniqueValues;

            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
                $difference,
                (1 === $difference ? 'is' : 'are')
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function eq($value, $expect, $message = '')
    {
        if ($expect != $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value equal to %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($expect)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notEq($value, $expect, $message = '')
    {
        if ($expect == $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a different value than %s.',
                static::valueToString($expect)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function same($value, $expect, $message = '')
    {
        if ($expect !== $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value identical to %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($expect)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notSame($value, $expect, $message = '')
    {
        if ($expect === $value) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value not identical to %s.',
                static::valueToString($expect)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function greaterThan($value, $limit, $message = '')
    {
        if ($value <= $limit) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value greater than %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($limit)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function greaterThanEq($value, $limit, $message = '')
    {
        if ($value < $limit) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($limit)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function lessThan($value, $limit, $message = '')
    {
        if ($value >= $limit) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value less than %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($limit)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function lessThanEq($value, $limit, $message = '')
    {
        if ($value > $limit) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($limit)
            ));
        }
    }

    /**
     * Inclusive range, so Assert::(3, 3, 5) passes.
     *
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $min
     * @param mixed  $max
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function range($value, $min, $max, $message = '')
    {
        if ($value < $min || $value > $max) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
                static::valueToString($value),
                static::valueToString($min),
                static::valueToString($max)
            ));
        }
    }

    /**
     * A more human-readable alias of Assert::inArray().
     *
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function oneOf($value, array $values, $message = '')
    {
        static::inArray($value, $values, $message);
    }

    /**
     * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion.
     *
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function inArray($value, array $values, $message = '')
    {
        if (!\in_array($value, $values, true)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected one of: %2$s. Got: %s',
                static::valueToString($value),
                \implode(', ', \array_map(array(static::class, 'valueToString'), $values))
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $subString
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function contains($value, $subString, $message = '')
    {
        if (false === \strpos($value, $subString)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($subString)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $subString
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notContains($value, $subString, $message = '')
    {
        if (false !== \strpos($value, $subString)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: '%2$s was not expected to be contained in a value. Got: %s',
                static::valueToString($value),
                static::valueToString($subString)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notWhitespaceOnly($value, $message = '')
    {
        if (\preg_match('/^\s*$/', $value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a non-whitespace string. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $prefix
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function startsWith($value, $prefix, $message = '')
    {
        if (0 !== \strpos($value, $prefix)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to start with %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($prefix)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $prefix
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notStartsWith($value, $prefix, $message = '')
    {
        if (0 === \strpos($value, $prefix)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value not to start with %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($prefix)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function startsWithLetter($value, $message = '')
    {
        static::string($value);

        $valid = isset($value[0]);

        if ($valid) {
            $locale = \setlocale(LC_CTYPE, 0);
            \setlocale(LC_CTYPE, 'C');
            $valid = \ctype_alpha($value[0]);
            \setlocale(LC_CTYPE, $locale);
        }

        if (!$valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to start with a letter. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $suffix
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function endsWith($value, $suffix, $message = '')
    {
        if ($suffix !== \substr($value, -\strlen($suffix))) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to end with %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($suffix)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $suffix
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notEndsWith($value, $suffix, $message = '')
    {
        if ($suffix === \substr($value, -\strlen($suffix))) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value not to end with %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($suffix)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $pattern
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function regex($value, $pattern, $message = '')
    {
        if (!\preg_match($pattern, $value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The value %s does not match the expected pattern.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $pattern
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function notRegex($value, $pattern, $message = '')
    {
        if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The value %s matches the pattern %s (at offset %d).',
                static::valueToString($value),
                static::valueToString($pattern),
                $matches[0][1]
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function unicodeLetters($value, $message = '')
    {
        static::string($value);

        if (!\preg_match('/^\p{L}+$/u', $value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function alpha($value, $message = '')
    {
        static::string($value);

        $locale = \setlocale(LC_CTYPE, 0);
        \setlocale(LC_CTYPE, 'C');
        $valid = !\ctype_alpha($value);
        \setlocale(LC_CTYPE, $locale);

        if ($valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain only letters. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function digits($value, $message = '')
    {
        $locale = \setlocale(LC_CTYPE, 0);
        \setlocale(LC_CTYPE, 'C');
        $valid = !\ctype_digit($value);
        \setlocale(LC_CTYPE, $locale);

        if ($valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain digits only. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function alnum($value, $message = '')
    {
        $locale = \setlocale(LC_CTYPE, 0);
        \setlocale(LC_CTYPE, 'C');
        $valid = !\ctype_alnum($value);
        \setlocale(LC_CTYPE, $locale);

        if ($valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain letters and digits only. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert lowercase-string $value
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function lower($value, $message = '')
    {
        $locale = \setlocale(LC_CTYPE, 0);
        \setlocale(LC_CTYPE, 'C');
        $valid = !\ctype_lower($value);
        \setlocale(LC_CTYPE, $locale);

        if ($valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert !lowercase-string $value
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function upper($value, $message = '')
    {
        $locale = \setlocale(LC_CTYPE, 0);
        \setlocale(LC_CTYPE, 'C');
        $valid = !\ctype_upper($value);
        \setlocale(LC_CTYPE, $locale);

        if ($valid) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param int    $length
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function length($value, $length, $message = '')
    {
        if ($length !== static::strlen($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain %2$s characters. Got: %s',
                static::valueToString($value),
                $length
            ));
        }
    }

    /**
     * Inclusive min.
     *
     * @psalm-pure
     *
     * @param string    $value
     * @param int|float $min
     * @param string    $message
     *
     * @throws InvalidArgumentException
     */
    public static function minLength($value, $min, $message = '')
    {
        if (static::strlen($value) < $min) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
                static::valueToString($value),
                $min
            ));
        }
    }

    /**
     * Inclusive max.
     *
     * @psalm-pure
     *
     * @param string    $value
     * @param int|float $max
     * @param string    $message
     *
     * @throws InvalidArgumentException
     */
    public static function maxLength($value, $max, $message = '')
    {
        if (static::strlen($value) > $max) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
                static::valueToString($value),
                $max
            ));
        }
    }

    /**
     * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion.
     *
     * @psalm-pure
     *
     * @param string    $value
     * @param int|float $min
     * @param int|float $max
     * @param string    $message
     *
     * @throws InvalidArgumentException
     */
    public static function lengthBetween($value, $min, $max, $message = '')
    {
        $length = static::strlen($value);

        if ($length < $min || $length > $max) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
                static::valueToString($value),
                $min,
                $max
            ));
        }
    }

    /**
     * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file.
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function fileExists($value, $message = '')
    {
        static::string($value);

        if (!\file_exists($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The file %s does not exist.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function file($value, $message = '')
    {
        static::fileExists($value, $message);

        if (!\is_file($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The path %s is not a file.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function directory($value, $message = '')
    {
        static::fileExists($value, $message);

        if (!\is_dir($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The path %s is no directory.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function readable($value, $message = '')
    {
        if (!\is_readable($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The path %s is not readable.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function writable($value, $message = '')
    {
        if (!\is_writable($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'The path %s is not writable.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-assert class-string $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function classExists($value, $message = '')
    {
        if (!\class_exists($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an existing class name. Got: %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert class-string<ExpectedType>|ExpectedType $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function subclassOf($value, $class, $message = '')
    {
        if (!\is_subclass_of($value, $class)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a sub-class of %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($class)
            ));
        }
    }

    /**
     * @psalm-assert class-string $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function interfaceExists($value, $message = '')
    {
        if (!\interface_exists($value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an existing interface name. got %s',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $interface
     * @psalm-assert class-string<ExpectedType> $value
     *
     * @param mixed  $value
     * @param mixed  $interface
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function implementsInterface($value, $interface, $message = '')
    {
        if (!\in_array($interface, \class_implements($value))) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an implementation of %2$s. Got: %s',
                static::valueToString($value),
                static::valueToString($interface)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object $classOrObject
     *
     * @param string|object $classOrObject
     * @param mixed         $property
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function propertyExists($classOrObject, $property, $message = '')
    {
        if (!\property_exists($classOrObject, $property)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the property %s to exist.',
                static::valueToString($property)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object $classOrObject
     *
     * @param string|object $classOrObject
     * @param mixed         $property
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function propertyNotExists($classOrObject, $property, $message = '')
    {
        if (\property_exists($classOrObject, $property)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the property %s to not exist.',
                static::valueToString($property)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object $classOrObject
     *
     * @param string|object $classOrObject
     * @param mixed         $method
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function methodExists($classOrObject, $method, $message = '')
    {
        if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the method %s to exist.',
                static::valueToString($method)
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object $classOrObject
     *
     * @param string|object $classOrObject
     * @param mixed         $method
     * @param string        $message
     *
     * @throws InvalidArgumentException
     */
    public static function methodNotExists($classOrObject, $method, $message = '')
    {
        if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the method %s to not exist.',
                static::valueToString($method)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param array      $array
     * @param string|int $key
     * @param string     $message
     *
     * @throws InvalidArgumentException
     */
    public static function keyExists($array, $key, $message = '')
    {
        if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the key %s to exist.',
                static::valueToString($key)
            ));
        }
    }

    /**
     * @psalm-pure
     *
     * @param array      $array
     * @param string|int $key
     * @param string     $message
     *
     * @throws InvalidArgumentException
     */
    public static function keyNotExists($array, $key, $message = '')
    {
        if (isset($array[$key]) || \array_key_exists($key, $array)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected the key %s to not exist.',
                static::valueToString($key)
            ));
        }
    }

    /**
     * Checks if a value is a valid array key (int or string).
     *
     * @psalm-pure
     * @psalm-assert array-key $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function validArrayKey($value, $message = '')
    {
        if (!(\is_int($value) || \is_string($value))) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected string or integer. Got: %s',
                static::typeToString($value)
            ));
        }
    }

    /**
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
     *
     * @param Countable|array $array
     * @param int             $number
     * @param string          $message
     *
     * @throws InvalidArgumentException
     */
    public static function count($array, $number, $message = '')
    {
        static::eq(
            \count($array),
            $number,
            \sprintf(
                $message ?: 'Expected an array to contain %d elements. Got: %d.',
                $number,
                \count($array)
            )
        );
    }

    /**
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
     *
     * @param Countable|array $array
     * @param int|float       $min
     * @param string          $message
     *
     * @throws InvalidArgumentException
     */
    public static function minCount($array, $min, $message = '')
    {
        if (\count($array) < $min) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
                \count($array),
                $min
            ));
        }
    }

    /**
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
     *
     * @param Countable|array $array
     * @param int|float       $max
     * @param string          $message
     *
     * @throws InvalidArgumentException
     */
    public static function maxCount($array, $max, $message = '')
    {
        if (\count($array) > $max) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
                \count($array),
                $max
            ));
        }
    }

    /**
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
     *
     * @param Countable|array $array
     * @param int|float       $min
     * @param int|float       $max
     * @param string          $message
     *
     * @throws InvalidArgumentException
     */
    public static function countBetween($array, $min, $max, $message = '')
    {
        $count = \count($array);

        if ($count < $min || $count > $max) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
                $count,
                $min,
                $max
            ));
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert list $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isList($array, $message = '')
    {
        if (!\is_array($array)) {
            static::reportInvalidArgument(
                $message ?: 'Expected list - non-associative array.'
            );
        }

        if ($array === \array_values($array)) {
            return;
        }

        $nextKey = -1;
        foreach ($array as $k => $v) {
            if ($k !== ++$nextKey) {
                static::reportInvalidArgument(
                    $message ?: 'Expected list - non-associative array.'
                );
            }
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert non-empty-list $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isNonEmptyList($array, $message = '')
    {
        static::isList($array, $message);
        static::notEmpty($array, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param mixed|array<T> $array
     * @psalm-assert array<string, T> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isMap($array, $message = '')
    {
        if (
            !\is_array($array) ||
            \array_keys($array) !== \array_filter(\array_keys($array), '\is_string')
        ) {
            static::reportInvalidArgument(
                $message ?: 'Expected map - associative array with string keys.'
            );
        }
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param mixed|array<T> $array
     * @psalm-assert array<string, T> $array
     * @psalm-assert !empty $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function isNonEmptyMap($array, $message = '')
    {
        static::isMap($array, $message);
        static::notEmpty($array, $message);
    }

    /**
     * @psalm-pure
     *
     * @param string $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     */
    public static function uuid($value, $message = '')
    {
        $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);

        // The nil UUID is special form of UUID that is specified to have all
        // 128 bits set to zero.
        if ('00000000-0000-0000-0000-000000000000' === $value) {
            return;
        }

        if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) {
            static::reportInvalidArgument(\sprintf(
                $message ?: 'Value %s is not a valid UUID.',
                static::valueToString($value)
            ));
        }
    }

    /**
     * @psalm-param class-string<Throwable> $class
     *
     * @param Closure $expression
     * @param string  $class
     * @param string  $message
     *
     * @throws InvalidArgumentException
     */
    public static function throws(Closure $expression, $class = 'Exception', $message = '')
    {
        static::string($class);

        $actual = 'none';

        try {
            $expression();
        } catch (Exception $e) {
            $actual = \get_class($e);
            if ($e instanceof $class) {
                return;
            }
        } catch (Throwable $e) {
            $actual = \get_class($e);
            if ($e instanceof $class) {
                return;
            }
        }

        static::reportInvalidArgument($message ?: \sprintf(
            'Expected to throw "%s", got "%s"',
            $class,
            $actual
        ));
    }

    /**
     * @throws BadMethodCallException
     */
    public static function __callStatic($name, $arguments)
    {
        if ('nullOr' === \substr($name, 0, 6)) {
            if (null !== $arguments[0]) {
                $method = \lcfirst(\substr($name, 6));
                \call_user_func_array(array(static::class, $method), $arguments);
            }

            return;
        }

        if ('all' === \substr($name, 0, 3)) {
            static::isIterable($arguments[0]);

            $method = \lcfirst(\substr($name, 3));
            $args = $arguments;

            foreach ($arguments[0] as $entry) {
                $args[0] = $entry;

                \call_user_func_array(array(static::class, $method), $args);
            }

            return;
        }

        throw new BadMethodCallException('No such method: '.$name);
    }

    /**
     * @param mixed $value
     *
     * @return string
     */
    protected static function valueToString($value)
    {
        if (null === $value) {
            return 'null';
        }

        if (true === $value) {
            return 'true';
        }

        if (false === $value) {
            return 'false';
        }

        if (\is_array($value)) {
            return 'array';
        }

        if (\is_object($value)) {
            if (\method_exists($value, '__toString')) {
                return \get_class($value).': '.self::valueToString($value->__toString());
            }

            if ($value instanceof DateTime || $value instanceof DateTimeImmutable) {
                return \get_class($value).': '.self::valueToString($value->format('c'));
            }

            return \get_class($value);
        }

        if (\is_resource($value)) {
            return 'resource';
        }

        if (\is_string($value)) {
            return '"'.$value.'"';
        }

        return (string) $value;
    }

    /**
     * @param mixed $value
     *
     * @return string
     */
    protected static function typeToString($value)
    {
        return \is_object($value) ? \get_class($value) : \gettype($value);
    }

    protected static function strlen($value)
    {
        if (!\function_exists('mb_detect_encoding')) {
            return \strlen($value);
        }

        if (false === $encoding = \mb_detect_encoding($value)) {
            return \strlen($value);
        }

        return \mb_strlen($value, $encoding);
    }

    /**
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @psalm-pure this method is not supposed to perform side-effects
     * @psalm-return never
     */
    protected static function reportInvalidArgument($message)
    {
        throw new InvalidArgumentException($message);
    }

    private function __construct()
    {
    }
}
<?php

/*
 * This file is part of the webmozart/assert package.
 *
 * (c) Bernhard Schussek <bschussek@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Webmozart\Assert;

class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php

namespace Webmozart\Assert;

use ArrayAccess;
use Closure;
use Countable;
use Throwable;

/**
 * This trait provides nurllOr*, all* and allNullOr* variants of assertion base methods.
 * Do not use this trait directly: it will change, and is not designed for reuse.
 */
trait Mixin
{
    /**
     * @psalm-pure
     * @psalm-assert string|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrString($value, $message = '')
    {
        null === $value || static::string($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<string> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allString($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::string($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<string|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrString($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::string($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert non-empty-string|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrStringNotEmpty($value, $message = '')
    {
        null === $value || static::stringNotEmpty($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<non-empty-string> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allStringNotEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::stringNotEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<non-empty-string|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrStringNotEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::stringNotEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert int|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrInteger($value, $message = '')
    {
        null === $value || static::integer($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<int> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allInteger($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::integer($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<int|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrInteger($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::integer($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert numeric|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIntegerish($value, $message = '')
    {
        null === $value || static::integerish($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<numeric> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIntegerish($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::integerish($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<numeric|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIntegerish($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::integerish($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert positive-int|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrPositiveInteger($value, $message = '')
    {
        null === $value || static::positiveInteger($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<positive-int> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allPositiveInteger($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::positiveInteger($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<positive-int|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrPositiveInteger($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::positiveInteger($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert float|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrFloat($value, $message = '')
    {
        null === $value || static::float($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<float> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allFloat($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::float($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<float|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrFloat($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::float($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert numeric|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNumeric($value, $message = '')
    {
        null === $value || static::numeric($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<numeric> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNumeric($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::numeric($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<numeric|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNumeric($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::numeric($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert positive-int|0|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNatural($value, $message = '')
    {
        null === $value || static::natural($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<positive-int|0> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNatural($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::natural($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<positive-int|0|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNatural($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::natural($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert bool|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrBoolean($value, $message = '')
    {
        null === $value || static::boolean($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<bool> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allBoolean($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::boolean($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<bool|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrBoolean($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::boolean($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert scalar|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrScalar($value, $message = '')
    {
        null === $value || static::scalar($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<scalar> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allScalar($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::scalar($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<scalar|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrScalar($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::scalar($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert object|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrObject($value, $message = '')
    {
        null === $value || static::object($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<object> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allObject($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::object($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<object|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrObject($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::object($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert resource|null $value
     *
     * @param mixed       $value
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrResource($value, $type = null, $message = '')
    {
        null === $value || static::resource($value, $type, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<resource> $value
     *
     * @param mixed       $value
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allResource($value, $type = null, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::resource($entry, $type, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<resource|null> $value
     *
     * @param mixed       $value
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrResource($value, $type = null, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::resource($entry, $type, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert callable|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsCallable($value, $message = '')
    {
        null === $value || static::isCallable($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<callable> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsCallable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isCallable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<callable|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsCallable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isCallable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert array|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsArray($value, $message = '')
    {
        null === $value || static::isArray($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsArray($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isArray($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsArray($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isArray($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable|null $value
     *
     * @deprecated use "isIterable" or "isInstanceOf" instead
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsTraversable($value, $message = '')
    {
        null === $value || static::isTraversable($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<iterable> $value
     *
     * @deprecated use "isIterable" or "isInstanceOf" instead
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsTraversable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isTraversable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<iterable|null> $value
     *
     * @deprecated use "isIterable" or "isInstanceOf" instead
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsTraversable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isTraversable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert array|ArrayAccess|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsArrayAccessible($value, $message = '')
    {
        null === $value || static::isArrayAccessible($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array|ArrayAccess> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsArrayAccessible($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isArrayAccessible($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array|ArrayAccess|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsArrayAccessible($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isArrayAccessible($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert countable|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsCountable($value, $message = '')
    {
        null === $value || static::isCountable($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<countable> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsCountable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isCountable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<countable|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsCountable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isCountable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsIterable($value, $message = '')
    {
        null === $value || static::isIterable($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<iterable> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsIterable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isIterable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<iterable|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsIterable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isIterable($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert ExpectedType|null $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsInstanceOf($value, $class, $message = '')
    {
        null === $value || static::isInstanceOf($value, $class, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<ExpectedType> $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsInstanceOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isInstanceOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<ExpectedType|null> $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsInstanceOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isInstanceOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotInstanceOf($value, $class, $message = '')
    {
        null === $value || static::notInstanceOf($value, $class, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotInstanceOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notInstanceOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<!ExpectedType|null> $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotInstanceOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notInstanceOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param mixed                $value
     * @param array<object|string> $classes
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsInstanceOfAny($value, $classes, $message = '')
    {
        null === $value || static::isInstanceOfAny($value, $classes, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param mixed                $value
     * @param array<object|string> $classes
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsInstanceOfAny($value, $classes, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isInstanceOfAny($entry, $classes, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param mixed                $value
     * @param array<object|string> $classes
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsInstanceOfAny($value, $classes, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isInstanceOfAny($entry, $classes, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert ExpectedType|class-string<ExpectedType>|null $value
     *
     * @param object|string|null $value
     * @param string             $class
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsAOf($value, $class, $message = '')
    {
        null === $value || static::isAOf($value, $class, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<ExpectedType|class-string<ExpectedType>> $value
     *
     * @param iterable<object|string> $value
     * @param string                  $class
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsAOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isAOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<ExpectedType|class-string<ExpectedType>|null> $value
     *
     * @param iterable<object|string|null> $value
     * @param string                       $class
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsAOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isAOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template UnexpectedType of object
     * @psalm-param class-string<UnexpectedType> $class
     *
     * @param object|string|null $value
     * @param string             $class
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsNotA($value, $class, $message = '')
    {
        null === $value || static::isNotA($value, $class, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template UnexpectedType of object
     * @psalm-param class-string<UnexpectedType> $class
     *
     * @param iterable<object|string> $value
     * @param string                  $class
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsNotA($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isNotA($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template UnexpectedType of object
     * @psalm-param class-string<UnexpectedType> $class
     * @psalm-assert iterable<!UnexpectedType|null> $value
     * @psalm-assert iterable<!class-string<UnexpectedType>|null> $value
     *
     * @param iterable<object|string|null> $value
     * @param string                       $class
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsNotA($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isNotA($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param object|string|null $value
     * @param string[]           $classes
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsAnyOf($value, $classes, $message = '')
    {
        null === $value || static::isAnyOf($value, $classes, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param iterable<object|string> $value
     * @param string[]                $classes
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsAnyOf($value, $classes, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isAnyOf($entry, $classes, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param array<class-string> $classes
     *
     * @param iterable<object|string|null> $value
     * @param string[]                     $classes
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsAnyOf($value, $classes, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isAnyOf($entry, $classes, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert empty $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsEmpty($value, $message = '')
    {
        null === $value || static::isEmpty($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<empty> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::isEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<empty|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::isEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotEmpty($value, $message = '')
    {
        null === $value || static::notEmpty($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<!empty|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotEmpty($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notEmpty($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNull($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::null($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotNull($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notNull($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert true|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrTrue($value, $message = '')
    {
        null === $value || static::true($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<true> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allTrue($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::true($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<true|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrTrue($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::true($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert false|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrFalse($value, $message = '')
    {
        null === $value || static::false($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<false> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allFalse($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::false($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<false|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrFalse($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::false($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotFalse($value, $message = '')
    {
        null === $value || static::notFalse($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotFalse($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notFalse($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<!false|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotFalse($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notFalse($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIp($value, $message = '')
    {
        null === $value || static::ip($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIp($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::ip($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIp($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::ip($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIpv4($value, $message = '')
    {
        null === $value || static::ipv4($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIpv4($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::ipv4($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIpv4($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::ipv4($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIpv6($value, $message = '')
    {
        null === $value || static::ipv6($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIpv6($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::ipv6($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIpv6($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::ipv6($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrEmail($value, $message = '')
    {
        null === $value || static::email($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allEmail($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::email($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrEmail($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::email($entry, $message);
        }
    }

    /**
     * @param array|null $values
     * @param string     $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrUniqueValues($values, $message = '')
    {
        null === $values || static::uniqueValues($values, $message);
    }

    /**
     * @param iterable<array> $values
     * @param string          $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allUniqueValues($values, $message = '')
    {
        static::isIterable($values);

        foreach ($values as $entry) {
            static::uniqueValues($entry, $message);
        }
    }

    /**
     * @param iterable<array|null> $values
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrUniqueValues($values, $message = '')
    {
        static::isIterable($values);

        foreach ($values as $entry) {
            null === $entry || static::uniqueValues($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrEq($value, $expect, $message = '')
    {
        null === $value || static::eq($value, $expect, $message);
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allEq($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::eq($entry, $expect, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrEq($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::eq($entry, $expect, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotEq($value, $expect, $message = '')
    {
        null === $value || static::notEq($value, $expect, $message);
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotEq($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notEq($entry, $expect, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotEq($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notEq($entry, $expect, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrSame($value, $expect, $message = '')
    {
        null === $value || static::same($value, $expect, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allSame($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::same($entry, $expect, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrSame($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::same($entry, $expect, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotSame($value, $expect, $message = '')
    {
        null === $value || static::notSame($value, $expect, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotSame($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notSame($entry, $expect, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $expect
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotSame($value, $expect, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notSame($entry, $expect, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrGreaterThan($value, $limit, $message = '')
    {
        null === $value || static::greaterThan($value, $limit, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allGreaterThan($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::greaterThan($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrGreaterThan($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::greaterThan($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrGreaterThanEq($value, $limit, $message = '')
    {
        null === $value || static::greaterThanEq($value, $limit, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allGreaterThanEq($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::greaterThanEq($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrGreaterThanEq($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::greaterThanEq($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrLessThan($value, $limit, $message = '')
    {
        null === $value || static::lessThan($value, $limit, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allLessThan($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::lessThan($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrLessThan($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::lessThan($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrLessThanEq($value, $limit, $message = '')
    {
        null === $value || static::lessThanEq($value, $limit, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allLessThanEq($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::lessThanEq($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $limit
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrLessThanEq($value, $limit, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::lessThanEq($entry, $limit, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $min
     * @param mixed  $max
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrRange($value, $min, $max, $message = '')
    {
        null === $value || static::range($value, $min, $max, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $min
     * @param mixed  $max
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allRange($value, $min, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::range($entry, $min, $max, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param mixed  $min
     * @param mixed  $max
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrRange($value, $min, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::range($entry, $min, $max, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrOneOf($value, $values, $message = '')
    {
        null === $value || static::oneOf($value, $values, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allOneOf($value, $values, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::oneOf($entry, $values, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrOneOf($value, $values, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::oneOf($entry, $values, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrInArray($value, $values, $message = '')
    {
        null === $value || static::inArray($value, $values, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allInArray($value, $values, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::inArray($entry, $values, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param array  $values
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrInArray($value, $values, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::inArray($entry, $values, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $subString
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrContains($value, $subString, $message = '')
    {
        null === $value || static::contains($value, $subString, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $subString
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allContains($value, $subString, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::contains($entry, $subString, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $subString
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrContains($value, $subString, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::contains($entry, $subString, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $subString
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotContains($value, $subString, $message = '')
    {
        null === $value || static::notContains($value, $subString, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $subString
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotContains($value, $subString, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notContains($entry, $subString, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $subString
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotContains($value, $subString, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notContains($entry, $subString, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotWhitespaceOnly($value, $message = '')
    {
        null === $value || static::notWhitespaceOnly($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotWhitespaceOnly($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notWhitespaceOnly($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotWhitespaceOnly($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notWhitespaceOnly($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $prefix
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrStartsWith($value, $prefix, $message = '')
    {
        null === $value || static::startsWith($value, $prefix, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $prefix
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allStartsWith($value, $prefix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::startsWith($entry, $prefix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $prefix
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrStartsWith($value, $prefix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::startsWith($entry, $prefix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $prefix
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotStartsWith($value, $prefix, $message = '')
    {
        null === $value || static::notStartsWith($value, $prefix, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $prefix
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotStartsWith($value, $prefix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notStartsWith($entry, $prefix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $prefix
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotStartsWith($value, $prefix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notStartsWith($entry, $prefix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrStartsWithLetter($value, $message = '')
    {
        null === $value || static::startsWithLetter($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allStartsWithLetter($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::startsWithLetter($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrStartsWithLetter($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::startsWithLetter($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $suffix
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrEndsWith($value, $suffix, $message = '')
    {
        null === $value || static::endsWith($value, $suffix, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $suffix
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allEndsWith($value, $suffix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::endsWith($entry, $suffix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $suffix
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrEndsWith($value, $suffix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::endsWith($entry, $suffix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $suffix
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotEndsWith($value, $suffix, $message = '')
    {
        null === $value || static::notEndsWith($value, $suffix, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $suffix
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotEndsWith($value, $suffix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notEndsWith($entry, $suffix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $suffix
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotEndsWith($value, $suffix, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notEndsWith($entry, $suffix, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $pattern
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrRegex($value, $pattern, $message = '')
    {
        null === $value || static::regex($value, $pattern, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $pattern
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allRegex($value, $pattern, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::regex($entry, $pattern, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $pattern
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrRegex($value, $pattern, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::regex($entry, $pattern, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $pattern
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrNotRegex($value, $pattern, $message = '')
    {
        null === $value || static::notRegex($value, $pattern, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $pattern
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNotRegex($value, $pattern, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::notRegex($entry, $pattern, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $pattern
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrNotRegex($value, $pattern, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::notRegex($entry, $pattern, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrUnicodeLetters($value, $message = '')
    {
        null === $value || static::unicodeLetters($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allUnicodeLetters($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::unicodeLetters($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrUnicodeLetters($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::unicodeLetters($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrAlpha($value, $message = '')
    {
        null === $value || static::alpha($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allAlpha($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::alpha($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrAlpha($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::alpha($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrDigits($value, $message = '')
    {
        null === $value || static::digits($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allDigits($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::digits($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrDigits($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::digits($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrAlnum($value, $message = '')
    {
        null === $value || static::alnum($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allAlnum($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::alnum($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrAlnum($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::alnum($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert lowercase-string|null $value
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrLower($value, $message = '')
    {
        null === $value || static::lower($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<lowercase-string> $value
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allLower($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::lower($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<lowercase-string|null> $value
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrLower($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::lower($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrUpper($value, $message = '')
    {
        null === $value || static::upper($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allUpper($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::upper($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<!lowercase-string|null> $value
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrUpper($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::upper($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param int         $length
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrLength($value, $length, $message = '')
    {
        null === $value || static::length($value, $length, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param int              $length
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allLength($value, $length, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::length($entry, $length, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param int                   $length
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrLength($value, $length, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::length($entry, $length, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param int|float   $min
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMinLength($value, $min, $message = '')
    {
        null === $value || static::minLength($value, $min, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param int|float        $min
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMinLength($value, $min, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::minLength($entry, $min, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param int|float             $min
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMinLength($value, $min, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::minLength($entry, $min, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param int|float   $max
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMaxLength($value, $max, $message = '')
    {
        null === $value || static::maxLength($value, $max, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param int|float        $max
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMaxLength($value, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::maxLength($entry, $max, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param int|float             $max
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMaxLength($value, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::maxLength($entry, $max, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param int|float   $min
     * @param int|float   $max
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrLengthBetween($value, $min, $max, $message = '')
    {
        null === $value || static::lengthBetween($value, $min, $max, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param int|float        $min
     * @param int|float        $max
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allLengthBetween($value, $min, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::lengthBetween($entry, $min, $max, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param int|float             $min
     * @param int|float             $max
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrLengthBetween($value, $min, $max, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::lengthBetween($entry, $min, $max, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrFileExists($value, $message = '')
    {
        null === $value || static::fileExists($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allFileExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::fileExists($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrFileExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::fileExists($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrFile($value, $message = '')
    {
        null === $value || static::file($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allFile($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::file($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrFile($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::file($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrDirectory($value, $message = '')
    {
        null === $value || static::directory($value, $message);
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allDirectory($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::directory($entry, $message);
        }
    }

    /**
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrDirectory($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::directory($entry, $message);
        }
    }

    /**
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrReadable($value, $message = '')
    {
        null === $value || static::readable($value, $message);
    }

    /**
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allReadable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::readable($entry, $message);
        }
    }

    /**
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrReadable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::readable($entry, $message);
        }
    }

    /**
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrWritable($value, $message = '')
    {
        null === $value || static::writable($value, $message);
    }

    /**
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allWritable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::writable($entry, $message);
        }
    }

    /**
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrWritable($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::writable($entry, $message);
        }
    }

    /**
     * @psalm-assert class-string|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrClassExists($value, $message = '')
    {
        null === $value || static::classExists($value, $message);
    }

    /**
     * @psalm-assert iterable<class-string> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allClassExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::classExists($entry, $message);
        }
    }

    /**
     * @psalm-assert iterable<class-string|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrClassExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::classExists($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert class-string<ExpectedType>|ExpectedType|null $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrSubclassOf($value, $class, $message = '')
    {
        null === $value || static::subclassOf($value, $class, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<class-string<ExpectedType>|ExpectedType> $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allSubclassOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::subclassOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $class
     * @psalm-assert iterable<class-string<ExpectedType>|ExpectedType|null> $value
     *
     * @param mixed         $value
     * @param string|object $class
     * @param string        $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrSubclassOf($value, $class, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::subclassOf($entry, $class, $message);
        }
    }

    /**
     * @psalm-assert class-string|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrInterfaceExists($value, $message = '')
    {
        null === $value || static::interfaceExists($value, $message);
    }

    /**
     * @psalm-assert iterable<class-string> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allInterfaceExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::interfaceExists($entry, $message);
        }
    }

    /**
     * @psalm-assert iterable<class-string|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrInterfaceExists($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::interfaceExists($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $interface
     * @psalm-assert class-string<ExpectedType>|null $value
     *
     * @param mixed  $value
     * @param mixed  $interface
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrImplementsInterface($value, $interface, $message = '')
    {
        null === $value || static::implementsInterface($value, $interface, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $interface
     * @psalm-assert iterable<class-string<ExpectedType>> $value
     *
     * @param mixed  $value
     * @param mixed  $interface
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allImplementsInterface($value, $interface, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::implementsInterface($entry, $interface, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template ExpectedType of object
     * @psalm-param class-string<ExpectedType> $interface
     * @psalm-assert iterable<class-string<ExpectedType>|null> $value
     *
     * @param mixed  $value
     * @param mixed  $interface
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrImplementsInterface($value, $interface, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::implementsInterface($entry, $interface, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object|null $classOrObject
     *
     * @param string|object|null $classOrObject
     * @param mixed              $property
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrPropertyExists($classOrObject, $property, $message = '')
    {
        null === $classOrObject || static::propertyExists($classOrObject, $property, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object> $classOrObject
     *
     * @param iterable<string|object> $classOrObject
     * @param mixed                   $property
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allPropertyExists($classOrObject, $property, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            static::propertyExists($entry, $property, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object|null> $classOrObject
     *
     * @param iterable<string|object|null> $classOrObject
     * @param mixed                        $property
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrPropertyExists($classOrObject, $property, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            null === $entry || static::propertyExists($entry, $property, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object|null $classOrObject
     *
     * @param string|object|null $classOrObject
     * @param mixed              $property
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrPropertyNotExists($classOrObject, $property, $message = '')
    {
        null === $classOrObject || static::propertyNotExists($classOrObject, $property, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object> $classOrObject
     *
     * @param iterable<string|object> $classOrObject
     * @param mixed                   $property
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allPropertyNotExists($classOrObject, $property, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            static::propertyNotExists($entry, $property, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object|null> $classOrObject
     *
     * @param iterable<string|object|null> $classOrObject
     * @param mixed                        $property
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrPropertyNotExists($classOrObject, $property, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            null === $entry || static::propertyNotExists($entry, $property, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object|null $classOrObject
     *
     * @param string|object|null $classOrObject
     * @param mixed              $method
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMethodExists($classOrObject, $method, $message = '')
    {
        null === $classOrObject || static::methodExists($classOrObject, $method, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object> $classOrObject
     *
     * @param iterable<string|object> $classOrObject
     * @param mixed                   $method
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMethodExists($classOrObject, $method, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            static::methodExists($entry, $method, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object|null> $classOrObject
     *
     * @param iterable<string|object|null> $classOrObject
     * @param mixed                        $method
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMethodExists($classOrObject, $method, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            null === $entry || static::methodExists($entry, $method, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param class-string|object|null $classOrObject
     *
     * @param string|object|null $classOrObject
     * @param mixed              $method
     * @param string             $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMethodNotExists($classOrObject, $method, $message = '')
    {
        null === $classOrObject || static::methodNotExists($classOrObject, $method, $message);
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object> $classOrObject
     *
     * @param iterable<string|object> $classOrObject
     * @param mixed                   $method
     * @param string                  $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMethodNotExists($classOrObject, $method, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            static::methodNotExists($entry, $method, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-param iterable<class-string|object|null> $classOrObject
     *
     * @param iterable<string|object|null> $classOrObject
     * @param mixed                        $method
     * @param string                       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMethodNotExists($classOrObject, $method, $message = '')
    {
        static::isIterable($classOrObject);

        foreach ($classOrObject as $entry) {
            null === $entry || static::methodNotExists($entry, $method, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param array|null $array
     * @param string|int $key
     * @param string     $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrKeyExists($array, $key, $message = '')
    {
        null === $array || static::keyExists($array, $key, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<array> $array
     * @param string|int      $key
     * @param string          $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allKeyExists($array, $key, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::keyExists($entry, $key, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<array|null> $array
     * @param string|int           $key
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrKeyExists($array, $key, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::keyExists($entry, $key, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param array|null $array
     * @param string|int $key
     * @param string     $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrKeyNotExists($array, $key, $message = '')
    {
        null === $array || static::keyNotExists($array, $key, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<array> $array
     * @param string|int      $key
     * @param string          $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allKeyNotExists($array, $key, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::keyNotExists($entry, $key, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<array|null> $array
     * @param string|int           $key
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrKeyNotExists($array, $key, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::keyNotExists($entry, $key, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert array-key|null $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrValidArrayKey($value, $message = '')
    {
        null === $value || static::validArrayKey($value, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array-key> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allValidArrayKey($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::validArrayKey($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<array-key|null> $value
     *
     * @param mixed  $value
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrValidArrayKey($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::validArrayKey($entry, $message);
        }
    }

    /**
     * @param Countable|array|null $array
     * @param int                  $number
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrCount($array, $number, $message = '')
    {
        null === $array || static::count($array, $number, $message);
    }

    /**
     * @param iterable<Countable|array> $array
     * @param int                       $number
     * @param string                    $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allCount($array, $number, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::count($entry, $number, $message);
        }
    }

    /**
     * @param iterable<Countable|array|null> $array
     * @param int                            $number
     * @param string                         $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrCount($array, $number, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::count($entry, $number, $message);
        }
    }

    /**
     * @param Countable|array|null $array
     * @param int|float            $min
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMinCount($array, $min, $message = '')
    {
        null === $array || static::minCount($array, $min, $message);
    }

    /**
     * @param iterable<Countable|array> $array
     * @param int|float                 $min
     * @param string                    $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMinCount($array, $min, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::minCount($entry, $min, $message);
        }
    }

    /**
     * @param iterable<Countable|array|null> $array
     * @param int|float                      $min
     * @param string                         $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMinCount($array, $min, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::minCount($entry, $min, $message);
        }
    }

    /**
     * @param Countable|array|null $array
     * @param int|float            $max
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrMaxCount($array, $max, $message = '')
    {
        null === $array || static::maxCount($array, $max, $message);
    }

    /**
     * @param iterable<Countable|array> $array
     * @param int|float                 $max
     * @param string                    $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allMaxCount($array, $max, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::maxCount($entry, $max, $message);
        }
    }

    /**
     * @param iterable<Countable|array|null> $array
     * @param int|float                      $max
     * @param string                         $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrMaxCount($array, $max, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::maxCount($entry, $max, $message);
        }
    }

    /**
     * @param Countable|array|null $array
     * @param int|float            $min
     * @param int|float            $max
     * @param string               $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrCountBetween($array, $min, $max, $message = '')
    {
        null === $array || static::countBetween($array, $min, $max, $message);
    }

    /**
     * @param iterable<Countable|array> $array
     * @param int|float                 $min
     * @param int|float                 $max
     * @param string                    $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allCountBetween($array, $min, $max, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::countBetween($entry, $min, $max, $message);
        }
    }

    /**
     * @param iterable<Countable|array|null> $array
     * @param int|float                      $min
     * @param int|float                      $max
     * @param string                         $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrCountBetween($array, $min, $max, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::countBetween($entry, $min, $max, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert list|null $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsList($array, $message = '')
    {
        null === $array || static::isList($array, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<list> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsList($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::isList($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<list|null> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsList($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::isList($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert non-empty-list|null $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsNonEmptyList($array, $message = '')
    {
        null === $array || static::isNonEmptyList($array, $message);
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<non-empty-list> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsNonEmptyList($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::isNonEmptyList($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-assert iterable<non-empty-list|null> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsNonEmptyList($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::isNonEmptyList($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param mixed|array<T>|null $array
     * @psalm-assert array<string, T>|null $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsMap($array, $message = '')
    {
        null === $array || static::isMap($array, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param iterable<mixed|array<T>> $array
     * @psalm-assert iterable<array<string, T>> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsMap($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::isMap($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param iterable<mixed|array<T>|null> $array
     * @psalm-assert iterable<array<string, T>|null> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsMap($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::isMap($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param mixed|array<T>|null $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrIsNonEmptyMap($array, $message = '')
    {
        null === $array || static::isNonEmptyMap($array, $message);
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param iterable<mixed|array<T>> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allIsNonEmptyMap($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            static::isNonEmptyMap($entry, $message);
        }
    }

    /**
     * @psalm-pure
     * @psalm-template T
     * @psalm-param iterable<mixed|array<T>|null> $array
     * @psalm-assert iterable<array<string, T>|null> $array
     * @psalm-assert iterable<!empty|null> $array
     *
     * @param mixed  $array
     * @param string $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrIsNonEmptyMap($array, $message = '')
    {
        static::isIterable($array);

        foreach ($array as $entry) {
            null === $entry || static::isNonEmptyMap($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param string|null $value
     * @param string      $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrUuid($value, $message = '')
    {
        null === $value || static::uuid($value, $message);
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string> $value
     * @param string           $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allUuid($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            static::uuid($entry, $message);
        }
    }

    /**
     * @psalm-pure
     *
     * @param iterable<string|null> $value
     * @param string                $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrUuid($value, $message = '')
    {
        static::isIterable($value);

        foreach ($value as $entry) {
            null === $entry || static::uuid($entry, $message);
        }
    }

    /**
     * @psalm-param class-string<Throwable> $class
     *
     * @param Closure|null $expression
     * @param string       $class
     * @param string       $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function nullOrThrows($expression, $class = 'Exception', $message = '')
    {
        null === $expression || static::throws($expression, $class, $message);
    }

    /**
     * @psalm-param class-string<Throwable> $class
     *
     * @param iterable<Closure> $expression
     * @param string            $class
     * @param string            $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allThrows($expression, $class = 'Exception', $message = '')
    {
        static::isIterable($expression);

        foreach ($expression as $entry) {
            static::throws($entry, $class, $message);
        }
    }

    /**
     * @psalm-param class-string<Throwable> $class
     *
     * @param iterable<Closure|null> $expression
     * @param string                 $class
     * @param string                 $message
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function allNullOrThrows($expression, $class = 'Exception', $message = '')
    {
        static::isIterable($expression);

        foreach ($expression as $entry) {
            null === $entry || static::throws($entry, $class, $message);
        }
    }
}
<?php

if ( ! function_exists('array_get')) {
    /**
     * Get an item from an array using "dot" notation.
     *
     * @param  array $array
     * @param  string $key
     * @param  mixed $default
     *
     * @return mixed
     */
    function array_get(array $array, $key, $default = null) {
        if ($key === null) {
            return null;
        }

        if (isset($array[$key])) {
            return $array[$key];
        }

        foreach (explode('.', $key) as $segment) {
            if ( ! is_array($array) || ! array_key_exists($segment, $array)) {
                return $default;
            }

            $array = $array[$segment];
        }

        return $array;
    }
}

if ( ! function_exists('array_has')) {
    /**
     * Check if an item exists in an array using "dot" notation.
     *
     * @param  array $array
     * @param  string $key
     *
     * @return bool
     */
    function array_has(array $array, $key) {
        if (empty($array) || $key === null) {
            return false;
        }

        if (array_key_exists($key, $array)) {
            return true;
        }

        foreach (explode('.', $key) as $segment) {
            if ( ! is_array($array) || ! array_key_exists($segment, $array)) {
                return false;
            }

            $array = $array[$segment];
        }

        return true;
    }
}

if ( ! function_exists('array_set')) {
    /**
     * Set an array item to a given value using "dot" notation.
     *
     * @param  array $array
     * @param  string $key
     * @param  mixed $value
     *
     * @return array
     */
    function array_set(array &$array, $key, $value) {
        if ($key === null) {
            return null;
        }

        $keys = explode('.', $key);

        while (count($keys) > 1) {
            $key = array_shift($keys);

            if ( ! isset($array[$key]) || ! is_array($array[$key])) {
                $array[$key] = [];
            }

            $array = &$array[$key];
        }

        $array[array_shift($keys)] = $value;

        return $array;
    }
}

if ( ! function_exists('array_remove')) {
    /**
     * Remove one or many array items from a given array using "dot" notation.
     *
     * @param  array $array
     * @param  array|string $keys
     *
     * @return void
     */
    function array_remove(array &$array, $keys) {
        $original = &$array;

        if ( ! is_array($keys)) {
            $keys = [$keys];
        }

        foreach ((array) $keys as $key) {
            $parts = explode('.', $key);

            while (count($parts) > 1) {
                $part = array_shift($parts);

                if (isset($array[$part]) && is_array($array[$part])) {
                    $array = &$array[$part];
                }
            }

            unset($array[array_shift($parts)]);

            $array = &$original;
        }
    }
}

if ( ! function_exists('array_add')) {
    /**
     * Add an element to the array at a specific location
     * using the "dot" notation.
     *
     * @param array $array
     * @param $key
     * @param $value
     *
     * @return array
     */
    function array_add(array &$array, $key, $value) {
        $target = array_get($array, $key, []);

        if ( ! is_array($target)) {
            $target = [$target];
        }

        $target[] = $value;
         array_set($array, $key, $target);

        return $array;
    }
}

if ( ! function_exists('array_take')) {
    /**
     * Get an item and remove it from the array.
     *
     * @param array $array
     * @param $key
     * @param null $default
     *
     * @return mixed
     */
    function array_take(array &$array, $key, $default = null) {
        $value = array_get($array, $key, $default);

        if (array_has($array, $key)) {
            array_remove($array, $key);
        }

        return $value;
    }
}

if ( ! function_exists('array_first')) {
    /**
     * @param array $array
     * @param null $default
     *
     * @return mixed
     */
    function array_first(array $array, $default = null) {
        if (empty($array)) {
            return $default;
        }

        return reset($array);
    }
}

if ( ! function_exists('array_last')) {
    /**
     * @param array $array
     * @param null $default
     *
     * @return mixed
     */
    function array_last(array $array, $default = null) {
        if (empty($array)) {
            return $default;
        }

        return array_first(array_reverse($array, true), $default);
    }
}

if ( ! function_exists('array_reset')) {
    /**
     * Reset all numerical indexes of an array (start from zero).
     * Non-numerical indexes will stay untouched. Returns a new array.
     *
     * @param array $array
     * @param bool|false $deep
     *
     * @return array
     */
    function array_reset(array $array, $deep = false) {
        $target = [];

        foreach ($array as $key => $value) {
            if ($deep && is_array($value)) {
                $value = array_reset($value);
            }

            if (is_numeric($key)) {
                $target[] = $value;
            } else {
                $target[$key] = $value;
            }
        }

        return $target;
    }
}

if ( ! function_exists('array_dot')) {
    /**
     * Flatten a multi-dimensional associative array with dots.
     *
     * @param  array $array
     * @param  string $prepend
     *
     * @return array
     */
    function array_dot(array $array, $prepend = '') {
        $results = [];

        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $results = array_merge($results, array_dot($value, $prepend . $key . '.'));
            } else {
                $results[$prepend . $key] = $value;
            }
        }

        return $results;
    }
}

if ( ! function_exists('array_extend')) {
    /**
     * Extend one array with another.
     *
     * @param array $arrays
     *
     * @return array
     */
    function array_extend(array $arrays) {
        $merged = [];

        foreach (func_get_args() as $array) {
            foreach ($array as $key => $value) {
                if (is_array($value) && array_has($merged, $key) && is_array($merged[$key])) {
                    $merged[$key] = array_extend($merged[$key], $value);
                } else {
                    $merged[$key] = $value;
                }
            }
        }

        return $merged;
    }
}

if ( ! function_exists('array_extend_distinct')) {
    /**
     * Extend one array with another. Non associative arrays will not be merged
     * but rather replaced.
     *
     * @param array $arrays
     *
     * @return array
     */
    function array_extend_distinct(array $arrays) {
        $merged = [];

        foreach (func_get_args() as $array) {
            foreach ($array as $key => $value) {
                if (is_array($value) &&
                    array_has($merged, $key) &&
                    is_array($merged[$key])
                ) {
                    if (array_is_associative($value) && array_is_associative($merged[$key])) {
                        $merged[$key] = array_extend_distinct($merged[$key], $value);

                        continue;
                    }
                }

                $merged[$key] = $value;
            }
        }

        return $merged;
    }
}

if ( ! function_exists('array_is_associative')) {
    /**
     * Check if the given array is associative.
     *
     * @param array $array
     *
     * @return bool
     */
    function array_is_associative(array $array) {
        if ($array == []) {
            return true;
        }

        $keys = array_keys($array);

        if (array_keys($keys) !== $keys) {
            foreach ($keys as $key) {
                if ( ! is_numeric($key)) {
                    return true;
                }
            }
        }

        return false;
    }
}

if ( ! function_exists('array_is_indexed')) {
    /**
     * Check if an array has a numeric index.
     *
     * @param array $array
     *
     * @return bool
     */
    function array_is_indexed(array $array) {
        if ($array == []) {
            return true;
        }

        return ! array_is_associative($array);
    }
}

if ( ! function_exists('array_contains')) {
    /**
     * Check if an array contains a specific value.
     *
     * @param array $array
     * @param $search
     * @param bool $strict
     *
     * @return bool
     */
    function array_contains(array $array, $search, $strict = true) {
        return in_array($search, $array, $strict);
    }
}
<?php

class ArrayTest extends PHPUnit_Framework_TestCase {
    public function array_has_provider() {
        return [
            [true, ['foo' => 'bar'], 'foo'],
            [false, ['foo' => 'bar'], 'bar'],
            [true, ['foo' => ['bar' => 'baz']], 'foo.bar'],
            [false, ['foo' => ['bar' => 'baz']], 'foo.baz'],
            [true, ['foo' => ['bar' => ['baz' => 'yolo']]], 'foo.bar.baz'],
            [false, ['foo' => ['bar' => ['baz' => 'yolo']]], 'foo.bar.yolo'],
        ];
    }

    public function array_get_provider() {
        return [
            [null, ['foo' => 'bar'], null, null],
            ['bar', ['foo' => 'bar'], 'foo', null],
            ['foo', ['foo' => 'bar'], 'bar', 'foo'],
            ['baz', ['foo' => ['bar' => 'baz']], 'foo.bar', null],
            ['bar', ['foo' => ['bar' => 'baz']], 'foo.baz', 'bar'],
            ['yolo', ['foo' => ['bar' => ['baz' => 'yolo']]], 'foo.bar.baz', null],
            ['baz', ['foo' => ['bar' => ['baz' => 'yolo']]], 'foo.bar.yolo', 'baz'],
        ];
    }

    public function array_set_provider() {
        return [
            [null, null, 'foo'],
            ['foo', 'foo', 'foo'],
            ['bar', 'foo.bar', 'bar'],
            ['baz', 'foo.bar.baz', 'baz'],
        ];
    }

    public function array_remove_provider() {
        return [
            ['foo'],
            ['foo.bar'],
            ['foo.bar.baz']
        ];
    }

    public function array_dot_provider() {
        return [
            [['foo' => 'bar'], ['foo' => 'bar']],
            [['foo.bar' => 'baz'], ['foo' => ['bar' => 'baz']]],
            [['foo.bar.baz' => 'yolo'], ['foo' => ['bar' => ['baz' => 'yolo']]]],
        ];
    }

    public function array_extend_provider() {
        return [
            [
                ['foo' => 'bar', 'bar' => 'bar', [1, 2, 3]],
                ['foo' => 'foo', [1, 2, 3]],
                ['foo' => 'bar', 'bar' => 'bar']
            ],
            [
                ['foo' => ['bar' => 'baz'], [1, 2, 3, 'foo' => 'bar', 'yolo' => 'swag']],
                ['foo' => ['bar' => ['baz' => 'yolo']], [1, 'yolo' => 'swag']],
                ['foo' => ['bar' => 'baz'], [1, 2, 3, 'foo' => 'bar']],
            ],
            [
                [0 => 'yolo', 1 => 'bar', 'bar' => ['bar' => ['baz' => 'swag']], 'baz' => ['foo' => 'bar'], 2 => [1, 3]],
                [0 => 'foo', 1 => 'bar', 'baz' => ['foo' => 'bar'], 2 => [2, 3]],
                [0 => 'yolo', 'bar' => ['bar' => ['baz' => 'swag']], 2 => [1]],
            ],
        ];
    }

    public function array_extend_distinct_provider() {
        return [
            [
                ['foo' => 'bar', 'bar' => 'bar', [1, 2, 3]],
                ['foo' => 'foo', [1, 2, 3]],
                ['foo' => 'bar', 'bar' => 'bar']
            ],
            [
                ['foo' => ['bar' => 'baz'], [1, 2, 3, 'foo' => 'bar', 'yolo' => 'swag']],
                ['foo' => ['bar' => ['baz' => 'yolo']], [1, 'yolo' => 'swag']],
                ['foo' => ['bar' => 'baz'], [1, 2, 3, 'foo' => 'bar']],
            ],
            [
                [0 => 'yolo', 1 => 'bar', 'bar' => ['bar' => ['baz' => 'swag']], 'baz' => ['foo' => 'bar'], 2 => [1]],
                [0 => 'foo', 1 => 'bar', 'baz' => ['foo' => 'bar'], 2 => [2, 3]],
                [0 => 'yolo', 'bar' => ['bar' => ['baz' => 'swag']], 2 => [1]],
            ],
            [
                ['foo' => ['bar' => [5]]],
                ['foo' => ['bar' => [1, 2, 3,]]],
                ['foo' => ['bar' => [5]]],
            ],
        ];
    }

    public function array_is_associative_provider() {
        return [
            [false, [0, '1', 2]],
            [false, [99 => 0, 5 => 1, 2 => 2]],
            [true, ['foo' => 'bar', 1, 2]],
            [true, ['foo' => 'bar', 'bar' => 'baz']],
            [true, []],
        ];
    }

    public function array_is_index_provider() {
        return [
            [false, [1, 2, 3, 'a' => 'foo']],
            [false, [0 => 3, 'a' => 'foo']],
            [true, [1, 2, 3]],
            [true, [0 => 1, '3' => 2]],
            [true, []],
        ];
    }

    public function array_reset_provider() {
        return [
            [
                [0 => 'foo', 'baz' => 'yolo', 1 => 'bar'],
                [10 => 'foo', 'baz' => 'yolo', '199' => 'bar'],
                false
            ],
            [
                [0 => [10 => 'foo', 'baz' => 'yolo', '199' => 'bar'], 'baz' => 'yolo', 1 => 'bar'],
                [10 => [10 => 'foo', 'baz' => 'yolo', '199' => 'bar'], 'baz' => 'yolo', '199' => 'bar'],
                false,
            ],
            [
                [0 => [0 => 'foo', 'baz' => 'yolo', 1 => 'bar'], 'baz' => 'yolo', 1 => 'bar'],
                [10 => [10 => 'foo', 'baz' => 'yolo', '199' => 'bar'], 'baz' => 'yolo', '199' => 'bar'],
                true,
            ],
        ];
    }

    public function array_add_provider() {
        return [
            [['list' => [1, 2, 3]], ['list' => [1, 2]], 'list', 3,],
            [['value' => [1, 2]], ['value' => 1], 'value', 2,],
            [['nested' => ['value' => [1, 2]]], ['nested' => ['value' => 1]], 'nested.value', 2,],
            [['nested' => ['value' => [1, 2]]], ['nested' => ['value' => [1]]], 'nested.value', 2,],
        ];
    }

    /**
     * @dataProvider array_has_provider
     */
    public function test_array_has($expected, $array, $path) {
        $this->assertEquals($expected, array_has($array, $path));
    }

    /**
     * @dataProvider array_get_provider
     */
    public function test_array_get($expected, $array, $path, $default) {
        $this->assertEquals($expected, array_get($array, $path, $default));
    }

    /**
     * @dataProvider array_set_provider
     */
    public function test_array_set($expected, $path, $value) {
        $array = [];
        $this->assertFalse(array_has($array, $path));
        array_set($array, $path, $value);
        $this->assertEquals($expected, array_get($array, $path));
    }

    /**
     * @dataProvider array_remove_provider
     */
    public function test_array_remove($path) {
        $array = [];
        array_set($array, $path, 'foo');
        $this->assertTrue(array_has($array, $path));
        array_remove($array, $path);
        $this->assertFalse(array_has($array, $path));
    }

    /**
     * @dataProvider array_dot_provider
     */
    public function test_array_dot($expected, $array) {
        $this->assertEquals($expected, array_dot($array));
    }

    /**
     * @dataProvider array_extend_provider
     */
    public function test_array_extend($expected, $array1, $array2) {
        $this->assertEquals($expected, array_extend($array1, $array2));
    }

    public function test_array_extend_many() {
        $expected = [
            'foo' => 'bar', 'bar' => 'foo', 'baz' => 'foo', 'yolo' => 'swag'
        ];

        $array1 = ['foo' => 'bar'];
        $array2 = ['bar' => 'foo'];
        $array3 = ['baz' => 'foo'];
        $array4 = ['yolo' => 'swag'];

        $this->assertEquals($expected, array_extend($array1, $array2, $array3, $array4));
    }

    /**
     * @dataProvider array_extend_distinct_provider
     */
    public function test_array_extend_distinct($expected, $array1, $array2) {
        $this->assertEquals($expected, array_extend_distinct($array1, $array2));
    }

    /**
     * @dataProvider array_is_associative_provider
     */
    public function test_array_is_associative($expected, $array) {
        $this->assertEquals($expected, array_is_associative($array));
    }

    /**
     * @dataProvider array_is_index_provider
     */
    public function test_array_is_indexed($expected, $array) {
        $this->assertEquals($expected, array_is_indexed($array));
    }

    /**
     * @dataProvider array_reset_provider
     */
    public function test_array_reset($expected, $array, $deep) {
        $this->assertEquals($expected, array_reset($array, $deep), $deep);
    }

    /**
     * @dataProvider array_add_provider
     */
    public function test_array_add($expected, $array, $key, $value) {
        $this->assertEquals($expected, array_add($array, $key, $value));
    }

    public function test_array_take() {
        $array = ['foo' => ['bar' => 'baz']];
        $this->assertEquals('baz', array_take($array, 'foo.bar'));
        $this->assertEquals(['foo' => []], $array);
    }

    public function test_array_first() {
        $array = ['foo', 'bar', 'baz'];
        $this->assertEquals('foo', array_first($array));
    }

    public function test_array_first_returns_default_value() {
        $this->assertEquals('foo', array_first([], 'foo'));
    }

    public function test_array_last() {
        $array = ['foo', 'bat', 'baz'];
        $this->assertEquals('baz', array_last($array));
    }

    public function test_array_last_returns_default_value() {
        $this->assertEquals('baz', array_last([], 'baz'));
    }

    public function test_array_contains() {
        $this->assertTrue(array_contains(['foo', 'bar'], 'bar'));
        $this->assertFalse(array_contains(['foo', 'bar'], true));
        $this->assertFalse(array_contains([true, 'bar'], 'foo'));
        $this->assertTrue(array_contains([true, 'bar'], true));
        $this->assertFalse(array_contains([true, 'bar'], 'true'));
    }
}
<?php

require __DIR__.'/../vendor/autoload.php';
gj4_μRNK)t%j\nNBhjOBHF/   GBMB